Skip to content

Commit

Permalink
Merge pull request #83 from PaNOSC-ViNYL/include_meta
Browse files Browse the repository at this point in the history
Write component parameters
  • Loading branch information
mads-bertelsen authored Aug 9, 2024
2 parents 2fa3cc5 + 6ec43bc commit 6bbe6fa
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 7 deletions.
2 changes: 1 addition & 1 deletion mcstasscript/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.0.68"
__version__ = "0.0.70"
60 changes: 60 additions & 0 deletions mcstasscript/data/data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import matplotlib.pyplot
import numpy as np
import copy
import re


class McStasMetaData:
Expand Down Expand Up @@ -967,3 +968,62 @@ def __str__(self):

def __repr__(self):
return "\n" + self.__str__()

def parse_coordinates(line, keyword):
# Extract the coordinates from the line
match = re.search(r'\(([^)]+)\)', line)
if match:
coords = match.group(1).split(',')
coords = [float(coord.strip()) for coord in coords]
return {f'{keyword}_x': coords[0], f'{keyword}_y': coords[1], f'{keyword}_z': coords[2]}
return {}

class ComponentData:
def __init__(self, file_path):
self.file_path = file_path
self.data = None

def read(self):

components = {}

current_component = None

with open(self.file_path, 'r') as file:
for line in file:
line = line.strip()
if line.startswith('COMPONENT'):
match = re.match(r'COMPONENT (\S+) = (\S+)', line)
if match:
component_name = match.group(1)
component_type = match.group(2)
current_component = {'component': component_type}
components[component_name] = current_component
current_component["parameters"] = {}
elif '=' in line:
if current_component is not None:
key, value = line.split('=',1)
try:
value = float(value)
except:
pass
current_component["parameters"][key] = value
elif line.startswith('AT'):
if current_component is not None:
current_component.update(parse_coordinates(line, 'AT'))
if line.endswith('ABSOLUTE'):
current_component['AT_relative'] = "ABSOLUTE"
else:
current_component['AT_relative'] = line.split('RELATIVE')[1].strip()
elif line.startswith('ROTATED'):
if current_component is not None:
current_component.update(parse_coordinates(line, 'ROTATED'))
if line.endswith('ABSOLUTE'):
current_component['ROTATED_relative'] = "ABSOLUTE"
else:
current_component['ROTATED_relative'] = line.split('RELATIVE')[1].strip()

self.data = components

return components

71 changes: 69 additions & 2 deletions mcstasscript/helper/mcstas_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ def __init__(self, instance_name, component_name, AT=None,
AT_RELATIVE=None, ROTATED=None, ROTATED_RELATIVE=None,
RELATIVE=None, WHEN=None, EXTEND=None, GROUP=None,
JUMP=None, SPLIT=None, comment=None, c_code_before=None,
c_code_after=None):
c_code_after=None, save_parameters=False):
"""
Initializes McStas component with specified name and component
Expand Down Expand Up @@ -564,6 +564,7 @@ def __init__(self, instance_name, component_name, AT=None,
self.c_code_before = ""
self.c_code_after = ""
self.search_statement_list = SearchStatementList()
self.save_parameters = save_parameters

# references to component names
self.AT_reference = None
Expand All @@ -589,7 +590,8 @@ def __init__(self, instance_name, component_name, AT=None,
def set_keyword_input(self, AT=None, AT_RELATIVE=None, ROTATED=None,
ROTATED_RELATIVE=None, RELATIVE=None, WHEN=None,
EXTEND=None, GROUP=None, JUMP=None, SPLIT=None,
comment=None, c_code_before=None, c_code_after=None):
comment=None, c_code_before=None, c_code_after=None,
save_parameters=None):
# Allow addition of attributes in init
self._unfreeze()

Expand Down Expand Up @@ -966,6 +968,12 @@ def set_c_code_after(self, string):
+ "given " + str(type(string)))
self.c_code_after = string

def set_save_parameters(self, value):
if value:
self.save_parameters = True
else:
self.save_parameters = False

def add_search(self, statement, SHELL=False):
"""
Adds a search statement to the component
Expand Down Expand Up @@ -1010,6 +1018,8 @@ def write_component(self, fo):
# Could use character limit on lines instead
parameters_written = 0 # internal parameter

save_parameter_string = ""

if len(self.c_code_before) > 0:
explanation = "From component named " + self.name
fo.write("%s // %s\n" % (str(self.c_code_before), explanation))
Expand Down Expand Up @@ -1078,10 +1088,14 @@ def write_component(self, fo):

fo.write(" %s\n" % self.AT_relative)

if self.save_parameters:
save_parameter_string += " %s\n" % self.AT_relative

if self.ROTATED_specified:
fo.write("ROTATED (%s,%s,%s)" % (str(self.ROTATED_data[0]),
str(self.ROTATED_data[1]),
str(self.ROTATED_data[2])))

fo.write(" %s\n" % self.ROTATED_relative)

if not self.GROUP == "":
Expand All @@ -1104,6 +1118,59 @@ def write_component(self, fo):
# Leave a new line between components for readability
fo.write("\n")

def make_write_string(self):
string = ""

string += f'fprintf(file, "COMPONENT {self.name} = {self.component_name}\\n");\n'

component_parameters = {}
for key in self.parameter_names:
val = getattr(self, key)
if val is None:
if self.parameter_defaults[key] is None:
raise NameError("Required parameter named "
+ key
+ " in component named "
+ self.name
+ " not set.")
else:
continue
elif isinstance(val, (Parameter, DeclareVariable)):
# Extract the parameter name
val = val.name

