diff --git a/src/pyxems/csx.py b/src/pyxems/csx.py index 8402f7c..5fecfb6 100644 --- a/src/pyxems/csx.py +++ b/src/pyxems/csx.py @@ -49,7 +49,7 @@ def to_xml(self, short=True) -> str: return f'<{self.name} Epsilon="{self.epsilon_r.__str__(short=False)}" Mue="{self.mu_r.__str__(short=False)}" Kappa="{self.kappa.__str__(short=False)}" Sigma="{self.sigma.__str__(short=False)}" Density="{self.density:e}" />' -@dataclass +@dataclass(frozen=True) class LumpedProperty: direction: Optional[Axes] = "Z" caps: int = 1 @@ -65,6 +65,33 @@ def to_xml(self, short=True) -> str: return f' Direction="{axe_number[self.direction]}" Caps="{self.caps}" R="{self.resistance:e}" C="{cap}" L="{ind}" LEtype="{self.letype:e}"' +@dataclass(frozen=True) +class ExcitationProperty: + number: int = 0 + enable: int = 1 + frequency: float = 0.0 + delay: float = 0 + type = 0 + excite: tuple[float, float, float] = (0.0, 0.0, -1.0) + propdir: tuple[float, float, float] = (0.0, 0.0, 0.0) + + def to_xml(self, short=True) -> str: + return f' Number="{self.number}" Enabled="{self.enable}" Frequency="{self.frequency:e}" Delay="{self.delay:e}" Type="{self.type}" Excite="{",".join([f"{v:e}" for v in self.excite])}" PropDir="{",".join([f"{v:e}" for v in self.propdir])}"' + + +@dataclass(frozen=True) +class ProbeBoxProperty: + number: int = 0 + type: int = 0 + weight: int = -1 + normdir: int = -1 + starttime: float = 0 + stoptime: float = 0 + + def to_xml(self, short=True) -> str: + return f' Number="{self.number}" Type="{self.type}" Weight="{self.weight}" NormDir="{self.normdir}" StartTime="{self.starttime:g}" StopTime="{self.stoptime:g}"' + + @dataclass(frozen=True) class Color: r: int @@ -109,7 +136,9 @@ class Property: kind: PropertyKind = "Material" fillcolor: Color = field(default_factory=lambda: Color(255, 255, 255, 255)) edgecolor: Color = field(default_factory=lambda: Color(0, 0, 0, 255)) - material: MaterialProperty | LumpedProperty = field( + material: ( + MaterialProperty | LumpedProperty | ExcitationProperty | ProbeBoxProperty + ) = field( default_factory=lambda: MaterialProperty( "Property", Physical(1.0), Physical(1.0) ) @@ -134,6 +163,12 @@ def to_xml(self) -> str: iso = ' Isotropy="1"' case "LumpedElement": iso = self.material.to_xml() + case "Excitation": + iso = self.material.to_xml() + case "ProbeBox": + iso = self.material.to_xml() + case _: + iso = "" xml = f'<{self.kind} ID="{self.id}" Name="{self.name}"{iso}>\n' xml += f" \n" xml += f" \n" @@ -145,6 +180,8 @@ def to_xml(self) -> str: if self.kind == "Material": xml += f" {self.material.to_xml(False)}\n" xml += f" {self.weight.to_xml(False)}\n" + if self.kind == "Excitation": + xml += ' \n' xml += f"\n" return xml @@ -173,22 +210,39 @@ def add_property( name: str, fillcolor: Color = Color(255, 255, 255, 255), edgecolor: Optional[Color] = None, - eps: float = 1.0, - mu: float = 1.0, - kappa: float = 0.0, - sigma: float = 0.0, + prop_conf: Optional[dict[str, float | int]] = None, ): id = len(self.properties) - if kind in ("Material", "Metal"): - property = MaterialProperty( - "Property", - Physical(eps), - Physical(mu), - Physical((kappa, 0, 0)), - Physical((sigma, 0, 0)), - ) - else: - property = LumpedProperty() + if prop_conf is None: + prop_conf = {} + match kind: + case "Material" | "Metal": + property = MaterialProperty( + "Property", + Physical(prop_conf["eps"] if "eps" in prop_conf else 1.0), + Physical(prop_conf["mu"] if "mu" in prop_conf else 1.0), + Physical( + (prop_conf["kappa"] if "kappa" in prop_conf else 0.0, 0, 0) + ), + Physical( + (prop_conf["sigma"] if "sigma" in prop_conf else 0.0, 0, 0) + ), + ) + case "LumpedElement": + property = LumpedProperty() + case "Excitation": + property = ExcitationProperty() + case "ProbeBox": + property = ProbeBoxProperty( + number=int(prop_conf["number"] if "number" in prop_conf else 0), + type=int(prop_conf["type"] if "type" in prop_conf else 0), + weight=int(prop_conf["weight"] if "weight" in prop_conf else -1), + normdir=int(prop_conf["normdir"] if "normdir" in prop_conf else -1), + starttime=prop_conf["starttime"] if "starttime" in prop_conf else 0, + stoptime=prop_conf["stoptime"] if "stoptime" in prop_conf else 0, + ) + case _: + raise ValueError(f"Unknown property kind: {kind}") prop = Property( name, id, diff --git a/src/pyxems/main.py b/src/pyxems/main.py index 2795d5c..2cb94d1 100644 --- a/src/pyxems/main.py +++ b/src/pyxems/main.py @@ -14,7 +14,7 @@ def to_xml(self) -> str: xml = "\n" xml += self.fdtd.to_xml() xml += self.csx.to_xml() - xml += "" + xml += "\n" return xml diff --git a/tests/data/simp_patch.xml b/tests/data/simp_patch.xml index 6183146..15aa607 100644 --- a/tests/data/simp_patch.xml +++ b/tests/data/simp_patch.xml @@ -76,7 +76,7 @@ - + diff --git a/tests/test_main.py b/tests/test_main.py index 692a4fe..7979069 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -172,8 +172,7 @@ def test_generate_simp_patch(tmp_path: Path): "substrate", Color(132, 225, 108, 123), Color(132, 225, 108, 123), - eps=3.38, - kappa=4.606928e-4, + {"eps": 3.38, "kappa": 4.606928e-4}, ) oems_config.csx.add_box( start=(-30, -30, 0), @@ -200,5 +199,31 @@ def test_generate_simp_patch(tmp_path: Path): priority=5, property_id=3, ) + oems_config.csx.add_property("Excitation", "port_excite_1", Color(241, 187, 233)) + oems_config.csx.add_box( + start=(-6, 0, 0), + stop=(-6, 0, 1.524), + priority=5, + property_id=4, + ) + oems_config.csx.add_property("ProbeBox", "port_ut_1", Color(235, 179, 166)) + oems_config.csx.add_box( + start=(-6, 0, 0), + stop=(-6, 0, 1.524), + priority=0, + property_id=5, + ) + oems_config.csx.add_property( + "ProbeBox", + "port_it_1", + Color(219, 60, 135), + prop_conf={"type": 1, "normdir": 2, "weight": 1}, + ) + oems_config.csx.add_box( + start=(-6, 0, 0.762), + stop=(-6, 0, 0.762), + priority=0, + property_id=6, + ) write_openEMS_xml(tmp_path / "openEMS_config.xml", oems_config) assert (tmp_path / "openEMS_config.xml").read_text() == ref.read_text()