diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 58fdfcb..b2ca244 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -63,7 +63,6 @@ jobs: run: | uv run pytest -rxXs --basetemp=tmp - name: Store reports - if: failure() uses: actions/upload-artifact@v6 with: name: reports-${{ matrix.os }} diff --git a/src/pyxems/csx.py b/src/pyxems/csx.py index 5fecfb6..1e89228 100644 --- a/src/pyxems/csx.py +++ b/src/pyxems/csx.py @@ -92,6 +92,23 @@ 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 DumpBoxProperty: + number: int = 0 + type: int = 0 + weight: int = 1 + normdir: int = -1 + starttime: float = 0 + stoptime: float = 0 + dumptype: int = 0 + dumpmode: int = 1 + filetype: int = 1 + multigridlevel: int = 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}" DumpType="{self.dumptype}" DumpMode="{self.dumpmode}" FileType="{self.filetype}" MultiGridLevel="{self.multigridlevel}"' + + @dataclass(frozen=True) class Color: r: int @@ -137,7 +154,11 @@ class Property: 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 | ExcitationProperty | ProbeBoxProperty + MaterialProperty + | LumpedProperty + | ExcitationProperty + | ProbeBoxProperty + | DumpBoxProperty ) = field( default_factory=lambda: MaterialProperty( "Property", Physical(1.0), Physical(1.0) @@ -157,15 +178,9 @@ class Property: def to_xml(self) -> str: match self.kind: - case "Metal": - iso = "" case "Material": iso = ' Isotropy="1"' - case "LumpedElement": - iso = self.material.to_xml() - case "Excitation": - iso = self.material.to_xml() - case "ProbeBox": + case "LumpedElement" | "ProbeBox" | "Excitation" | "DumpBox": iso = self.material.to_xml() case _: iso = "" @@ -241,6 +256,12 @@ def add_property( starttime=prop_conf["starttime"] if "starttime" in prop_conf else 0, stoptime=prop_conf["stoptime"] if "stoptime" in prop_conf else 0, ) + case "DumpBox": + property = DumpBoxProperty( + dumptype=int( + prop_conf["dumptype"] if "dumptype" in prop_conf else 0 + ), + ) case _: raise ValueError(f"Unknown property kind: {kind}") prop = Property( diff --git a/src/pyxems/run.py b/src/pyxems/run.py index ec63a17..9f798d7 100644 --- a/src/pyxems/run.py +++ b/src/pyxems/run.py @@ -3,6 +3,7 @@ from shutil import which import os from typing import Optional +import logging try: import cyclopts @@ -19,13 +20,23 @@ def find_openems_executable() -> Optional[Path]: if which("openEMS") is not None: + logging.info(f"Found OpenEMS executable in PATH: {which('openEMS')}") return Path(which("openEMS")) # type: ignore load_dotenv() - if "OPENEMS_PATH" in os.environ: - openems_path = Path(os.environ["OPENEMS_PATH"]) / "openEMS" - if openems_path.is_file(): - return openems_path - return None + if "OPENEMS_PATH" not in os.environ: + logging.info( + "OPENEMS_PATH environment variable not set. Please set it to the directory containing the OpenEMS executable." + ) + return None + openems_path = Path(os.environ["OPENEMS_PATH"]) / ( + "openEMS" if os.name != "nt" else "openEMS.exe" + ) + if not openems_path.is_file(): + logging.info( + f"OpenEMS executable not found at {openems_path}. Please ensure OPENEMS_PATH is set correctly." + ) + return None + return openems_path def check_config() -> bool: diff --git a/tests/test_main.py b/tests/test_main.py index 7979069..d997ab4 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -225,5 +225,63 @@ def test_generate_simp_patch(tmp_path: Path): priority=0, property_id=6, ) + oems_config.csx.add_property("DumpBox", "nf2ff_E", Color(12, 62, 153)) + start = (-90.50519, -90.66667, -40.34557) + stop = (-90.50519, 90.66667, 90.32554) + oems_config.csx.add_box(start, stop, priority=0, property_id=7) + oems_config.csx.add_box( + (-start[0], *start[1:]), (-stop[0], *stop[1:]), priority=0, property_id=7 + ) + oems_config.csx.add_box( + start, (-stop[0], -stop[1], stop[2]), priority=0, property_id=7 + ) + oems_config.csx.add_box( + (start[0], -start[1], start[2]), + (-stop[0], stop[1], stop[2]), + priority=0, + property_id=7, + ) + oems_config.csx.add_box( + (start[0], start[1], start[2]), + (-stop[0], stop[1], start[2]), + priority=0, + property_id=7, + ) + oems_config.csx.add_box( + (start[0], start[1], stop[2]), + (-stop[0], stop[1], stop[2]), + priority=0, + property_id=7, + ) + oems_config.csx.add_property( + "DumpBox", "nf2ff_H", Color(36, 94, 13), prop_conf={"dumptype": 1} + ) + start = (-90.50519, -90.66667, -40.34557) + stop = (-90.50519, 90.66667, 90.32554) + oems_config.csx.add_box(start, stop, priority=0, property_id=8) + oems_config.csx.add_box( + (-start[0], *start[1:]), (-stop[0], *stop[1:]), priority=0, property_id=8 + ) + oems_config.csx.add_box( + start, (-stop[0], -stop[1], stop[2]), priority=0, property_id=8 + ) + oems_config.csx.add_box( + (start[0], -start[1], start[2]), + (-stop[0], stop[1], stop[2]), + priority=0, + property_id=8, + ) + oems_config.csx.add_box( + (start[0], start[1], start[2]), + (-stop[0], stop[1], start[2]), + priority=0, + property_id=8, + ) + oems_config.csx.add_box( + (start[0], start[1], stop[2]), + (-stop[0], stop[1], stop[2]), + priority=0, + property_id=8, + ) write_openEMS_xml(tmp_path / "openEMS_config.xml", oems_config) assert (tmp_path / "openEMS_config.xml").read_text() == ref.read_text() diff --git a/tests/test_run.py b/tests/test_run.py index 1d901ce..2687376 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -1,9 +1,11 @@ from pathlib import Path -from pyxems.run import simulate, check_config +from pyxems.run import simulate, check_config, find_openems_executable import pytest -@pytest.mark.skipif(not check_config(), reason="OpenEMS exe not found.") +@pytest.mark.skipif( + not check_config(), reason=f"OpenEMS exe not found. {find_openems_executable()}" +) def test_simulate(tmp_path: Path): config_path = Path(__file__).parent / "data" / "simp_patch.xml" result = simulate(config_path, tmp_path)