component_parameters[key] = val

for key, val in component_parameters.items():
par_type = self.parameter_types[key] # from component reader

cast = ""
if par_type == "" or par_type == "double":
type_string = "%lf"
cast = "(double)"
elif par_type == "int":
type_string = "%d"
cast = "(int)"
elif par_type == "string":
type_string = "%s"
else:
raise ValueError("Unknown parameter type: " + par_type)

string += f'fprintf(file, "{key}={type_string}\\n", {cast} {val});\n'

string += f'fprintf(file, "AT (%lf,%lf,%lf) {self.AT_relative}\\n",'
string += "(double) " + str(self.AT_data[0]) + ","
string += "(double) " + str(self.AT_data[1]) + ","
string += "(double) " + str(self.AT_data[2]) + ");\n"

if self.ROTATED_specified:
string += f'fprintf(file, "ROTATED (%lf,%lf,%lf) {self.ROTATED_relative}\\n",'
string += "(double) " + str(self.ROTATED_data[0]) + ","
string += "(double) " + str(self.ROTATED_data[1]) + ","
string += "(double) " + str(self.ROTATED_data[2]) + ");\n"

return string

def __str__(self):
"""
Returns string of information about the component
Expand Down
41 changes: 38 additions & 3 deletions mcstasscript/interface/instr.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ def __init__(self, name, parameters=None, author=None,
increment_folder_name=None, custom_flags=None,
executable_path=None, executable=None,
suppress_output=None, gravity=None, input_path=None,
package_path=None, checks=None, NeXus=None, openacc=None):
package_path=None, checks=None, NeXus=None,
save_comp_pars=None, openacc=None):
"""
Initialization of McStas Instrument
Expand Down Expand Up @@ -296,6 +297,9 @@ def __init__(self, name, parameters=None, author=None,
gravity : bool
If True, gravity will be simulated
save_comp_pars : bool
If True, McStas run writes all comp pars to disk
"""

super().__init__(name, input=[],
Expand Down Expand Up @@ -406,6 +410,11 @@ def __init__(self, name, parameters=None, author=None,
if NeXus is not None:
provided_run_settings["NeXus"] = NeXus

if save_comp_pars is not None:
provided_run_settings["save_comp_pars"] = save_comp_pars
else:
provided_run_settings["save_comp_pars"] = False

if openacc is not None:
provided_run_settings["openacc"] = openacc

Expand Down Expand Up @@ -467,7 +476,7 @@ def init_parameters(self):

def _read_calibration(self):
"""
Place holder method that should be overwritten by classes
Placeholder method that should be overwritten by classes
that inherit from McCode_instr.
"""
pass
Expand Down Expand Up @@ -2118,6 +2127,22 @@ def write_full_instrument(self):
fo.write("%include "generated_includes/"
+ self.name + "_initialize.c")
"""

save_parameter_code = ""
for component in self.make_component_subset():
if component.save_parameters or self._run_settings["save_comp_pars"]:
save_parameter_code += component.make_write_string()

if save_parameter_code != "":
fo.write('MPI_MASTER(\n')
fo.write('FILE *file = fopen("component_parameters.txt", "w");\n')
fo.write('if (file) {\n')
fo.write(save_parameter_code)
fo.write('} else {\n')
fo.write(' perror("fopen");\n')
fo.write('}\n')
fo.write(')\n')

fo.write("%}\n\n")

# Write trace
Expand Down Expand Up @@ -2288,7 +2313,7 @@ def settings(self, ncount=None, mpi="not_set", seed=None,
increment_folder_name=None, custom_flags=None,
executable=None, executable_path=None,
suppress_output=None, gravity=None, checks=None,
openacc=None, NeXus=None):
openacc=None, NeXus=None, save_comp_pars=False):
"""
Sets settings for McStas run performed with backengine
Expand Down Expand Up @@ -2325,6 +2350,8 @@ def settings(self, ncount=None, mpi="not_set", seed=None,
If True, adds --openacc to mcrun call
NeXus : bool
If True, adds --format=NeXus to mcrun call
save_comp_pars : bool
If True, McStas run writes all comp pars to disk
"""

settings = {}
Expand Down Expand Up @@ -2386,6 +2413,9 @@ def settings(self, ncount=None, mpi="not_set", seed=None,
if NeXus is not None:
settings["NeXus"] = bool(NeXus)

if save_comp_pars is not None:
settings["save_comp_pars"] = bool(save_comp_pars)

self._run_settings.update(settings)

def settings_string(self):
Expand Down Expand Up @@ -2460,6 +2490,11 @@ def settings_string(self):
description += " openacc:".ljust(variable_space)
description += str(value) + "\n"

if "save_comp_pars" in self._run_settings:
value = self._run_settings["save_comp_pars"]
description += " save_comp_pars:".ljust(variable_space)
description += str(value) + "\n"

return description.strip()

def show_settings(self):
Expand Down
3 changes: 2 additions & 1 deletion mcstasscript/tests/test_Instr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2123,7 +2123,8 @@ def test_run_backengine_complex_settings(self, mock_sub, mock_stdout):
executable_path=executable_path,
mpi=5, ncount=19373, openacc=True,
NeXus=True, force_compile=False,
seed=300, gravity=True, checks=False)
seed=300, gravity=True, checks=False,
save_comp_pars=True)
instr.backengine()

expected_path = os.path.join(executable_path, "mcrun")
Expand Down

0 comments on commit 6bbe6fa

Please sign in to comment.