Source code for zeroheliumkit.fem.palacer

import os
import json
from dataclasses import dataclass, asdict, field
import subprocess
import platform


[docs] @dataclass class ProblemConfig: Type: str = "Driven" Verbose: int = 2 Output: str="postpro/" def __post_init__(self): if self.Type not in ["Eigenmode", "Driven", "Transient", "Electrostatic", "Magnetostatic"]: raise ValueError("Problem Type must be 'Eigenmode', 'Driven', 'Transient', 'Electrostatic', or 'Magnetostatic'.")
[docs] @dataclass class ModelConfig: Refinement: dict Mesh: str = "mesh/meshfile.msh" L0: float = 1.0e-6
[docs] @dataclass class MaterialsConfig: Attributes: list[int] Permeability: float = 1.0 Permittivity: float = 1.0 LossTan: float | list[float] = 0.0
# Conductivity: float = 0.0 # LondonDepth: float = 0.0
[docs] @dataclass class PostProEnergyConfig: Index: int=1 Attributes: list[int]=field(default_factory=lambda: [1])
[docs] @dataclass class PostProProbeConfigurator: xlist: list[float] ylist: list[float] zlist: list[float] config: list[dict]=field(default_factory=list) schema: tuple=field(default_factory=tuple) def __post_init__(self): index = 0 self.schema = (len(self.zlist), len(self.ylist), len(self.xlist)) for z in self.zlist: for y in self.ylist: for x in self.xlist: index += 1 self.config.append({ "Index": index, "Center": [x, y, z] })
[docs] @dataclass class PostProProbeConfig: Index: int=1 Center: list[float]=field(default_factory=lambda: [0,0,0])
[docs] @dataclass class DomainConfig: Materials: list Postprocessing: dict
[docs] @dataclass class ElementConfig: Attributes: list[int] Direction: str
[docs] @dataclass class LumpedPortConfig: Index: int = 1 R: float = 50.0 Excitation: bool = True Elements: list[ElementConfig] = field(default_factory=list)
[docs] @dataclass class ImpedanceConfig: Attributes: list[int] Rs: float = 0.0 Ls: float = 0.0 Cs: float = 0.0
[docs] @dataclass class AbsorbingConfig: Attributes: list[int] Order: int = 1
[docs] @dataclass class SurfaceCurrentElementConfig: Attributes: list[int] Direction: list[float] CoordinateSystem: str="Cartesian"
[docs] @dataclass class SurfaceCurrentConfig: Index: int Elements: list[SurfaceCurrentElementConfig]
[docs] @dataclass class BoundaryConfig: PEC: dict=None Absorbing: AbsorbingConfig=None LumpedPort: list[LumpedPortConfig]=None Impedance: list[ImpedanceConfig]=None SurfaceCurrent: list[SurfaceCurrentConfig]=None def __post_init__(self): self.__dataclass_fields__ = { k: v for k, v in self.__dataclass_fields__.items() if getattr(self, k) is not None }
[docs] @dataclass class DrivenConfig: MinFreq: float=1 # GHz MaxFreq: float=10 # GHz FreqStep: float=0.1 # GHz Save: list=field(default_factory=lambda: [1,10]) AdaptiveTol: float=1.0e-3
[docs] @dataclass class EigenConfig: N: int=6 Tol: float=1.0e-8 Target: float=5.0 # GHz Save: int=6
[docs] @dataclass class SolverConfig: Order: int = 1 Device: str = "CPU" Driven: DrivenConfig = None Eigenmode: EigenConfig = None Magnetostatic: dict = None Linear: dict = None def __post_init__(self): if self.Magnetostatic is not None: self.Linear = { "Type": "AMS", "KSPType": "CG", "Tol": 1.0e-6, "MaxIts": 100 } self.__dataclass_fields__ = { k: v for k, v in self.__dataclass_fields__.items() if getattr(self, k) is not None }
[docs] @dataclass class PalaceConfig: Problem: ProblemConfig Model: ModelConfig Domains: DomainConfig Boundaries: BoundaryConfig Solver: SolverConfig
[docs] class PalaceRunner: """ A class to run Palace simulations. """ def __init__(self, json_name: str, config: PalaceConfig, exec_path: str): self.config = config self.exec_path = exec_path self.json_path = self.config.Problem.Output + json_name + '.json' self.save_json(self.json_path)
[docs] def save_json(self, path: str = 'palace.json'): """ Save the Palace configuration to a JSON file. """ with open(path, 'w') as f: json.dump(asdict(self.config), f, indent=2)
def run(self, multicore: int = None): command_to_cd = f'cd {os.getcwd()}' if multicore: command_to_run = self.exec_path + ' -np ' + str(multicore) + ' ' + self.json_path else: command_to_run = self.exec_path + ' ' + self.json_path command = command_to_cd + ' && ' + command_to_run try: system = platform.system() if system == "Darwin": # macOS # Use osascript to tell the Terminal application to open a new window and execute the command subprocess.run([ 'osascript', '-e', f'tell application "Terminal" to do script "{command}"' ]) elif system == "Linux": # Linux subprocess.run([ 'gnome-terminal', '--', 'bash', '-c', f"{command}; exec bash" ]) elif system == "Windows": # Windows print(" Windows system is not yet supported for automatic terminal launching.") # need to test this part on Windows # subprocess.run([ # 'cmd.exe', # '/c', # f'start cmd.exe /k "{command}"' # ]) except KeyboardInterrupt: message = 'Interrupted by user' print(message)