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"{self.kind}>\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()