From 1171a2a06d403012479446dc8a47947d25f1480b Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 12 May 2023 17:14:46 +0200 Subject: [PATCH 01/23] removing dummy parser --- converter/api.py | 6 +- converter/common.py | 27 ++++-- converter/shieldhit/geo.py | 8 +- converter/shieldhit/parser.py | 64 +++----------- converter/topas/parser.py | 7 +- setup.cfg | 5 +- tests/test_shieldhit_converter.py | 7 ++ tests/test_shieldhit_dummy_converter.py | 107 ------------------------ tests/test_shieldit_beam.py | 7 +- tests/test_topas_converter.py | 7 ++ 10 files changed, 62 insertions(+), 183 deletions(-) delete mode 100644 tests/test_shieldhit_dummy_converter.py diff --git a/converter/api.py b/converter/api.py index c3d873b4..e3ea52f4 100644 --- a/converter/api.py +++ b/converter/api.py @@ -1,6 +1,6 @@ from pathlib import Path from typing import Union -from converter.shieldhit.parser import DummmyParser as SHDummyParser, ShieldhitParser +from converter.shieldhit.parser import ShieldhitParser from converter.topas.parser import TopasParser from converter.common import Parser from converter.fluka.parser import FlukaParser @@ -9,8 +9,6 @@ def get_parser_from_str(parser_type: str) -> Parser: """Get a converter object based on the provided type.""" # This is temporary, suggestions on how to do this better appreciated. - if parser_type.lower() == 'sh_dummy': - return SHDummyParser() if parser_type.lower() == 'shieldhit': return ShieldhitParser() if parser_type.lower() == 'topas': @@ -19,7 +17,7 @@ def get_parser_from_str(parser_type: str) -> Parser: return FlukaParser() print(f"Invalid parser type \"{parser_type}\".") - raise ValueError("Parser type must be either 'sh_dummy', 'shieldhit', 'topas' or 'fluka'.") + raise ValueError("Parser type must be either 'shieldhit', 'topas' or 'fluka'.") def run_parser(parser: Parser, input_data: dict, output_dir: Union[Path, None] = None, silent: bool = True) -> dict: diff --git a/converter/common.py b/converter/common.py index 8728ddd6..1b97c671 100644 --- a/converter/common.py +++ b/converter/common.py @@ -1,24 +1,37 @@ -from abc import ABC, abstractmethod +from abc import abstractmethod from pathlib import Path -class Parser(ABC): +class Parser: """Abstract parser, the template for implementing other parsers.""" - @abstractmethod + def __init__(self) -> None: + self.info = { + "version": "", + "label": "", + "simulator": "", + } + def parse_configs(self, json: dict) -> None: """Convert the json dict to the 4 config dataclasses.""" + raise NotImplementedError - @abstractmethod - def save_configs(self, target_dir: Path) -> None: + def save_configs(self, target_dir: str): """ Save the configs as text files in the target_dir. The files are: beam.dat, mat.dat, detect.dat and geo.dat. """ + if not Path(target_dir).exists(): + raise ValueError("Target directory does not exist.") + + for file_name, content in self.get_configs_json().items(): + with open(Path(target_dir, file_name), 'w') as conf_f: + conf_f.write(content) - @abstractmethod - def get_configs_json(self) -> dict: + @staticmethod + def get_configs_json() -> dict: """ Return a dict representation of the config files. Each element has the config files name as key and its content as value. """ + return {} diff --git a/converter/shieldhit/geo.py b/converter/shieldhit/geo.py index a7b4dd40..2e8559b8 100644 --- a/converter/shieldhit/geo.py +++ b/converter/shieldhit/geo.py @@ -17,7 +17,7 @@ class DefaultMaterial(IntEnum): @staticmethod def is_default_material(material_value: int) -> bool: - """Check if the material is one of the predefined materials.""" + """Check if the material is one of the predefined default materials.""" return material_value in DefaultMaterial._value2member_map_ @@ -29,7 +29,7 @@ def format_float(number: float, n: int) -> float: """ result = number # If number is zero we just want to get 0.0 (it would mess up the log10 operation below) - if isclose(result, 0.): + if isclose(result, 0., rel_tol=1e-9): return 0. length = n @@ -68,14 +68,14 @@ def format_float(number: float, n: int) -> float: # Formatting negative numbers smaller than the desired precission could result in -0.0 or 0.0 randomly. # To avoid this we catch -0.0 and return 0.0. - if isclose(result, 0.): + if isclose(result, 0., rel_tol=1e-9): return 0. return result def parse_figure(figure: SolidFigure, number: int) -> str: - """Parse a SolidFigure into a str representation of SH12A input file.""" + """Parse a SolidFigure into a string representation of SH12A input file.""" if type(figure) is BoxFigure: return _parse_box(figure, number) if type(figure) is CylinderFigure: diff --git a/converter/shieldhit/parser.py b/converter/shieldhit/parser.py index 8e71302b..b8defbc4 100644 --- a/converter/shieldhit/parser.py +++ b/converter/shieldhit/parser.py @@ -15,62 +15,15 @@ ScoringZone) -class DummmyParser(Parser): - """A simple placeholder parser that ignores the json input and prints example (default) configs.""" +class ShieldhitParser(Parser): + """A SHIELD-HIT12A parser""" def __init__(self) -> None: + super().__init__() + self.info['simulator'] = 'shieldhit' self.beam_config = BeamConfig() self.detect_config = DetectConfig() self.geo_mat_config = GeoMatConfig() - self.info = { - "version": "not implemented", - "label": "placeholder", - "simulator": "shieldhit", - } - - def parse_configs(self, json: dict): - """Basicaly do nothing since we work on defaults in this parser.""" - - def save_configs(self, target_dir: str): - """ - Save the configs as text files in the target_dir. - The files are: beam.dat, mat.dat, detect.dat and geo.dat. - """ - if not Path(target_dir).exists(): - raise ValueError("Target directory does not exist.") - - for file_name, content in self.get_configs_json().items(): - with open(Path(target_dir, file_name), 'w') as conf_f: - conf_f.write(content) - - def get_configs_json(self) -> dict: - """ - Return a dict representation of the config files. Each element has - the config files name as key and its content as value. - """ - configs_json = { - "info.json": str(self.info), - "beam.dat": str(self.beam_config), - "mat.dat": self.geo_mat_config.get_mat_string(), - "detect.dat": str(self.detect_config), - "geo.dat": self.geo_mat_config.get_geo_string() - } - - return configs_json - - -class ShieldhitParser(DummmyParser): - """A regular SHIELD-HIT12A parser""" - - def __init__(self) -> None: - super().__init__() - # Add version variable to deploy script - version = "unknown" - self.info = { - "version": version, - "label": "development", - "simulator": "shieldhit", - } def parse_configs(self, json: dict) -> None: """Wrapper for all parse functions""" @@ -456,7 +409,14 @@ def _get_figure_index_by_uuid(self, figure_uuid: str) -> int: def get_configs_json(self) -> dict: """Get JSON data for configs""" - configs_json = super().get_configs_json() + configs_json = { + "info.json": str(self.info), + "beam.dat": str(self.beam_config), + "mat.dat": self.geo_mat_config.get_mat_string(), + "detect.dat": str(self.detect_config), + "geo.dat": self.geo_mat_config.get_geo_string() + } + if self.beam_config.beam_source_type == BeamSourceType.FILE: configs_json["sobp.dat"] = self.beam_config.beam_source_file['value'] diff --git a/converter/topas/parser.py b/converter/topas/parser.py index 3661e4b2..88a70ebe 100644 --- a/converter/topas/parser.py +++ b/converter/topas/parser.py @@ -7,12 +7,9 @@ class TopasParser(Parser): """A simple placeholder parser that parses energy and number of particles.""" def __init__(self) -> None: + super().__init__() + self.info['simulator'] = 'topas' self.config = Config() - self.info = { - "version": "unknown", - "label": "development", - "simulator": "topas", - } def parse_configs(self, json: dict) -> None: """Basicaly do nothing since we work on defaults in this parser.""" diff --git a/setup.cfg b/setup.cfg index 5ea8afa1..488e4a17 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,4 +30,7 @@ max-line-length=120 [yapf] based_on_style = pep8 -column_limit = 120 \ No newline at end of file +column_limit = 120 + +[tool:pytest] +testpaths = tests \ No newline at end of file diff --git a/tests/test_shieldhit_converter.py b/tests/test_shieldhit_converter.py index 00361480..c3c516f2 100644 --- a/tests/test_shieldhit_converter.py +++ b/tests/test_shieldhit_converter.py @@ -22,6 +22,13 @@ def default_json() -> dict: with open(example_json, 'r') as json_f: return json.load(json_f) +def test_if_parser_created(parser: Parser) -> None: + """Check if parser is created""" + assert parser + assert parser.info['version'] == '' + assert parser.info['label'] == '' + assert parser.info['simulator'] == 'shieldhit' + @pytest.mark.parametrize('filename', ['beam.dat', 'mat.dat', 'detect.dat']) def test_if_expected_files_created(parser: Parser, default_json : dict, tmp_path : Path, filename: str) -> None: """Check if all output files are created""" diff --git a/tests/test_shieldhit_dummy_converter.py b/tests/test_shieldhit_dummy_converter.py deleted file mode 100644 index 67faba0f..00000000 --- a/tests/test_shieldhit_dummy_converter.py +++ /dev/null @@ -1,107 +0,0 @@ -import pytest -from os import path -from converter.shieldhit.parser import Parser -from converter.api import get_parser_from_str, run_parser - -_Beam_template = """ -RNDSEED 89736501 ! Random seed -JPART0 2 ! Incident particle type -TMAX0 {energy} {energy_spread} ! Incident energy and energy spread; both in (MeV/nucl) -! no energy cutoffs -NSTAT {nstat:d} 0 ! NSTAT, Step of saving -STRAGG 2 ! Straggling: 0-Off 1-Gauss, 2-Vavilov -MSCAT 2 ! Mult. scatt 0-Off 1-Gauss, 2-Moliere -NUCRE 1 ! Nucl.Reac. switcher: 1-ON, 0-OFF -BEAMPOS 0 0 0 ! Position of the beam -BEAMDIR 0.0 0.0 ! Direction of the beam -BEAMSIGMA -0.1 0.1 ! Beam extension -! no BEAMSAD value -DELTAE 0.03 ! relative mean energy loss per transportation step -""" - -_Beam_str = _Beam_template.format(energy=150., energy_spread=1.5, nstat=10000) - -_Mat_str = """MEDIUM 1 -ICRU 276 -END -""" - -_Detect_str = """Geometry Cyl - Name CylZ_Mesh - R 0 10 1 - Z 0 20 400 - -Geometry Mesh - Name YZ_Mesh - X -0.5 0.5 1 - Y -2 2 80 - Z 0 20 400 - - -Output - Filename cylz.bdo - Geo CylZ_Mesh - Quantity DoseGy - -Output - Filename yzmsh.bdo - Geo YZ_Mesh - Quantity DoseGy -""" - -_Geo_str = """ - 0 0 Unnamed geometry - RCC 1 0.0 10.0 10.0 0.0 -20.0 0.0 - 10.0 - RCC 2 0.0 12.5 7.5 0.0 -25.0 0.0 - 15.0 - RCC 3 0.0 15.0 5.0 0.0 -30.0 0.0 - 20.0 - END - 001 +1 - 002 +2 -1 - 003 +3 -2 - END - 1 2 3 - 1 1000 0 -""" - -_Test_dir = './test_runs' - - -@pytest.fixture -def parser() -> Parser: - """Just a praser fixture.""" - return get_parser_from_str('sh_dummy') - - -@pytest.fixture -def output_dir(tmp_path_factory, parser) -> str: - """Fixture that creates a temporary dir for testing converter output and runs the conversion there.""" - output_dir = tmp_path_factory.mktemp(_Test_dir) - run_parser(parser, {}, output_dir) - return output_dir - - -def test_if_beam_created(output_dir) -> None: - """Check if beam.dat file created""" - with open(path.join(output_dir, 'beam.dat')) as f: - assert f.read() == _Beam_str - - -def test_if_mat_created(output_dir) -> None: - """Check if mat.dat file created""" - with open(path.join(output_dir, 'mat.dat')) as f: - assert f.read() == _Mat_str - - -def test_if_detect_created(output_dir) -> None: - """Check if detect.dat file created""" - with open(path.join(output_dir, 'detect.dat')) as f: - assert f.read() == _Detect_str - - -def test_if_geo_created(output_dir) -> None: - """Check if geo.dat file created""" - with open(path.join(output_dir, 'geo.dat')) as f: - assert f.read() == _Geo_str diff --git a/tests/test_shieldit_beam.py b/tests/test_shieldit_beam.py index bfd30c27..dc818bbf 100644 --- a/tests/test_shieldit_beam.py +++ b/tests/test_shieldit_beam.py @@ -11,9 +11,10 @@ def project_json() -> dict: """Fixture that provides a JSON with beam.dat dedicatet config.""" this_script_path = Path(__file__).parent.absolute() + result = {} with open(this_script_path / "resources" / "physics_settings.json", "r") as f: - return json.load(f) - return {} + result = json.load(f) + return result @pytest.fixture def output_dir(tmp_path_factory) -> Path: @@ -43,7 +44,7 @@ def test_project_json(project_json) -> None: def test_parser(sh12a_parser) -> None: """Check if parser is created correctly""" - assert sh12a_parser.info['version'] == 'unknown' + assert sh12a_parser.info['version'] == '' assert sh12a_parser.info['simulator'] == 'shieldhit' def test_generated_beam_dat(project_json, sh12a_parser, output_dir) -> None: diff --git a/tests/test_topas_converter.py b/tests/test_topas_converter.py index 753ed4fc..587d6edc 100644 --- a/tests/test_topas_converter.py +++ b/tests/test_topas_converter.py @@ -87,6 +87,13 @@ def output_dir(tmp_path_factory, parser, default_json) -> str: run_parser(parser, default_json, output_dir) return output_dir +def test_if_parser_created(parser) -> None: + """Check if parser created.""" + assert parser is not None + assert parser.info['simulator'] == 'topas' + assert parser.info['version'] == '' + assert parser.info['label'] == '' + def test_if_config_created(output_dir) -> None: """Check if topas_config.txt file created""" From 0d5a803119a49b614e65008f903564c0767628bc Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 12 May 2023 17:22:53 +0200 Subject: [PATCH 02/23] fix typing --- converter/shieldhit/detect.py | 19 ++++++++++--------- converter/shieldhit/parser.py | 3 ++- converter/shieldhit/scoring_geometries.py | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/converter/shieldhit/detect.py b/converter/shieldhit/detect.py index 7509c907..7061dc9d 100644 --- a/converter/shieldhit/detect.py +++ b/converter/shieldhit/detect.py @@ -1,4 +1,5 @@ from dataclasses import dataclass, field +from typing import Optional from converter.shieldhit.scoring_geometries import ScoringGeometry, ScoringCylinder, ScoringMesh @@ -28,9 +29,9 @@ class OutputQuantity: detector_type: str filter_name: str = "" - diff1: tuple[float, float, float, str] = None + diff1: Optional[tuple[float, float, float, str]] = None diff1_t: str = None - diff2: tuple[float, float, float, str] = None + diff2: Optional[tuple[float, float, float, str]] = None diff2_t: str = None quantity_template: str = """ @@ -52,14 +53,14 @@ def __str__(self) -> str: class ScoringOutput: """Dataclass storing information about shieldhit scoring outputs.""" - filename: str = None - fileformat: str = None - geometry: str = None - medium: str = None - offset: float = None - primaries: float = None + filename: Optional[str] = None + fileformat: Optional[str] = None + geometry: Optional[str] = None + medium: Optional[str] = None + offset: Optional[float] = None + primaries: Optional[int] = None quantities: list[OutputQuantity] = field(default_factory=lambda: []) - rescale: float = None + rescale: Optional[float] = None filename_str_template: str = """ Filename {filename}""" diff --git a/converter/shieldhit/parser.py b/converter/shieldhit/parser.py index b8defbc4..849bbe8e 100644 --- a/converter/shieldhit/parser.py +++ b/converter/shieldhit/parser.py @@ -1,5 +1,6 @@ import itertools from pathlib import Path +from typing import Optional import converter.solid_figures as solid_figures from converter.common import Parser @@ -178,7 +179,7 @@ def _parse_scoring_outputs(self, json: dict) -> list[ScoringOutput]: return outputs - def _get_scoring_geometry_bu_uuid(self, geo_uuid: str) -> str: + def _get_scoring_geometry_bu_uuid(self, geo_uuid: str) -> Optional[str]: """Finds scoring geometry in the detect_config object by its uuid and returns its simmulation name.""" for scoring_geometry in self.detect_config.scoring_geometries: if scoring_geometry.uuid == geo_uuid: diff --git a/converter/shieldhit/scoring_geometries.py b/converter/shieldhit/scoring_geometries.py index 2aaebddc..6b17241d 100644 --- a/converter/shieldhit/scoring_geometries.py +++ b/converter/shieldhit/scoring_geometries.py @@ -86,7 +86,7 @@ class ScoringZone(ScoringGeometry): """Scoring zone dataclass used un DetectConfig.""" name: str - first_zone_id: str + first_zone_id: int last_zone_id: str = "" volume: float = 1. From d14a12e481f5dce5923197cda9db52f2b1a13aa1 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 12 May 2023 17:27:55 +0200 Subject: [PATCH 03/23] fixes --- converter/shieldhit/detect.py | 4 ++-- converter/shieldhit/geo.py | 13 +++++++------ converter/shieldhit/parser.py | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/converter/shieldhit/detect.py b/converter/shieldhit/detect.py index 7061dc9d..c7398f7a 100644 --- a/converter/shieldhit/detect.py +++ b/converter/shieldhit/detect.py @@ -30,9 +30,9 @@ class OutputQuantity: detector_type: str filter_name: str = "" diff1: Optional[tuple[float, float, float, str]] = None - diff1_t: str = None + diff1_t: Optional[str] = None diff2: Optional[tuple[float, float, float, str]] = None - diff2_t: str = None + diff2_t: Optional[str] = None quantity_template: str = """ Quantity {detector_type} {filter_name}""" diff --git a/converter/shieldhit/geo.py b/converter/shieldhit/geo.py index 2e8559b8..a4ae4467 100644 --- a/converter/shieldhit/geo.py +++ b/converter/shieldhit/geo.py @@ -1,3 +1,4 @@ +from typing import Optional from converter.solid_figures import SolidFigure, BoxFigure, CylinderFigure, SphereFigure from dataclasses import dataclass, field from math import log10, ceil, isclose @@ -161,7 +162,7 @@ class Material: uuid: str icru: int - density: float = None + density: Optional[float] = None idx: int = 0 property_template = """{name} {value}\n""" @@ -184,7 +185,7 @@ class Zone: id: int = 1 figures_operators: list[set[int]] = field(default_factory=lambda: [{1}]) - material: str = "0" + material: int = 0 material_override: dict[str, str] = field(default_factory=dict) zone_template: str = """ @@ -214,19 +215,19 @@ class GeoMatConfig: figures_operators=[{ 1, }], - material="1", + material=1, ), Zone( uuid="", id=2, figures_operators=[{-1, 2}], - material="1000", + material=1000, ), Zone( uuid="", id=3, figures_operators=[{-2, 3}], - material="0", + material=0, ), ]) materials: list[Material] = field(default_factory=lambda: [Material('', 276)]) @@ -244,7 +245,7 @@ class GeoMatConfig: """ @staticmethod - def _split_zones_to_rows(zones: list[Zone], max_size=14) -> list[list[Zone]]: + def _split_zones_to_rows(zones: list[int], max_size=14) -> list[list[int]]: """Split list of Zones into rows of not more than 14 elements""" return [zones[i:min(i + max_size, len(zones))] for i in range(0, len(zones), max_size)] diff --git a/converter/shieldhit/parser.py b/converter/shieldhit/parser.py index 849bbe8e..605705dd 100644 --- a/converter/shieldhit/parser.py +++ b/converter/shieldhit/parser.py @@ -363,9 +363,9 @@ def _parse_csg_operations(self, operations: list[list[dict]]) -> list[set[int]]: Parse dict of csg operations to a list of sets. Sets contain a list of intersecting geometries. The list contains a union of geometries from sets. """ - operations = [item for ops in operations for item in ops] + list_of_operations = [item for ops in operations for item in ops] parsed_operations = [] - for operation in operations: + for operation in list_of_operations: # lists are numbered from 0, but shieldhit figures are numbered from 1 figure_id = self._get_figure_index_by_uuid(operation["objectUuid"]) + 1 if operation["mode"] == "union": From 00d3a6efdfabf0348c104a0f91efcd7cc3aa213d Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 12 May 2023 18:07:58 +0200 Subject: [PATCH 04/23] fixes --- converter/common.py | 1 - converter/shieldhit/beam.py | 3 ++- converter/shieldhit/parser.py | 14 +++++++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/converter/common.py b/converter/common.py index 1b97c671..016d4c19 100644 --- a/converter/common.py +++ b/converter/common.py @@ -1,4 +1,3 @@ -from abc import abstractmethod from pathlib import Path diff --git a/converter/shieldhit/beam.py b/converter/shieldhit/beam.py index bf5610c5..02a9c7fb 100644 --- a/converter/shieldhit/beam.py +++ b/converter/shieldhit/beam.py @@ -71,7 +71,8 @@ class BeamConfig: energy_cutoff_template = "TCUT0 {energy_low_cutoff} {energy_high_cutoff} ! energy cutoffs [MeV]" sad_template = "BEAMSAD {sad_x} {sad_y} ! BEAMSAD value [cm]" beam_source_type: BeamSourceType = BeamSourceType.SIMPLE - beam_source_file: Optional[str] = None + beam_source_filename: Optional[str] = None + beam_source_file_content: Optional[str] = None beam_dat_template: str = """ RNDSEED 89736501 ! Random seed diff --git a/converter/shieldhit/parser.py b/converter/shieldhit/parser.py index 605705dd..7722257b 100644 --- a/converter/shieldhit/parser.py +++ b/converter/shieldhit/parser.py @@ -1,5 +1,4 @@ import itertools -from pathlib import Path from typing import Optional import converter.solid_figures as solid_figures @@ -73,8 +72,10 @@ def _parse_beam(self, json: dict) -> None: if json["beam"].get("beamSourceType", "") == BeamSourceType.FILE.value: self.beam_config.beam_source_type = BeamSourceType.FILE - self.beam_config.beam_source_file = json["beam"].get("beamSourceFile", '') - + if "beamSourceFile" in json["beam"]: + self.beam_config.beam_source_filename = json["beam"]["beamSourceFile"].get("name") + self.beam_config.beam_source_file_content = json["beam"]["beamSourceFile"].get("value") + if "physic" in json: self.beam_config.delta_e = json["physic"].get("energyLoss", self.beam_config.delta_e) self.beam_config.nuclear_reactions = json["physic"].get( @@ -396,7 +397,7 @@ def _calculate_world_zone_operations(self, world_zone_figure: int) -> list[set[i world_zone = new_world_zone # filter out sets containing oposite pairs of values - world_zone = filter(lambda x: not any(abs(i) == abs(j) for i, j in itertools.combinations(x, 2)), world_zone) + world_zone = list(filter(lambda x: not any(abs(i) == abs(j) for i, j in itertools.combinations(x, 2)), world_zone)) return world_zone @@ -420,6 +421,9 @@ def get_configs_json(self) -> dict: if self.beam_config.beam_source_type == BeamSourceType.FILE: - configs_json["sobp.dat"] = self.beam_config.beam_source_file['value'] + filename_of_beam_source_file : str = 'sobp.dat' + if not self.beam_config.beam_source_filename: + filename_of_beam_source_file = str(self.beam_config.beam_source_filename) + configs_json[filename_of_beam_source_file] = str(self.beam_config.beam_source_file_content) return configs_json From 0bc12d6225dff3b4071ff6524fea8887c8b8cde7 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 12 May 2023 18:15:16 +0200 Subject: [PATCH 05/23] fixes --- converter/shieldhit/parser.py | 7 +++---- converter/solid_figures.py | 8 ++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/converter/shieldhit/parser.py b/converter/shieldhit/parser.py index 7722257b..caa320f7 100644 --- a/converter/shieldhit/parser.py +++ b/converter/shieldhit/parser.py @@ -75,7 +75,7 @@ def _parse_beam(self, json: dict) -> None: if "beamSourceFile" in json["beam"]: self.beam_config.beam_source_filename = json["beam"]["beamSourceFile"].get("name") self.beam_config.beam_source_file_content = json["beam"]["beamSourceFile"].get("value") - + if "physic" in json: self.beam_config.delta_e = json["physic"].get("energyLoss", self.beam_config.delta_e) self.beam_config.nuclear_reactions = json["physic"].get( @@ -397,9 +397,9 @@ def _calculate_world_zone_operations(self, world_zone_figure: int) -> list[set[i world_zone = new_world_zone # filter out sets containing oposite pairs of values - world_zone = list(filter(lambda x: not any(abs(i) == abs(j) for i, j in itertools.combinations(x, 2)), world_zone)) + world_zone = filter(lambda x: not any(abs(i) == abs(j) for i, j in itertools.combinations(x, 2)), world_zone) - return world_zone + return list(world_zone) def _get_figure_index_by_uuid(self, figure_uuid: str) -> int: """Find the list index of a figure from geo_mat_config.figures by uuid. Usefull when parsing CSG operations.""" @@ -419,7 +419,6 @@ def get_configs_json(self) -> dict: "geo.dat": self.geo_mat_config.get_geo_string() } - if self.beam_config.beam_source_type == BeamSourceType.FILE: filename_of_beam_source_file : str = 'sobp.dat' if not self.beam_config.beam_source_filename: diff --git a/converter/solid_figures.py b/converter/solid_figures.py index b7d5ee3d..d7fce039 100644 --- a/converter/solid_figures.py +++ b/converter/solid_figures.py @@ -11,9 +11,10 @@ class SolidFigure(ABC): """ uuid: str = "AAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA" + name: str = "" - position: tuple[float, float, float] = field(default_factory=lambda: [0., 0., 0.]) - rotation: tuple[float, float, float] = field(default_factory=lambda: [0., 0., 0.]) + position: tuple[float, float, float] = field(default_factory=lambda: (0., 0., 0.)) + rotation: tuple[float, float, float] = field(default_factory=lambda: (0., 0., 0.)) def expand(self, margin: float) -> None: """Expand figure by `expansion` in each dimension.""" @@ -84,6 +85,7 @@ def parse_figure(figure_dict: dict) -> SolidFigure: if figure_type == "CylinderGeometry": return CylinderFigure( uuid=figure_dict["uuid"], + name=figure_dict["name"], position=tuple(figure_dict["geometryData"]["position"]), rotation=tuple(figure_dict["geometryData"]["rotation"]), radius_top=figure_dict["geometryData"]['parameters']["radius"], @@ -93,6 +95,7 @@ def parse_figure(figure_dict: dict) -> SolidFigure: if figure_type == "BoxGeometry": return BoxFigure( uuid=figure_dict["uuid"], + name=figure_dict["name"], position=tuple(figure_dict["geometryData"]["position"]), rotation=tuple(figure_dict["geometryData"]["rotation"]), y_edge_length=figure_dict["geometryData"]['parameters']["height"], @@ -102,6 +105,7 @@ def parse_figure(figure_dict: dict) -> SolidFigure: if figure_type == "SphereGeometry": return SphereFigure( uuid=figure_dict["uuid"], + name=figure_dict["name"], position=tuple(figure_dict["geometryData"]["position"]), rotation=tuple(figure_dict["geometryData"]["rotation"]), radius=figure_dict["geometryData"]['parameters']["radius"], From a294825a26f65c281c0e51f3fbd53cfe2d84fea6 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 12 May 2023 18:53:57 +0200 Subject: [PATCH 06/23] tests refactoring --- tests/{ => fluka}/test_fluka_converter.py | 0 tests/{ => shieldhit}/test_helpers.py | 0 tests/{ => shieldhit}/test_shieldhit_config_mappings.py | 0 tests/{ => shieldhit}/test_shieldhit_converter.py | 0 tests/{ => shieldhit}/test_shieldit_beam.py | 0 tests/{ => shieldhit}/test_zones.py | 0 tests/{ => topas}/test_topas_converter.py | 4 +++- 7 files changed, 3 insertions(+), 1 deletion(-) rename tests/{ => fluka}/test_fluka_converter.py (100%) rename tests/{ => shieldhit}/test_helpers.py (100%) rename tests/{ => shieldhit}/test_shieldhit_config_mappings.py (100%) rename tests/{ => shieldhit}/test_shieldhit_converter.py (100%) rename tests/{ => shieldhit}/test_shieldit_beam.py (100%) rename tests/{ => shieldhit}/test_zones.py (100%) rename tests/{ => topas}/test_topas_converter.py (95%) diff --git a/tests/test_fluka_converter.py b/tests/fluka/test_fluka_converter.py similarity index 100% rename from tests/test_fluka_converter.py rename to tests/fluka/test_fluka_converter.py diff --git a/tests/test_helpers.py b/tests/shieldhit/test_helpers.py similarity index 100% rename from tests/test_helpers.py rename to tests/shieldhit/test_helpers.py diff --git a/tests/test_shieldhit_config_mappings.py b/tests/shieldhit/test_shieldhit_config_mappings.py similarity index 100% rename from tests/test_shieldhit_config_mappings.py rename to tests/shieldhit/test_shieldhit_config_mappings.py diff --git a/tests/test_shieldhit_converter.py b/tests/shieldhit/test_shieldhit_converter.py similarity index 100% rename from tests/test_shieldhit_converter.py rename to tests/shieldhit/test_shieldhit_converter.py diff --git a/tests/test_shieldit_beam.py b/tests/shieldhit/test_shieldit_beam.py similarity index 100% rename from tests/test_shieldit_beam.py rename to tests/shieldhit/test_shieldit_beam.py diff --git a/tests/test_zones.py b/tests/shieldhit/test_zones.py similarity index 100% rename from tests/test_zones.py rename to tests/shieldhit/test_zones.py diff --git a/tests/test_topas_converter.py b/tests/topas/test_topas_converter.py similarity index 95% rename from tests/test_topas_converter.py rename to tests/topas/test_topas_converter.py index 587d6edc..8d198418 100644 --- a/tests/test_topas_converter.py +++ b/tests/topas/test_topas_converter.py @@ -76,7 +76,9 @@ def parser() -> Parser: @pytest.fixture def default_json() -> dict: """Creates default json.""" - file_path = Path.cwd() / "input_examples" / "sh_parser_test.json" + this_script_path = Path(__file__).parent + main_project_dir = this_script_path.parent.parent + file_path = main_project_dir / "input_examples" / "sh_parser_test.json" with file_path.open(mode='r') as json_f: return json.load(json_f) From bfe7f3eeb74d96c5a203f331900c6b9ed8392f02 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sat, 13 May 2023 19:58:22 +0200 Subject: [PATCH 07/23] moving example JSON to tests resources --- README.md | 3 +- .../expected_shieldhit_output/beam.dat | 14 ---- .../expected_shieldhit_output/detect.dat | 75 ------------------- .../expected_shieldhit_output/geo.dat | 15 ---- .../expected_shieldhit_output/mat.dat | 3 - tests/shieldhit/conftest.py | 10 +++ .../shieldhit/resources}/README.md | 0 .../expected_shieldhit_output/README.md | 0 .../shieldhit/resources/project.json | 0 9 files changed, 12 insertions(+), 108 deletions(-) delete mode 100644 input_examples/expected_shieldhit_output/beam.dat delete mode 100644 input_examples/expected_shieldhit_output/detect.dat delete mode 100644 input_examples/expected_shieldhit_output/geo.dat delete mode 100644 input_examples/expected_shieldhit_output/mat.dat create mode 100644 tests/shieldhit/conftest.py rename {input_examples => tests/shieldhit/resources}/README.md (100%) rename {input_examples => tests/shieldhit/resources}/expected_shieldhit_output/README.md (100%) rename input_examples/sh_parser_test.json => tests/shieldhit/resources/project.json (100%) diff --git a/README.md b/README.md index 78bc9669..dc148eda 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ The Converter of the project file (JSON file generated by frontend part) into a set of input files for particle transport simulators: - SHIELD-HIT12A (beam.dat, mat.dat, geo.dat and detect.dat). - TOPAS + - Fluka ## Requirements - Python 3.9+ @@ -28,7 +29,7 @@ It is capable of transforming JSON project file (generated in the yaptide web in To run the converter use the following command: ```bash -python converter/main.py editor.json workspace +python converter/main.py tests/shieldhit/resources/project.json workspace ``` ## Testing diff --git a/input_examples/expected_shieldhit_output/beam.dat b/input_examples/expected_shieldhit_output/beam.dat deleted file mode 100644 index c365ba88..00000000 --- a/input_examples/expected_shieldhit_output/beam.dat +++ /dev/null @@ -1,14 +0,0 @@ - -RNDSEED 89736501 ! Random seed -JPART0 2 ! Incident particle type -TMAX0 150.0 1.5 ! Incident energy and energy spread; both in (MeV/nucl) -TCUT0 0 1000 ! energy cutoffs [MeV] -NSTAT 10000 0 ! NSTAT, Step of saving -STRAGG 2 ! Straggling: 0-Off 1-Gauss, 2-Vavilov -MSCAT 2 ! Mult. scatt 0-Off 1-Gauss, 2-Moliere -NUCRE 1 ! Nucl.Reac. switcher: 1-ON, 0-OFF -BEAMPOS 0 0 0 ! Position of the beam -BEAMDIR 0.0 0.0 ! Direction of the beam -BEAMSIGMA 0 0 ! Beam extension -! no BEAMSAD value -DELTAE 0.03 ! relative mean energy loss per transportation step diff --git a/input_examples/expected_shieldhit_output/detect.dat b/input_examples/expected_shieldhit_output/detect.dat deleted file mode 100644 index dbaaf384..00000000 --- a/input_examples/expected_shieldhit_output/detect.dat +++ /dev/null @@ -1,75 +0,0 @@ -Geometry Cyl - Name CylZ_Mesh - R 0 5 1 - Z 0 20 400 - -Geometry Mesh - Name YZ_Mesh - X -0.25 0.25 1 - Y -2 2 80 - Z 0 20 400 - -Geometry Cyl - Name EntrySlab - R 0 5 1 - Z 0 0.1 1 - -Geometry Cyl - Name PeakSlab - R 0 5 1 - Z 15.3 15.4 1 - -Filter - Name Protons - Z == 1 - A == 1 -Filter - Name Primaries - Z == 1 - A == 1 - GEN == 0 -Filter - Name Secondary_protons - Z == 1 - A == 1 - GEN >= 1 -Output - Filename z_profile.bdo - Geo CylZ_Mesh - Quantity Dose - Quantity Fluence Protons - Quantity Fluence Primaries - Quantity Fluence Secondary_protons - -Output - Filename yz_profile.bdo - Geo YZ_Mesh - Quantity Dose - Quantity Fluence Protons - Quantity Fluence Secondary_protons - -Output - Filename entrance.bdo - Geo EntrySlab - Quantity Dose - Quantity AvgEnergy Primaries - Quantity AvgEnergy Protons - Quantity AvgEnergy Secondary_protons - Quantity dLET Protons - Quantity tLET Protons - Quantity Fluence Protons - Diff1 0 160 640 - Diff1Type E - -Output - Filename peak.bdo - Geo PeakSlab - Quantity Dose - Quantity AvgEnergy Primaries - Quantity AvgEnergy Protons - Quantity AvgEnergy Secondary_protons - Quantity dLET Protons - Quantity tLET Protons - Quantity Fluence Protons - Diff1 0 160 640 - Diff1Type E diff --git a/input_examples/expected_shieldhit_output/geo.dat b/input_examples/expected_shieldhit_output/geo.dat deleted file mode 100644 index f8d9de32..00000000 --- a/input_examples/expected_shieldhit_output/geo.dat +++ /dev/null @@ -1,15 +0,0 @@ - - 0 0 Proton pencil beam in water - RCC 1 0.0 0.0 0.0 0.0 0.0 20.0 - 5.0 - RCC 2 0.0 0.0 -0.5 0.0 0.0 22.0 - 5.5 - RCC 3 0.0 0.0 -1.5 0.0 0.0 24.0 - 6.0 - END - 001 +1 - 002 +2 -1 - 003 -2 +3 -1 - END - 1 2 3 - 1 1000 0 diff --git a/input_examples/expected_shieldhit_output/mat.dat b/input_examples/expected_shieldhit_output/mat.dat deleted file mode 100644 index 2c80bf7c..00000000 --- a/input_examples/expected_shieldhit_output/mat.dat +++ /dev/null @@ -1,3 +0,0 @@ -MEDIUM 1 -ICRU 276 -END diff --git a/tests/shieldhit/conftest.py b/tests/shieldhit/conftest.py new file mode 100644 index 00000000..d2d91dae --- /dev/null +++ b/tests/shieldhit/conftest.py @@ -0,0 +1,10 @@ +from pathlib import Path +import pytest +import json + +@pytest.fixture(scope='session') +def default_json() -> dict: + """Creates default json.""" + example_json = Path(__file__).parent.parent / 'input_examples' / 'sh_parser_test.json' + with open(example_json, 'r') as json_f: + return json.load(json_f) \ No newline at end of file diff --git a/input_examples/README.md b/tests/shieldhit/resources/README.md similarity index 100% rename from input_examples/README.md rename to tests/shieldhit/resources/README.md diff --git a/input_examples/expected_shieldhit_output/README.md b/tests/shieldhit/resources/expected_shieldhit_output/README.md similarity index 100% rename from input_examples/expected_shieldhit_output/README.md rename to tests/shieldhit/resources/expected_shieldhit_output/README.md diff --git a/input_examples/sh_parser_test.json b/tests/shieldhit/resources/project.json similarity index 100% rename from input_examples/sh_parser_test.json rename to tests/shieldhit/resources/project.json From 240e9e2d9651047aa985020efda90ee2a62cdc04 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sat, 13 May 2023 20:12:16 +0200 Subject: [PATCH 08/23] tests fixing --- tests/conftest.py | 11 ++ tests/shieldhit/conftest.py | 10 -- tests/shieldhit/test_shieldhit_converter.py | 7 +- tests/test_solid_figures.py | 109 ++++---------------- 4 files changed, 33 insertions(+), 104 deletions(-) create mode 100644 tests/conftest.py delete mode 100644 tests/shieldhit/conftest.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..104cceb6 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,11 @@ +from pathlib import Path +import pytest +import json + +@pytest.fixture(scope='session') +def project_shieldhit_json() -> dict: + """Dictionary with project data for SHIELD-HIT12A""" + this_file_location = Path(__file__).parent + json_file_path = this_file_location / 'shieldhit' / 'resources' / 'project.json' + with open(json_file_path, 'r') as file_handle: + return json.load(file_handle) \ No newline at end of file diff --git a/tests/shieldhit/conftest.py b/tests/shieldhit/conftest.py deleted file mode 100644 index d2d91dae..00000000 --- a/tests/shieldhit/conftest.py +++ /dev/null @@ -1,10 +0,0 @@ -from pathlib import Path -import pytest -import json - -@pytest.fixture(scope='session') -def default_json() -> dict: - """Creates default json.""" - example_json = Path(__file__).parent.parent / 'input_examples' / 'sh_parser_test.json' - with open(example_json, 'r') as json_f: - return json.load(json_f) \ No newline at end of file diff --git a/tests/shieldhit/test_shieldhit_converter.py b/tests/shieldhit/test_shieldhit_converter.py index c3c516f2..a9db50c1 100644 --- a/tests/shieldhit/test_shieldhit_converter.py +++ b/tests/shieldhit/test_shieldhit_converter.py @@ -15,12 +15,7 @@ def parser() -> Parser: return get_parser_from_str('shieldhit') -@pytest.fixture -def default_json() -> dict: - """Creates default json.""" - example_json = Path(__file__).parent.parent / 'input_examples' / 'sh_parser_test.json' - with open(example_json, 'r') as json_f: - return json.load(json_f) + def test_if_parser_created(parser: Parser) -> None: """Check if parser is created""" diff --git a/tests/test_solid_figures.py b/tests/test_solid_figures.py index 09886d96..5a11f1eb 100644 --- a/tests/test_solid_figures.py +++ b/tests/test_solid_figures.py @@ -1,91 +1,24 @@ import pytest from converter import solid_figures -_Json_with_figures = { - "object": { - "children": [ - { - "uuid": "3A594908-17F2-4858-A16E-EE20BD387C26", - "geometryData": { - "id": 940, - "geometryType": "CylinderGeometry", - "position": [1, 2, 3], - "rotation": [45, 60, 90], - "parameters": { - "radius": 1, - "depth": 1 - } - }, - }, - { - "uuid": "CBE326F9-48BB-4E5D-83CC-4F85B057AE00", - "geometryData": { - "id": 941, - "geometryType": "BoxGeometry", - "position": [1, 2, 3], - "rotation": [45, 60, 90], - "parameters": { - "width": 1, - "height": 1, - "depth": 1 - } - }, - }, - { - "uuid": "B0568AB3-A8F8-4615-8FF1-6121B506456F", - "geometryData": { - "id": 1113, - "geometryType": "SphereGeometry", - "position": [1, 2, 3], - "rotation": [45, 60, 90], - "parameters": { - "radius": 1 - } - }, - }, - ] - } -} - -_Cylinder_json = _Json_with_figures["object"]["children"][0] -_Box_json = _Json_with_figures["object"]["children"][1] -_Sphere_json = _Json_with_figures["object"]["children"][2] - - -@pytest.fixture -def figure(request): - """Fixture that provides a figure based on a json that contains figure information.""" - return solid_figures.parse_figure(request.param) - - -@pytest.mark.parametrize("figure,expected", [(_Cylinder_json, solid_figures.CylinderFigure), - (_Box_json, solid_figures.BoxFigure), - (_Sphere_json, solid_figures.SphereFigure)], - indirect=["figure"]) -def test_type(figure, expected): - """Test if parser returns correct figure object type""" - assert type(figure) is expected - - -@pytest.mark.parametrize("figure,expected", [(_Cylinder_json, _Cylinder_json), (_Box_json, _Box_json), - (_Sphere_json, _Sphere_json)], - indirect=["figure"]) -def test_uuid(figure, expected): - """Test if figure_parser parses uuid correctly""" - assert figure.uuid == expected['uuid'] - - -@pytest.mark.parametrize("figure,expected", [(_Cylinder_json, _Cylinder_json), (_Box_json, _Box_json), - (_Sphere_json, _Sphere_json)], - indirect=["figure"]) -def test_position(figure, expected): - """Test if figure_parser parses position(position) correctly""" - assert figure.position == tuple(expected['geometryData']['position']) - - -@pytest.mark.parametrize("figure,expected", [(_Cylinder_json, _Cylinder_json), (_Box_json, _Box_json), - (_Sphere_json, _Sphere_json)], - indirect=["figure"]) -def test_rotation(figure, expected): - """Test if figure_parser parses rotation correctly""" - assert figure.rotation == tuple(expected['geometryData']['rotation']) +@pytest.fixture(scope='module') +def cylinder_figure_dict(project_shieldhit_json): + return project_shieldhit_json['scene']['object']['children'][0] + +def test_cylinder_figure(cylinder_figure_dict): + assert cylinder_figure_dict['type'] == 'CylinderMesh' + assert cylinder_figure_dict['name'] == 'Water_phantom_cylinder' + assert 'geometryData' in cylinder_figure_dict + + cylinder_figure_obj = solid_figures.parse_figure(cylinder_figure_dict) + assert isinstance(cylinder_figure_obj, solid_figures.CylinderFigure) + assert cylinder_figure_obj.radius_top == 5 + assert cylinder_figure_obj.radius_bottom == 5 + assert cylinder_figure_obj.height == 20 + assert cylinder_figure_obj.name == cylinder_figure_dict['name'] + assert cylinder_figure_obj.rotation[0] == cylinder_figure_dict['geometryData']['rotation'][0] + assert cylinder_figure_obj.rotation[1] == cylinder_figure_dict['geometryData']['rotation'][1] + assert cylinder_figure_obj.rotation[2] == cylinder_figure_dict['geometryData']['rotation'][2] + assert cylinder_figure_obj.position[0] == cylinder_figure_dict['geometryData']['position'][0] + assert cylinder_figure_obj.position[1] == cylinder_figure_dict['geometryData']['position'][1] + assert cylinder_figure_obj.position[2] == cylinder_figure_dict['geometryData']['position'][2] From 0e167406c6a6a98b7595b437484ee8dbe94173e1 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sat, 13 May 2023 20:15:13 +0200 Subject: [PATCH 09/23] fixing TOPAS --- tests/test_solid_figures.py | 2 ++ tests/topas/conftest.py | 8 ++++++++ tests/topas/test_topas_converter.py | 12 ++---------- 3 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 tests/topas/conftest.py diff --git a/tests/test_solid_figures.py b/tests/test_solid_figures.py index 5a11f1eb..564395ee 100644 --- a/tests/test_solid_figures.py +++ b/tests/test_solid_figures.py @@ -3,9 +3,11 @@ @pytest.fixture(scope='module') def cylinder_figure_dict(project_shieldhit_json): + """Part of the project.json file with the cylinder figure""" return project_shieldhit_json['scene']['object']['children'][0] def test_cylinder_figure(cylinder_figure_dict): + """Test if the cylinder figure is parsed correctly""" assert cylinder_figure_dict['type'] == 'CylinderMesh' assert cylinder_figure_dict['name'] == 'Water_phantom_cylinder' assert 'geometryData' in cylinder_figure_dict diff --git a/tests/topas/conftest.py b/tests/topas/conftest.py new file mode 100644 index 00000000..c1751d07 --- /dev/null +++ b/tests/topas/conftest.py @@ -0,0 +1,8 @@ +from pathlib import Path +import pytest +import json + +@pytest.fixture(scope='session') +def project_topas_json(project_shieldhit_json) -> dict: + """We do not have yet project.json for TOPAS, so we use the one from SHIELD-HIT12A""" + return project_shieldhit_json \ No newline at end of file diff --git a/tests/topas/test_topas_converter.py b/tests/topas/test_topas_converter.py index 8d198418..9b0b1b68 100644 --- a/tests/topas/test_topas_converter.py +++ b/tests/topas/test_topas_converter.py @@ -73,20 +73,12 @@ def parser() -> Parser: """Just a parser fixture.""" return get_parser_from_str('topas') -@pytest.fixture -def default_json() -> dict: - """Creates default json.""" - this_script_path = Path(__file__).parent - main_project_dir = this_script_path.parent.parent - file_path = main_project_dir / "input_examples" / "sh_parser_test.json" - with file_path.open(mode='r') as json_f: - return json.load(json_f) @pytest.fixture -def output_dir(tmp_path_factory, parser, default_json) -> str: +def output_dir(tmp_path_factory, parser, project_topas_json) -> str: """Fixture that creates a temporary dir for testing converter output and runs the conversion there.""" output_dir = tmp_path_factory.mktemp(_Test_dir) - run_parser(parser, default_json, output_dir) + run_parser(parser, project_topas_json, output_dir) return output_dir def test_if_parser_created(parser) -> None: From 73ab7d365eb2deb3cf78a249d72f46a61c687450 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sat, 13 May 2023 21:49:53 +0200 Subject: [PATCH 10/23] fixing tests --- tests/conftest.py | 13 +- tests/shieldhit/conftest.py | 17 +++ tests/shieldhit/test_shieldhit_converter.py | 39 ++--- tests/shieldhit/test_shieldit_beam.py | 58 +------- tests/shieldhit/test_zones.py | 155 ++------------------ 5 files changed, 65 insertions(+), 217 deletions(-) create mode 100644 tests/shieldhit/conftest.py diff --git a/tests/conftest.py b/tests/conftest.py index 104cceb6..08d2aa83 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,9 +3,14 @@ import json @pytest.fixture(scope='session') -def project_shieldhit_json() -> dict: - """Dictionary with project data for SHIELD-HIT12A""" +def project_shieldhit_path() -> Path: + """Path to SHIELD-HIT12A project.json file""" this_file_location = Path(__file__).parent json_file_path = this_file_location / 'shieldhit' / 'resources' / 'project.json' - with open(json_file_path, 'r') as file_handle: - return json.load(file_handle) \ No newline at end of file + return json_file_path + +@pytest.fixture(scope='session') +def project_shieldhit_json(project_shieldhit_path) -> dict: + """Dictionary with project data for SHIELD-HIT12A""" + with open(project_shieldhit_path, 'r') as file_handle: + return json.load(file_handle) diff --git a/tests/shieldhit/conftest.py b/tests/shieldhit/conftest.py new file mode 100644 index 00000000..6499592d --- /dev/null +++ b/tests/shieldhit/conftest.py @@ -0,0 +1,17 @@ +from pathlib import Path +import pytest +from converter.api import get_parser_from_str + +from converter.common import Parser + + +@pytest.fixture(scope='session') +def sh12a_parser() -> Parser: + """Just a parser fixture.""" + return get_parser_from_str('shieldhit') + + +@pytest.fixture(scope='session') +def path_to_dir_with_expected_output(project_shieldhit_path: Path) -> Path: + """Just a parser fixture.""" + return project_shieldhit_path.parent / 'expected_shieldhit_output' diff --git a/tests/shieldhit/test_shieldhit_converter.py b/tests/shieldhit/test_shieldhit_converter.py index a9db50c1..a32ace8e 100644 --- a/tests/shieldhit/test_shieldhit_converter.py +++ b/tests/shieldhit/test_shieldhit_converter.py @@ -9,30 +9,33 @@ from converter.shieldhit.parser import Parser -@pytest.fixture -def parser() -> Parser: - """SHIELD-HIT12A parser fixture""" - return get_parser_from_str('shieldhit') +def test_parser(sh12a_parser : Parser) -> None: + """Check if parser is created correctly""" + assert sh12a_parser + assert sh12a_parser.info['version'] == '' + assert sh12a_parser.info['simulator'] == 'shieldhit' + +def test_project_json(project_shieldhit_json: dict) -> None: + """Check if project json is created correctly""" + assert project_shieldhit_json + assert "metadata" in project_shieldhit_json + assert "project" in project_shieldhit_json + assert "scene" in project_shieldhit_json + assert "physic" in project_shieldhit_json + assert "energyLoss" in project_shieldhit_json["physic"] + assert "enableNuclearReactions" in project_shieldhit_json["physic"] + assert "energyModelStraggling" in project_shieldhit_json["physic"] + assert "multipleScattering" in project_shieldhit_json["physic"] - - -def test_if_parser_created(parser: Parser) -> None: - """Check if parser is created""" - assert parser - assert parser.info['version'] == '' - assert parser.info['label'] == '' - assert parser.info['simulator'] == 'shieldhit' - @pytest.mark.parametrize('filename', ['beam.dat', 'mat.dat', 'detect.dat']) -def test_if_expected_files_created(parser: Parser, default_json : dict, tmp_path : Path, filename: str) -> None: +def test_if_expected_files_created(sh12a_parser: Parser, project_shieldhit_json : dict, tmp_path : Path, path_to_dir_with_expected_output: Path, filename: str) -> None: """Check if all output files are created""" logging.info('Checking %s file', filename) - run_parser(parser, default_json, tmp_path) - dir_with_expected_files = Path(__file__).parent.parent / 'input_examples' / 'expected_shieldhit_output' + run_parser(sh12a_parser, project_shieldhit_json, tmp_path) assert (tmp_path / filename).exists() - assert (dir_with_expected_files / filename).exists() - assert filecmp.cmp(tmp_path / filename, dir_with_expected_files / filename) + assert (path_to_dir_with_expected_output / filename).exists() + assert filecmp.cmp(tmp_path / filename, path_to_dir_with_expected_output / filename) @pytest.mark.parametrize('filename', ['geo.dat']) @pytest.mark.skip(reason="Something is wrong with geo.dat file.") diff --git a/tests/shieldhit/test_shieldit_beam.py b/tests/shieldhit/test_shieldit_beam.py index dc818bbf..a2f0a4d9 100644 --- a/tests/shieldhit/test_shieldit_beam.py +++ b/tests/shieldhit/test_shieldit_beam.py @@ -1,58 +1,14 @@ -import json from pathlib import Path -from converter.api import get_parser_from_str, run_parser -from converter.common import Parser -import pytest +from converter.api import run_parser -_Test_dir = './test_runs' - -@pytest.fixture -def project_json() -> dict: - """Fixture that provides a JSON with beam.dat dedicatet config.""" - this_script_path = Path(__file__).parent.absolute() - result = {} - with open(this_script_path / "resources" / "physics_settings.json", "r") as f: - result = json.load(f) - return result - -@pytest.fixture -def output_dir(tmp_path_factory) -> Path: - """Fixture that creates a temporary dir for testing converter output.""" - output_dir = tmp_path_factory.mktemp(_Test_dir) - return Path(output_dir) - - -@pytest.fixture -def sh12a_parser() -> Parser: - """Just a parser fixture.""" - return get_parser_from_str('shieldhit') - - -def test_project_json(project_json) -> None: - """Check if project json is created correctly""" - assert project_json - assert "metadata" in project_json - assert "project" in project_json - assert "scene" in project_json - assert "physic" in project_json - assert "energyLoss" in project_json["physic"] - assert "enableNuclearReactions" in project_json["physic"] - assert "energyModelStraggling" in project_json["physic"] - assert "multipleScattering" in project_json["physic"] - - -def test_parser(sh12a_parser) -> None: - """Check if parser is created correctly""" - assert sh12a_parser.info['version'] == '' - assert sh12a_parser.info['simulator'] == 'shieldhit' - -def test_generated_beam_dat(project_json, sh12a_parser, output_dir) -> None: +def test_generated_beam_dat(project_shieldhit_json, sh12a_parser, tmpdir) -> None: """Check if beam.dat file created properly""" - run_parser(sh12a_parser, project_json, output_dir) + output_dir = Path(tmpdir) + run_parser(sh12a_parser, project_shieldhit_json, output_dir) with open(output_dir / 'beam.dat') as f: input_text = f.read() assert input_text - assert "STRAGG 1" in input_text - assert "MSCAT 0" in input_text - assert "NUCRE 0" in input_text \ No newline at end of file + assert "STRAGG 2" in input_text + assert "MSCAT 2" in input_text + assert "NUCRE 1" in input_text \ No newline at end of file diff --git a/tests/shieldhit/test_zones.py b/tests/shieldhit/test_zones.py index 1c2840ff..b130e0e4 100644 --- a/tests/shieldhit/test_zones.py +++ b/tests/shieldhit/test_zones.py @@ -1,147 +1,14 @@ import pytest from converter.shieldhit.geo import Zone, parse_figure -from converter import solid_figures -_Box_test_cases = [ - ({ - "uuid": "CBE326F9-48BB-4E5D-83CC-4F85B057AE00", - "geometryData": { - "id": 941, - "geometryType": "BoxGeometry", - "position": [1, 2, 3], - "rotation": [0, 0, 0], - "parameters": { - "width": 1, - "height": 1, - "depth": 1 - } - }, - }, """ - BOX 1 0.5 1.5 2.5 1.0 0.0 0.0 - 0.0 1.0 0.0 0.0 0.0 1.0"""), -] - -_Cylinder_test_cases = [ - ({ - "uuid": "3A594908-17F2-4858-A16E-EE20BD387C26", - "geometryData": { - "id": 940, - "geometryType": "CylinderGeometry", - "position": [1, 2, 3], - "rotation": [0, 0, 0], - "parameters": { - "radius": 1, - "depth": 1 - } - }, - }, """ - RCC 1 1.0 2.0 2.5 0.0 0.0 1.0 - 1.0""") -] - -_Sphere_test_cases = [ - ({ - "uuid": "B0568AB3-A8F8-4615-8FF1-6121B506456F", - "geometryData": { - "id": 1113, - "geometryType": "SphereGeometry", - "position": [1, 2, 3], - "rotation": [0, 0, 0], - "parameters": { - "radius": 1 - } - }, - }, """ - SPH 1 1.0 2.0 3.0 1.0"""), -] - - -@pytest.fixture -def figure(request): - """Fixture that provides a figure based on a json that contains figure information.""" - return solid_figures.parse_figure(request.param) - - -@pytest.mark.parametrize("figure,expected", _Box_test_cases, indirect=["figure"]) -def test_box_parser(figure, expected): - """Test if boxes are parsed corectly.""" - assert parse_figure(figure, 1) == expected - - -@pytest.mark.parametrize("figure,expected", _Cylinder_test_cases, indirect=["figure"]) -def test_cylinder_parser(figure, expected): - """Test if cylinders are parsed corectly.""" - assert parse_figure(figure, 1) == expected - - -@pytest.mark.parametrize("figure,expected", _Sphere_test_cases, indirect=["figure"]) -def test_sphere_parser(figure, expected): - """Test if spheres are parsed corectly.""" - assert parse_figure(figure, 1) == expected - - -_Zone_test_cases = [ - ( - { - "id": 1, - "figures_operators": [{1}], - }, - """ - 001 +1""" - ), - ( - { - "id": 11, - "figures_operators": [{-2}], - }, - """ - 011 -2""" - ), - ( - { - "id": 111, - "figures_operators": [{1, -2}], - }, - """ - 111 +1 -2""" - ), - ( - { - "id": 2, - "figures_operators": [{1}, {-2}], - }, - """ - 002 +1OR -2""" - ), - ( - { - "id": 3, - "figures_operators": [{1, -2}, {11, -12, 13}], - }, - """ - 003 +1 -2OR +11 -12 +13""" - ), - ( - { - "id": 4, - "figures_operators": [{4, -2}, {2}, {3, 4}], - }, - """ - 004 +4 -2OR +2OR +3 +4""" - ) -] - - -@pytest.fixture -def zone(request): - """ - Fixture that provides a zone based on a list containing csg information, id - and material that the zone is made out of. - """ - return Zone("", **request.param) - - -@pytest.mark.parametrize("zone,expected", _Zone_test_cases, indirect=["zone"]) -def test_zone_geometries(zone, expected): - """Test if zone geometry string representation is correct.""" - assert str(zone) == expected +@pytest.fixture(scope='module') +def water_phantom_zone_dict(project_shieldhit_json): + """Part of the project.json file with the water phantom zone""" + return project_shieldhit_json['zoneManager']['zones'][0] + +def test_water_phantom_zone(water_phantom_zone_dict): + assert water_phantom_zone_dict['name'] == 'Water_phantom_zone' + zone_obj = Zone(water_phantom_zone_dict) + assert zone_obj.id == 1 + assert zone_obj.material == 0 # why ??? + assert str(zone_obj) == '\n 001 +1' From d61ab280b9a08918af9e470dda3152a689c7017e Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sat, 13 May 2023 22:02:54 +0200 Subject: [PATCH 11/23] missing files added --- .gitignore | 2 +- tests/resources/physics_settings.json | 651 ------------------ .../expected_shieldhit_output/beam.dat | 14 + .../expected_shieldhit_output/detect.dat | 75 ++ .../expected_shieldhit_output/geo.dat | 15 + .../expected_shieldhit_output/mat.dat | 3 + 6 files changed, 108 insertions(+), 652 deletions(-) delete mode 100644 tests/resources/physics_settings.json create mode 100644 tests/shieldhit/resources/expected_shieldhit_output/beam.dat create mode 100644 tests/shieldhit/resources/expected_shieldhit_output/detect.dat create mode 100644 tests/shieldhit/resources/expected_shieldhit_output/geo.dat create mode 100644 tests/shieldhit/resources/expected_shieldhit_output/mat.dat diff --git a/.gitignore b/.gitignore index 9f623987..59cec4ef 100644 --- a/.gitignore +++ b/.gitignore @@ -266,4 +266,4 @@ cython_debug/ # End of https://www.toptal.com/developers/gitignore/api/python,visualstudiocode,pycharm **/*.dat -!input_examples/expected_shieldhit_output/*.dat \ No newline at end of file +!tests/shieldhit/resources/expected_shieldhit_output/*.dat \ No newline at end of file diff --git a/tests/resources/physics_settings.json b/tests/resources/physics_settings.json deleted file mode 100644 index 3bb89cad..00000000 --- a/tests/resources/physics_settings.json +++ /dev/null @@ -1,651 +0,0 @@ -{ - "metadata": { - "version": 0.5, - "type": "Editor", - "generator": "Editor.toJSON" - }, - "project": { - "title": "Proton pencil beam in water", - "description": "Proton pencil beam with initial kinetic energy 150 MeV and 1% energy spread.\nThe target is a cylindrical water phantom with a radius of 10 cm and a length of 20 cm.\n\nWe score dose from all particles and fluence according to primary particles (protons), secondary protons, and all protons.", - "shadows": true, - "shadowType": 1, - "physicallyCorrectLights": false, - "toneMapping": 0, - "toneMappingExposure": 1, - "viewManager": { - "ViewPanelXY": { - "cameraMatrix": [1,0,0,0,0,0.9999999999994986,9.999999999621414e-7,0,0,-9.999999999621414e-7,0.9999999999994986,0,0,-0.00009999999999621423,99.99999999994995,1], - "clipPlane": { - "planeConstant": 0, - "visible": true - } - }, - "ViewPanel3D": { - "cameraMatrix": [0.7071067811865476,8.326672684688673e-17,-0.7071067811865471,0,-0.4082482904638628,0.8164965809277258,-0.40824829046386285,0,0.5773502691896253,0.5773502691896254,0.5773502691896257,0,10,10,10.000000000000002,1] - }, - "ViewPanelY": { - "cameraMatrix": [6.661338147750989e-16,-2.2204460492503294e-16,1.000000000000007,0,0.9999999999995064,0.0000010000000003618291,-4.440892098500656e-16,0,-0.0000010000000001397845,0.9999999999995064,4.440892098500656e-16,0,-0.00009999999999998334,99.99999999994999,6.1232339957357454e-21,1], - "clipPlane": { - "planeConstant": 0, - "visible": true - } - }, - "ViewPanelX": { - "cameraMatrix": [-2.2204460492503136e-16,1.0000000000000004,0,0,9.999999999177327e-7,-2.2204460492503116e-16,0.9999999999994995,0,0.9999999999994995,0,-0.0000010000000001397773,0,99.99999999994995,0,-0.0000999999999999833,1], - "clipPlane": { - "planeConstant": 0, - "visible": true - } - }, - "ViewPanel": { - "cameraMatrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,20,20.000000000000004,1] - } - } - }, - "scene": { - "metadata": { - "version": 4.5, - "type": "Object", - "generator": "Object3D.toJSON" - }, - "geometries": [ - { - "uuid": "744d5753-c4ab-4565-bfbd-77c981e84fec", - "type": "CylinderGeometry", - "radiusTop": 5, - "radiusBottom": 5, - "height": 20, - "radialSegments": 16, - "heightSegments": 1, - "openEnded": false, - "thetaStart": 0, - "thetaLength": 6.283185307179586 - }, - { - "uuid": "918ef747-7846-462d-ab4d-a1bfef2d196a", - "type": "CylinderGeometry", - "radiusTop": 5.5, - "radiusBottom": 5.5, - "height": 22, - "radialSegments": 16, - "heightSegments": 1, - "openEnded": false, - "thetaStart": 0, - "thetaLength": 6.283185307179586 - }], - "materials": [ - { - "uuid": "81a7aa32-b85f-45c4-bcd7-f648a0be12dc", - "type": "MeshBasicMaterial", - "color": 0, - "reflectivity": 1, - "refractionRatio": 0.98, - "side": 2, - "opacity": 0.5, - "transparent": true, - "depthFunc": 3, - "depthTest": true, - "depthWrite": true, - "colorWrite": true, - "stencilWrite": false, - "stencilWriteMask": 255, - "stencilFunc": 519, - "stencilRef": 0, - "stencilFuncMask": 255, - "stencilFail": 7680, - "stencilZFail": 7680, - "stencilZPass": 7680, - "wireframe": true - }, - { - "uuid": "8485707f-07bf-49d2-86ab-070eb9878a00", - "type": "MeshBasicMaterial", - "color": 0, - "reflectivity": 1, - "refractionRatio": 0.98, - "side": 2, - "opacity": 0.5, - "transparent": true, - "depthFunc": 3, - "depthTest": true, - "depthWrite": true, - "colorWrite": true, - "stencilWrite": false, - "stencilWriteMask": 255, - "stencilFunc": 519, - "stencilRef": 0, - "stencilFuncMask": 255, - "stencilFail": 7680, - "stencilZFail": 7680, - "stencilZPass": 7680, - "wireframe": true - }], - "object": { - "uuid": "C1BF5EE7-ACC7-4896-8451-A5B358DF9889", - "type": "Scene", - "name": "Figures", - "layers": 1, - "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1], - "children": [ - { - "uuid": "7ab62ba9-6dba-4543-b50b-ce31e143d482", - "type": "CylinderMesh", - "name": "Water_phantom_cylinder", - "visible": false, - "layers": 1, - "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,10,1], - "geometry": "744d5753-c4ab-4565-bfbd-77c981e84fec", - "material": "81a7aa32-b85f-45c4-bcd7-f648a0be12dc", - "geometryData": { - "id": 992, - "geometryType": "CylinderGeometry", - "position": [0,0,10], - "rotation": [0,0,0], - "parameters": { - "radius": 5, - "depth": 20 - } - } - }, - { - "uuid": "aeeffad9-ed86-44ae-bfe4-b5f78580741b", - "type": "CylinderMesh", - "name": "Vacuum_cylinder", - "visible": false, - "layers": 1, - "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,10.5,1], - "geometry": "918ef747-7846-462d-ab4d-a1bfef2d196a", - "material": "8485707f-07bf-49d2-86ab-070eb9878a00", - "geometryData": { - "id": 994, - "geometryType": "CylinderGeometry", - "position": [0,0,10.5], - "rotation": [0,0,0], - "parameters": { - "radius": 5.5, - "depth": 22 - } - } - }] - } - }, - "history": { - "undos": [], - "redos": [] - }, - "zoneManager": { - "zones": [ - { - "uuid": "9ee041c1-acc0-433f-bc66-90e057b72474", - "name": "Water_phantom_zone", - "materialUuid": "49ce56b9-ee48-4640-88d4-bcfd660d8c0e", - "unionOperations": [[ - { - "mode": "union", - "objectUuid": "7ab62ba9-6dba-4543-b50b-ce31e143d482" - }]], - "subscribedObjects": { - "7ab62ba9-6dba-4543-b50b-ce31e143d482": 1 - }, - "materialPropertiesOverrides": {} - }, - { - "uuid": "a2c614cf-7074-4abe-a757-4a850f6731b3", - "name": "Vacuum_zone", - "materialUuid": "cd7c2eb0-e91f-4144-b4eb-536e4626cc09", - "unionOperations": [[ - { - "mode": "union", - "objectUuid": "aeeffad9-ed86-44ae-bfe4-b5f78580741b" - }]], - "subscribedObjects": { - "aeeffad9-ed86-44ae-bfe4-b5f78580741b": 1 - }, - "materialPropertiesOverrides": {} - }], - "uuid": "368269D3-6F9B-4241-84A0-5D908D10E196", - "name": "Zones", - "worldZone": { - "uuid": "f947b247-8759-4dd8-9929-4993a0451410", - "center": { - "x": 0, - "y": 0, - "z": 10.5 - }, - "size": { - "x": 6, - "y": 6, - "z": 24 - }, - "type": "WorldZone", - "geometryType": "Cylinder", - "name": "World Zone", - "marginMultiplier": 1.1, - "autoCalculate": false, - "materialUuid": "1dd2e8f0-6684-42c2-ad35-7aa55358204e", - "geometryData": { - "id": 14, - "geometryType": "CylinderGeometry", - "position": [0,0,10.5], - "rotation": [0,0,0], - "parameters": { - "radius": 6, - "depth": 24 - } - } - } - }, - "detectManager": { - "uuid": "9A7D17B8-BAE4-441F-965F-490CAA617EC6", - "name": "DetectManager", - "detectGeometries": [ - { - "uuid": "186ec65a-8511-418b-8218-8890138c6b12", - "data": { - "radius": 5, - "innerRadius": 0, - "depth": 20, - "radialSegments": 1, - "zSegments": 400 - }, - "type": "Cyl", - "position": [0,0,10], - "name": "CylZ_Mesh", - "colorHex": 327424 - }, - { - "uuid": "3306e98b-5da2-46ee-8892-ac0191d645a7", - "data": { - "width": 0.5, - "height": 4, - "depth": 20, - "xSegments": 1, - "ySegments": 80, - "zSegments": 400 - }, - "type": "Mesh", - "position": [0,0,10], - "name": "YZ_Mesh", - "colorHex": 65535 - }, - { - "uuid": "53fff3c4-30de-4210-9066-20dc0f90cccb", - "data": { - "radius": 5, - "innerRadius": 0, - "depth": 0.1, - "radialSegments": 1, - "zSegments": 1 - }, - "type": "Cyl", - "position": [0,0,0.05], - "name": "EntrySlab", - "colorHex": 65535 - }, - { - "uuid": "deb6a8f8-fab3-488e-8a01-9bb3e8ea4649", - "data": { - "radius": 5, - "innerRadius": 0, - "depth": 0.1, - "radialSegments": 1, - "zSegments": 1 - }, - "type": "Cyl", - "position": [0,0,15.35], - "name": "PeakSlab", - "colorHex": 65535 - }], - "filters": [ - { - "uuid": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "name": "Protons", - "rules": [ - { - "uuid": "e5f50132-6d2a-4606-a58d-24a764d1a413", - "keyword": "Z", - "operator": "==", - "value": 1 - }, - { - "uuid": "f25fb8bb-fdaa-49ae-9483-76bf6f8de0a6", - "keyword": "A", - "operator": "==", - "value": 1 - }] - }, - { - "uuid": "eacf5223-2411-4529-8abe-2c0fb2daf57f", - "name": "Primaries", - "rules": [ - { - "uuid": "624050ff-9761-4688-99e3-b3ba9592ae78", - "keyword": "Z", - "operator": "==", - "value": 1 - }, - { - "uuid": "6cef8b17-9337-46e5-b522-70a9d1b26324", - "keyword": "A", - "operator": "==", - "value": 1 - }, - { - "uuid": "d9b7c82e-338f-40d9-b316-67ed0bab2eb1", - "keyword": "GEN", - "operator": "==", - "value": 0 - }] - }, - { - "uuid": "6ba215e8-359e-447d-bac9-4f2808faed51", - "name": "Secondary_protons", - "rules": [ - { - "uuid": "3d485d37-4753-4afa-85ab-ed0f9bc5ae3b", - "keyword": "Z", - "operator": "==", - "value": 1 - }, - { - "uuid": "b9b5c2a9-6625-409f-81e2-827799cef0a5", - "keyword": "A", - "operator": "==", - "value": 1 - }, - { - "uuid": "919e4280-15ad-449b-9495-1cf1ac0337bc", - "keyword": "GEN", - "operator": ">=", - "value": 1 - }] - }] - }, - "beam": { - "position": [0,0,0], - "direction": [0,0,1], - "energy": 150, - "energySpread": 1.5, - "energyLowCutoff": 0, - "energyHighCutoff": 1000, - "sigma": { - "type": "Gaussian", - "x": 0, - "y": 0 - }, - "sad": { - "type": "double", - "x": 200, - "y": 250 - }, - "divergence": { - "distanceToFocal": 0, - "x": 0, - "y": 0 - }, - "particle": { - "a": 1, - "id": 2, - "z": 1 - }, - "colorHex": 16776960, - "numberOfParticles": 10000, - "beamSourceFile": { - "name": "sobp.dat", - "value": "*ENERGY(GEV) X(CM) Y(CM) FWHM(cm) WEIGHT\n0.270550 -1.00 1.00 0.48 9.3700e+06\n0.270550 -0.90 1.00 0.48 9.3700e+06\n0.270550 -0.80 1.00 0.48 9.3700e+06\n0.270550 -0.70 1.00 0.48 9.3700e+06\n0.270550 -0.60 1.00 0.48 9.3700e+06\n0.270550 -0.50 1.00 0.48 9.3700e+06\n0.270550 -0.40 1.00 0.48 9.3700e+06\n0.270550 -0.30 1.00 0.48 9.3700e+06\n0.270550 -0.20 1.00 0.48 9.3700e+06\n0.270550 -0.10 1.00 0.48 9.3700e+06" - }, - "beamSourceType": "file" - }, - "physic": { - "energyLoss": 0.03, - "enableNuclearReactions": false, - "energyModelStraggling": "Gaussian", - "multipleScattering": "no scattering" - }, - "materialManager": { - "materials": [ - { - "uuid": "1dd2e8f0-6684-42c2-ad35-7aa55358204e", - "name": "BLACK HOLE", - "icru": 0, - "density": 1, - "color": 196613 - }, - { - "uuid": "49ce56b9-ee48-4640-88d4-bcfd660d8c0e", - "name": "WATER, LIQUID", - "icru": 276, - "density": 1, - "color": 34047, - "opacity": 0.4, - "transparent": true - }, - { - "uuid": "cd7c2eb0-e91f-4144-b4eb-536e4626cc09", - "name": "VACUUM", - "icru": 1000, - "density": 1, - "color": 16119285, - "opacity": 0.1, - "transparent": true - }], - "selectedMaterials": { - "49ce56b9-ee48-4640-88d4-bcfd660d8c0e": 1, - "cd7c2eb0-e91f-4144-b4eb-536e4626cc09": 1, - "1dd2e8f0-6684-42c2-ad35-7aa55358204e": 1 - } - }, - "scoringManager": { - "uuid": "D0F67F59-F311-4F8E-A06F-5A07D618FDE2", - "name": "Outputs", - "scoringOutputs": [ - { - "name": "z_profile", - "uuid": "d24dd7eb-6a7c-40d0-b39e-f4424b3dd937", - "quantities": { - "active": [ - { - "name": "Quantity", - "uuid": "3b0bc80c-5d78-4899-870f-23167e99fe30", - "keyword": "Dose", - "modifiers": [] - }, - { - "name": "Quantity_1", - "uuid": "e3488754-9a67-4d3c-b0ea-17300d651a8a", - "keyword": "DoseGy", - "modifiers": [] - }, - { - "name": "Quantity_2", - "uuid": "53ba1036-4975-4a96-a6bd-3d336fc72612", - "keyword": "Fluence", - "filter": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "modifiers": [] - }, - { - "name": "Quantity_3", - "uuid": "050f3919-a59b-45a4-9326-38d788c16ab7", - "keyword": "Fluence", - "filter": "eacf5223-2411-4529-8abe-2c0fb2daf57f", - "modifiers": [] - }, - { - "name": "Quantity_4", - "uuid": "b3286437-b2a1-4ee9-b7da-8cc2cc435fcd", - "keyword": "Fluence", - "filter": "6ba215e8-359e-447d-bac9-4f2808faed51", - "modifiers": [] - }] - }, - "detectGeometry": "186ec65a-8511-418b-8218-8890138c6b12", - "trace": false - }, - { - "name": "yz_profile", - "uuid": "6e69ee1b-a73c-4936-a5a2-e81f5bf8bc04", - "quantities": { - "active": [ - { - "name": "Quantity", - "uuid": "828d1276-a60e-4e31-9da7-88c84587445a", - "keyword": "Dose", - "modifiers": [] - }, - { - "name": "Quantity_1", - "uuid": "c3499475-9496-4ee5-b705-950b83867dac", - "keyword": "DoseGy", - "modifiers": [] - }, - { - "name": "Quantity_2", - "uuid": "be97ed10-07af-49d2-b91a-5bfe09c0c228", - "keyword": "Fluence", - "filter": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "modifiers": [] - }, - { - "name": "Quantity_3", - "uuid": "69305c71-de72-466c-86bc-ba5e58635a9e", - "keyword": "Fluence", - "filter": "6ba215e8-359e-447d-bac9-4f2808faed51", - "modifiers": [] - }] - }, - "detectGeometry": "3306e98b-5da2-46ee-8892-ac0191d645a7", - "trace": false - }, - { - "name": "entrance", - "uuid": "2e46a6ab-35d7-4fce-9de8-406a47fc9180", - "quantities": { - "active": [ - { - "name": "Quantity", - "uuid": "9730c840-7163-4125-8596-7d26735c373a", - "keyword": "Dose", - "modifiers": [] - }, - { - "name": "Quantity_1", - "uuid": "48b2c7a4-58c4-4ff7-816b-865ce146ae95", - "keyword": "AvgEnergy", - "filter": "eacf5223-2411-4529-8abe-2c0fb2daf57f", - "modifiers": [] - }, - { - "name": "Quantity_2", - "uuid": "a9164784-1770-48d5-a772-3342fb06efe9", - "keyword": "AvgEnergy", - "filter": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "modifiers": [] - }, - { - "name": "Quantity_3", - "uuid": "2bf3b68d-a855-443a-8ea0-2bf05eeb9e65", - "keyword": "AvgEnergy", - "filter": "6ba215e8-359e-447d-bac9-4f2808faed51", - "modifiers": [] - }, - { - "name": "Quantity_4", - "uuid": "d0c4addd-0775-420e-9240-d5ba3e279a2b", - "keyword": "dLET", - "filter": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "modifiers": [] - }, - { - "name": "Quantity_5", - "uuid": "a4e9cac1-a643-4448-bc4a-89977101cc67", - "keyword": "tLET", - "filter": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "modifiers": [] - }, - { - "name": "Quantity_6", - "uuid": "de64c12b-15cc-4e72-9262-b5507a738c9f", - "keyword": "Fluence", - "filter": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "modifiers": [ - { - "diffType": "E", - "lowerLimit": 0, - "upperLimit": 160, - "binsNumber": 640, - "isLog": false, - "uuid": "1afaf3d8-443f-4bac-8999-be914ff0691a" - }] - }] - }, - "detectGeometry": "53fff3c4-30de-4210-9066-20dc0f90cccb", - "trace": false - }, - { - "name": "peak", - "uuid": "a9e8737f-edae-45fe-9395-1e6b220ef384", - "quantities": { - "active": [ - { - "name": "Quantity", - "uuid": "d13a9fc5-d13c-4e5a-9fc4-decfe15c9ee4", - "keyword": "Dose", - "modifiers": [] - }, - { - "name": "Quantity_1", - "uuid": "54b85511-c885-41bd-a81d-a97842197764", - "keyword": "AvgEnergy", - "filter": "eacf5223-2411-4529-8abe-2c0fb2daf57f", - "modifiers": [] - }, - { - "name": "Quantity_2", - "uuid": "e7ff88d1-e46a-4a69-b676-e8e3ed1e67fd", - "keyword": "AvgEnergy", - "filter": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "modifiers": [] - }, - { - "name": "Quantity_3", - "uuid": "95c292b9-966e-42fe-91a0-3d0f0db55876", - "keyword": "AvgEnergy", - "filter": "6ba215e8-359e-447d-bac9-4f2808faed51", - "modifiers": [] - }, - { - "name": "Quantity_4", - "uuid": "efd9f82c-8e0e-4d3d-a22d-70a0cc11ef7b", - "keyword": "dLET", - "filter": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "modifiers": [] - }, - { - "name": "Quantity_5", - "uuid": "dac16bbd-e361-46d3-8eae-9c69571aea96", - "keyword": "tLET", - "filter": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "modifiers": [] - }, - { - "name": "Quantity_6", - "uuid": "65f821c8-a654-4f6f-b666-0fdc8c925cf5", - "keyword": "Fluence", - "filter": "9d0bae09-9ebe-46fe-9e59-bd7888db9442", - "modifiers": [ - { - "diffType": "E", - "lowerLimit": 0, - "upperLimit": 160, - "binsNumber": 640, - "isLog": false, - "uuid": "07a5db58-a8ea-4175-93e7-9fe74ca14d34" - }] - }] - }, - "detectGeometry": "deb6a8f8-fab3-488e-8a01-9bb3e8ea4649", - "trace": false - }] - }, - "hash": "f47bc517674ad28202dab188b7ac4e06af9e5ec7" -} diff --git a/tests/shieldhit/resources/expected_shieldhit_output/beam.dat b/tests/shieldhit/resources/expected_shieldhit_output/beam.dat new file mode 100644 index 00000000..c365ba88 --- /dev/null +++ b/tests/shieldhit/resources/expected_shieldhit_output/beam.dat @@ -0,0 +1,14 @@ + +RNDSEED 89736501 ! Random seed +JPART0 2 ! Incident particle type +TMAX0 150.0 1.5 ! Incident energy and energy spread; both in (MeV/nucl) +TCUT0 0 1000 ! energy cutoffs [MeV] +NSTAT 10000 0 ! NSTAT, Step of saving +STRAGG 2 ! Straggling: 0-Off 1-Gauss, 2-Vavilov +MSCAT 2 ! Mult. scatt 0-Off 1-Gauss, 2-Moliere +NUCRE 1 ! Nucl.Reac. switcher: 1-ON, 0-OFF +BEAMPOS 0 0 0 ! Position of the beam +BEAMDIR 0.0 0.0 ! Direction of the beam +BEAMSIGMA 0 0 ! Beam extension +! no BEAMSAD value +DELTAE 0.03 ! relative mean energy loss per transportation step diff --git a/tests/shieldhit/resources/expected_shieldhit_output/detect.dat b/tests/shieldhit/resources/expected_shieldhit_output/detect.dat new file mode 100644 index 00000000..dbaaf384 --- /dev/null +++ b/tests/shieldhit/resources/expected_shieldhit_output/detect.dat @@ -0,0 +1,75 @@ +Geometry Cyl + Name CylZ_Mesh + R 0 5 1 + Z 0 20 400 + +Geometry Mesh + Name YZ_Mesh + X -0.25 0.25 1 + Y -2 2 80 + Z 0 20 400 + +Geometry Cyl + Name EntrySlab + R 0 5 1 + Z 0 0.1 1 + +Geometry Cyl + Name PeakSlab + R 0 5 1 + Z 15.3 15.4 1 + +Filter + Name Protons + Z == 1 + A == 1 +Filter + Name Primaries + Z == 1 + A == 1 + GEN == 0 +Filter + Name Secondary_protons + Z == 1 + A == 1 + GEN >= 1 +Output + Filename z_profile.bdo + Geo CylZ_Mesh + Quantity Dose + Quantity Fluence Protons + Quantity Fluence Primaries + Quantity Fluence Secondary_protons + +Output + Filename yz_profile.bdo + Geo YZ_Mesh + Quantity Dose + Quantity Fluence Protons + Quantity Fluence Secondary_protons + +Output + Filename entrance.bdo + Geo EntrySlab + Quantity Dose + Quantity AvgEnergy Primaries + Quantity AvgEnergy Protons + Quantity AvgEnergy Secondary_protons + Quantity dLET Protons + Quantity tLET Protons + Quantity Fluence Protons + Diff1 0 160 640 + Diff1Type E + +Output + Filename peak.bdo + Geo PeakSlab + Quantity Dose + Quantity AvgEnergy Primaries + Quantity AvgEnergy Protons + Quantity AvgEnergy Secondary_protons + Quantity dLET Protons + Quantity tLET Protons + Quantity Fluence Protons + Diff1 0 160 640 + Diff1Type E diff --git a/tests/shieldhit/resources/expected_shieldhit_output/geo.dat b/tests/shieldhit/resources/expected_shieldhit_output/geo.dat new file mode 100644 index 00000000..f8d9de32 --- /dev/null +++ b/tests/shieldhit/resources/expected_shieldhit_output/geo.dat @@ -0,0 +1,15 @@ + + 0 0 Proton pencil beam in water + RCC 1 0.0 0.0 0.0 0.0 0.0 20.0 + 5.0 + RCC 2 0.0 0.0 -0.5 0.0 0.0 22.0 + 5.5 + RCC 3 0.0 0.0 -1.5 0.0 0.0 24.0 + 6.0 + END + 001 +1 + 002 +2 -1 + 003 -2 +3 -1 + END + 1 2 3 + 1 1000 0 diff --git a/tests/shieldhit/resources/expected_shieldhit_output/mat.dat b/tests/shieldhit/resources/expected_shieldhit_output/mat.dat new file mode 100644 index 00000000..2c80bf7c --- /dev/null +++ b/tests/shieldhit/resources/expected_shieldhit_output/mat.dat @@ -0,0 +1,3 @@ +MEDIUM 1 +ICRU 276 +END From 3d221ab3e0815e967f87546e3d6452e43ae7aa30 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sat, 13 May 2023 20:08:01 +0000 Subject: [PATCH 12/23] refactor: Autofix issues in 4 files Resolved issues in the following files with DeepSource Autofix: 1. tests/shieldhit/test_shieldhit_converter.py 2. tests/shieldhit/test_zones.py 3. tests/topas/conftest.py 4. tests/topas/test_topas_converter.py --- tests/shieldhit/test_shieldhit_converter.py | 3 +-- tests/shieldhit/test_zones.py | 2 +- tests/topas/conftest.py | 2 -- tests/topas/test_topas_converter.py | 2 -- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/shieldhit/test_shieldhit_converter.py b/tests/shieldhit/test_shieldhit_converter.py index a32ace8e..ddf3aafc 100644 --- a/tests/shieldhit/test_shieldhit_converter.py +++ b/tests/shieldhit/test_shieldhit_converter.py @@ -1,11 +1,10 @@ import filecmp -import json import logging from pathlib import Path import pytest -from converter.api import get_parser_from_str, run_parser +from converter.api import run_parser from converter.shieldhit.parser import Parser diff --git a/tests/shieldhit/test_zones.py b/tests/shieldhit/test_zones.py index b130e0e4..dba3b2ff 100644 --- a/tests/shieldhit/test_zones.py +++ b/tests/shieldhit/test_zones.py @@ -1,5 +1,5 @@ import pytest -from converter.shieldhit.geo import Zone, parse_figure +from converter.shieldhit.geo import Zone @pytest.fixture(scope='module') def water_phantom_zone_dict(project_shieldhit_json): diff --git a/tests/topas/conftest.py b/tests/topas/conftest.py index c1751d07..6d8d4a82 100644 --- a/tests/topas/conftest.py +++ b/tests/topas/conftest.py @@ -1,6 +1,4 @@ -from pathlib import Path import pytest -import json @pytest.fixture(scope='session') def project_topas_json(project_shieldhit_json) -> dict: diff --git a/tests/topas/test_topas_converter.py b/tests/topas/test_topas_converter.py index 9b0b1b68..9939f88a 100644 --- a/tests/topas/test_topas_converter.py +++ b/tests/topas/test_topas_converter.py @@ -1,8 +1,6 @@ import pytest -from pathlib import Path from converter.api import get_parser_from_str, run_parser from converter.common import Parser -import json _Config_str = """s:Ge/MyBox/Type = "TsBox" s:Ge/MyBox/Material = "Air" From 75b36375db960c5567d4aaf548c54ef55dc67609 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sat, 13 May 2023 22:08:18 +0200 Subject: [PATCH 13/23] readme added --- tests/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/README.md diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 00000000..b8ba63c6 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,16 @@ +# Tests layout + +## General tests + +The general tests cover aspects of the converter common to all simulators. +Currently only the Figures part of geometry is tested here. +There is also `conftests.py` which contains fixture with location and content of a reference JSON project file. +As for now this file is based on the SHIELD-HIT12A simualator, but could be used as well for Fluka and Topas tests. + +### Reference files + +The reference JSON file is located in `tests/shieldhit/resources/project.json` together with the expected output files. + +## Simulator specific tests + +The simulator specific tests cover aspects of the converter specific to a given simulator. They are located in the `shieldhit`, `fluka` and `topas` directories. From 4c842f882bb25cffea63006a7b407352377c1f46 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sat, 13 May 2023 22:14:32 +0200 Subject: [PATCH 14/23] fixes --- converter/common.py | 8 +++++--- converter/fluka/parser.py | 16 ++-------------- converter/shieldhit/parser.py | 6 +++--- converter/topas/parser.py | 5 ++--- 4 files changed, 12 insertions(+), 23 deletions(-) diff --git a/converter/common.py b/converter/common.py index 016d4c19..d33178c9 100644 --- a/converter/common.py +++ b/converter/common.py @@ -27,10 +27,12 @@ def save_configs(self, target_dir: str): with open(Path(target_dir, file_name), 'w') as conf_f: conf_f.write(content) - @staticmethod - def get_configs_json() -> dict: + def get_configs_json(self) -> dict: """ Return a dict representation of the config files. Each element has the config files name as key and its content as value. """ - return {} + configs_json = { + "info.json": str(self.info), + } + return configs_json diff --git a/converter/fluka/parser.py b/converter/fluka/parser.py index 5bf130ee..d8909175 100644 --- a/converter/fluka/parser.py +++ b/converter/fluka/parser.py @@ -1,7 +1,5 @@ -from pathlib import Path from converter.common import Parser - DEFAULT_CONFIG = """TITLE proton beam simulation * default physics settings for hadron therapy @@ -77,22 +75,12 @@ def __init__(self) -> None: def parse_configs(self, json: dict) -> None: """Basicaly do nothing since we work on defaults in this parser.""" - def save_configs(self, target_dir: Path) -> None: - """ - This will save the Fluka Configuration to a file named fl_sim.imp - in the target_dir directory. - """ - if not Path(target_dir).exists(): - raise FileNotFoundError("Target directory doest not exist.") - for file_name, content in self.get_configs_json().items(): - with open(Path(target_dir, file_name), "w") as conf_f: - conf_f.write(content) - def get_configs_json(self) -> dict: """ Return a dict representation of the config files. Each element has the config files name as key and its content as value. """ - configs_json = {"info.json": str(self.info), "fl_sim.inp": DEFAULT_CONFIG} + configs_json = super().get_configs_json() + configs_json["fl_sim.inp"] = DEFAULT_CONFIG return configs_json diff --git a/converter/shieldhit/parser.py b/converter/shieldhit/parser.py index caa320f7..3f0a727c 100644 --- a/converter/shieldhit/parser.py +++ b/converter/shieldhit/parser.py @@ -411,13 +411,13 @@ def _get_figure_index_by_uuid(self, figure_uuid: str) -> int: def get_configs_json(self) -> dict: """Get JSON data for configs""" - configs_json = { - "info.json": str(self.info), + configs_json = super().get_configs_json() + configs_json.update({ "beam.dat": str(self.beam_config), "mat.dat": self.geo_mat_config.get_mat_string(), "detect.dat": str(self.detect_config), "geo.dat": self.geo_mat_config.get_geo_string() - } + }) if self.beam_config.beam_source_type == BeamSourceType.FILE: filename_of_beam_source_file : str = 'sobp.dat' diff --git a/converter/topas/parser.py b/converter/topas/parser.py index 88a70ebe..4d9bf6df 100644 --- a/converter/topas/parser.py +++ b/converter/topas/parser.py @@ -30,8 +30,7 @@ def get_configs_json(self) -> dict: Return a dict representation of the config files. Each element has the config files name as key and its content as value. """ - configs_json = { - "topas_config.txt": str(self.config) - } + configs_json = super().get_configs_json() + configs_json["topas_config.txt"] = str(self.config) return configs_json From b32c1276d843ca83d911b7a0e2a20d9730aa9166 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sat, 13 May 2023 22:15:58 +0200 Subject: [PATCH 15/23] fixes --- converter/fluka/parser.py | 9 +++------ converter/topas/parser.py | 9 --------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/converter/fluka/parser.py b/converter/fluka/parser.py index d8909175..1296c2d2 100644 --- a/converter/fluka/parser.py +++ b/converter/fluka/parser.py @@ -65,12 +65,9 @@ class FlukaParser(Parser): """A simple placeholder that ignores the json input and prints example (default) configs.""" def __init__(self) -> None: - version = "unknown" - self.info = { - "version": version, - "label": "development", - "simulator": "fluka", - } + super().__init__() + self.info['simulator'] = 'fluka' + self.info['version'] = 'unknown' def parse_configs(self, json: dict) -> None: """Basicaly do nothing since we work on defaults in this parser.""" diff --git a/converter/topas/parser.py b/converter/topas/parser.py index 4d9bf6df..a1f9852d 100644 --- a/converter/topas/parser.py +++ b/converter/topas/parser.py @@ -16,15 +16,6 @@ def parse_configs(self, json: dict) -> None: self.config.energy = json["beam"]["energy"] self.config.num_histories = json["beam"].get("numberOfParticles", self.config.num_histories) - def save_configs(self, target_dir: str) -> None: - """Save the configs as text files in the target_dir in file topas_config.txt.""" - if not Path(target_dir).exists(): - raise ValueError("Target directory does not exist.") - - for file_name, content in self.get_configs_json().items(): - with open(Path(target_dir, file_name), 'w') as conf_f: - conf_f.write(content) - def get_configs_json(self) -> dict: """ Return a dict representation of the config files. Each element has From 66cacca46052a597d68e42b2b83b03ad6f1c89ee Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sat, 13 May 2023 22:23:22 +0200 Subject: [PATCH 16/23] fixes --- .github/workflows/test-run.yml | 10 +++++----- tests/fluka/test_fluka_converter.py | 18 +++++------------- tests/topas/test_topas_converter.py | 28 +++++++++++----------------- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/.github/workflows/test-run.yml b/.github/workflows/test-run.yml index 05643a9a..b4bc0e8a 100644 --- a/.github/workflows/test-run.yml +++ b/.github/workflows/test-run.yml @@ -28,7 +28,7 @@ jobs: pip3 install -r test_requirements.txt - name: Run main tests - run: python -m pytest tests/ + run: python -m pytest build-and-test: @@ -61,7 +61,7 @@ jobs: - name: Run main tests # when triggering tests with `python -m pytest` (instead of simply calling `pytest`) we add current directory to sys.path - run: python -m pytest tests/ + run: python -m pytest make-package: runs-on: ubuntu-latest @@ -87,7 +87,7 @@ jobs: name: packages path: | ./dist - ./input_examples + ./tests/shieldhit/resources test-package: runs-on: ubuntu-latest @@ -117,6 +117,6 @@ jobs: - name: Test package run: | yaptide-converter -h - yaptide-converter ./input_examples/sh_parser_test.json + yaptide-converter ./tests/shieldhit/resources/project.json python3 -m converter.main -h - python3 -m converter.main ./input_examples/sh_parser_test.json + python3 -m converter.main ./tests/shieldhit/resources/project.json diff --git a/tests/fluka/test_fluka_converter.py b/tests/fluka/test_fluka_converter.py index 8df56c33..0965a1b3 100644 --- a/tests/fluka/test_fluka_converter.py +++ b/tests/fluka/test_fluka_converter.py @@ -1,6 +1,5 @@ import pytest -from os import path -from converter.fluka.parser import FlukaParser +from converter.common import Parser from converter.api import get_parser_from_str, run_parser _Config_content = """TITLE @@ -63,26 +62,19 @@ STOP """ -_Test_dir = "./test_runs" - @pytest.fixture -def parser() -> FlukaParser: +def parser() -> Parser: """Parser fixture.""" return get_parser_from_str("fluka") -@pytest.fixture -def output_dir(tmp_path_factory) -> str: - """Fixture that creates a temporary dir for testing converter output.""" - output_dir = tmp_path_factory.mktemp(_Test_dir) - return output_dir def test_parser(parser) -> None: """Check if parser is created correctly.""" assert parser.info["version"] == "unknown" assert parser.info["simulator"] == "fluka" -def test_if_inp_created(parser, output_dir) -> None: +def test_if_inp_created(parser, tmp_path) -> None: """Check if fl_sim.inp file created.""" - run_parser(parser, {}, output_dir) - with open(path.join(output_dir, "fl_sim.inp")) as f: + run_parser(parser, {}, tmp_path) + with open(tmp_path / "fl_sim.inp") as f: assert f.read() == _Config_content diff --git a/tests/topas/test_topas_converter.py b/tests/topas/test_topas_converter.py index 9939f88a..ca27bb11 100644 --- a/tests/topas/test_topas_converter.py +++ b/tests/topas/test_topas_converter.py @@ -1,3 +1,4 @@ +from pathlib import Path import pytest from converter.api import get_parser_from_str, run_parser from converter.common import Parser @@ -64,31 +65,24 @@ sv:Ph/Default/Modules = 1 "g4em-standard_opt0" """ -_Test_dir = './test_runs' -@pytest.fixture -def parser() -> Parser: +@pytest.fixture(scope='session') +def topas_parser() -> Parser: """Just a parser fixture.""" return get_parser_from_str('topas') -@pytest.fixture -def output_dir(tmp_path_factory, parser, project_topas_json) -> str: - """Fixture that creates a temporary dir for testing converter output and runs the conversion there.""" - output_dir = tmp_path_factory.mktemp(_Test_dir) - run_parser(parser, project_topas_json, output_dir) - return output_dir - -def test_if_parser_created(parser) -> None: +def test_if_parser_created(topas_parser: Parser) -> None: """Check if parser created.""" - assert parser is not None - assert parser.info['simulator'] == 'topas' - assert parser.info['version'] == '' - assert parser.info['label'] == '' + assert topas_parser is not None + assert topas_parser.info['simulator'] == 'topas' + assert topas_parser.info['version'] == '' + assert topas_parser.info['label'] == '' -def test_if_config_created(output_dir) -> None: +def test_if_config_created(topas_parser: Parser, project_topas_json: dict, tmp_path: Path) -> None: """Check if topas_config.txt file created""" - output_file = output_dir.joinpath('topas_config.txt') + output_file = tmp_path / 'topas_config.txt' + run_parser(topas_parser, project_topas_json, tmp_path) with output_file.open(mode='r') as f: assert f.read() == _Config_str \ No newline at end of file From b9baf13cb907bac32dc651f2b1fc9290c3bdfa7a Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sat, 13 May 2023 20:25:49 +0000 Subject: [PATCH 17/23] refactor: Autofix issues in 1 file Resolved issues in converter/topas/parser.py with DeepSource Autofix --- converter/topas/parser.py | 1 - 1 file changed, 1 deletion(-) diff --git a/converter/topas/parser.py b/converter/topas/parser.py index a1f9852d..fd826d14 100644 --- a/converter/topas/parser.py +++ b/converter/topas/parser.py @@ -1,6 +1,5 @@ from converter.common import Parser from converter.topas.config import Config -from pathlib import Path class TopasParser(Parser): From 85605e815426d728d1b47772d7858d65bb6ca9c4 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sat, 13 May 2023 22:27:10 +0200 Subject: [PATCH 18/23] deepsource --- tests/shieldhit/test_zones.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/shieldhit/test_zones.py b/tests/shieldhit/test_zones.py index dba3b2ff..db68901e 100644 --- a/tests/shieldhit/test_zones.py +++ b/tests/shieldhit/test_zones.py @@ -7,6 +7,7 @@ def water_phantom_zone_dict(project_shieldhit_json): return project_shieldhit_json['zoneManager']['zones'][0] def test_water_phantom_zone(water_phantom_zone_dict): + """Test if the water phantom zone is parsed correctly""" assert water_phantom_zone_dict['name'] == 'Water_phantom_zone' zone_obj = Zone(water_phantom_zone_dict) assert zone_obj.id == 1 From 6281d8bf446912bc2f04d42962351210debf3d57 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sun, 14 May 2023 12:52:22 +0200 Subject: [PATCH 19/23] Apply suggestions from code review Co-authored-by: Dominik Hendzel <128628266+hendzeld@users.noreply.github.com> --- tests/fluka/test_fluka_converter.py | 1 + tests/shieldhit/test_shieldhit_converter.py | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/fluka/test_fluka_converter.py b/tests/fluka/test_fluka_converter.py index 0965a1b3..0baac38c 100644 --- a/tests/fluka/test_fluka_converter.py +++ b/tests/fluka/test_fluka_converter.py @@ -72,6 +72,7 @@ def test_parser(parser) -> None: """Check if parser is created correctly.""" assert parser.info["version"] == "unknown" assert parser.info["simulator"] == "fluka" + assert parser.info["label"] == "" def test_if_inp_created(parser, tmp_path) -> None: """Check if fl_sim.inp file created.""" diff --git a/tests/shieldhit/test_shieldhit_converter.py b/tests/shieldhit/test_shieldhit_converter.py index ddf3aafc..64bb4c6f 100644 --- a/tests/shieldhit/test_shieldhit_converter.py +++ b/tests/shieldhit/test_shieldhit_converter.py @@ -13,6 +13,7 @@ def test_parser(sh12a_parser : Parser) -> None: assert sh12a_parser assert sh12a_parser.info['version'] == '' assert sh12a_parser.info['simulator'] == 'shieldhit' + assert sh12a_parser.info['label'] == '' def test_project_json(project_shieldhit_json: dict) -> None: """Check if project json is created correctly""" From 95dd78b68f92228aec0d1e3db267223c55800a4b Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sun, 14 May 2023 12:53:25 +0200 Subject: [PATCH 20/23] review --- tests/fluka/test_fluka_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fluka/test_fluka_converter.py b/tests/fluka/test_fluka_converter.py index 0baac38c..608060ae 100644 --- a/tests/fluka/test_fluka_converter.py +++ b/tests/fluka/test_fluka_converter.py @@ -2,7 +2,7 @@ from converter.common import Parser from converter.api import get_parser_from_str, run_parser -_Config_content = """TITLE +_excpected_fluka_input_content = """TITLE proton beam simulation * default physics settings for hadron therapy DEFAULTS HADROTHE @@ -78,4 +78,4 @@ def test_if_inp_created(parser, tmp_path) -> None: """Check if fl_sim.inp file created.""" run_parser(parser, {}, tmp_path) with open(tmp_path / "fl_sim.inp") as f: - assert f.read() == _Config_content + assert f.read() == _excpected_fluka_input_content From c52d13672ccd95d1a64e8468dbf7c8c9a8e9d5fa Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sun, 14 May 2023 12:54:19 +0200 Subject: [PATCH 21/23] review --- tests/topas/test_topas_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/topas/test_topas_converter.py b/tests/topas/test_topas_converter.py index ca27bb11..5f81534e 100644 --- a/tests/topas/test_topas_converter.py +++ b/tests/topas/test_topas_converter.py @@ -3,7 +3,7 @@ from converter.api import get_parser_from_str, run_parser from converter.common import Parser -_Config_str = """s:Ge/MyBox/Type = "TsBox" +_excpected_topas_input_content = """s:Ge/MyBox/Type = "TsBox" s:Ge/MyBox/Material = "Air" s:Ge/MyBox/Parent = "World" d:Ge/MyBox/HLX = 2.5 m @@ -85,4 +85,4 @@ def test_if_config_created(topas_parser: Parser, project_topas_json: dict, tmp_p output_file = tmp_path / 'topas_config.txt' run_parser(topas_parser, project_topas_json, tmp_path) with output_file.open(mode='r') as f: - assert f.read() == _Config_str \ No newline at end of file + assert f.read() == _excpected_topas_input_content \ No newline at end of file From f6ac0b99271b153247e9079fe946015f2cd8ee93 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sun, 14 May 2023 14:45:43 +0200 Subject: [PATCH 22/23] Apply suggestions from code review Co-authored-by: Mateusz Wronka <92746092+Bogdan2423@users.noreply.github.com> --- tests/topas/test_topas_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/topas/test_topas_converter.py b/tests/topas/test_topas_converter.py index 5f81534e..7280452f 100644 --- a/tests/topas/test_topas_converter.py +++ b/tests/topas/test_topas_converter.py @@ -3,7 +3,7 @@ from converter.api import get_parser_from_str, run_parser from converter.common import Parser -_excpected_topas_input_content = """s:Ge/MyBox/Type = "TsBox" +_expected_topas_input_content = """s:Ge/MyBox/Type = "TsBox" s:Ge/MyBox/Material = "Air" s:Ge/MyBox/Parent = "World" d:Ge/MyBox/HLX = 2.5 m @@ -85,4 +85,4 @@ def test_if_config_created(topas_parser: Parser, project_topas_json: dict, tmp_p output_file = tmp_path / 'topas_config.txt' run_parser(topas_parser, project_topas_json, tmp_path) with output_file.open(mode='r') as f: - assert f.read() == _excpected_topas_input_content \ No newline at end of file + assert f.read() == _expected_topas_input_content \ No newline at end of file From 2b6040deab75d5c7b2884e03b39d63817db76771 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Sun, 14 May 2023 14:46:28 +0200 Subject: [PATCH 23/23] Apply suggestions from code review Co-authored-by: Mateusz Wronka <92746092+Bogdan2423@users.noreply.github.com> --- tests/fluka/test_fluka_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fluka/test_fluka_converter.py b/tests/fluka/test_fluka_converter.py index 608060ae..37994c5a 100644 --- a/tests/fluka/test_fluka_converter.py +++ b/tests/fluka/test_fluka_converter.py @@ -2,7 +2,7 @@ from converter.common import Parser from converter.api import get_parser_from_str, run_parser -_excpected_fluka_input_content = """TITLE +_expected_fluka_input_content = """TITLE proton beam simulation * default physics settings for hadron therapy DEFAULTS HADROTHE @@ -78,4 +78,4 @@ def test_if_inp_created(parser, tmp_path) -> None: """Check if fl_sim.inp file created.""" run_parser(parser, {}, tmp_path) with open(tmp_path / "fl_sim.inp") as f: - assert f.read() == _excpected_fluka_input_content + assert f.read() == _expected_fluka_input_content