From 874bc2134be37e611efc6b3f508e479671f24903 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Thu, 20 Jul 2023 18:13:22 +0900 Subject: [PATCH 01/67] add lib_make_convolution.py and sim_trhepd_rheed_mb_connect.py --- src/py2dmat/solver/lib_make_convolution.py | 91 ++ .../solver/sim_trhepd_rheed_mb_connect.py | 1123 +++++++++++++++++ 2 files changed, 1214 insertions(+) create mode 100644 src/py2dmat/solver/lib_make_convolution.py create mode 100644 src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py diff --git a/src/py2dmat/solver/lib_make_convolution.py b/src/py2dmat/solver/lib_make_convolution.py new file mode 100644 index 00000000..438dc4eb --- /dev/null +++ b/src/py2dmat/solver/lib_make_convolution.py @@ -0,0 +1,91 @@ +import numpy as np +import sys + +def calc(Clines, omega, verbose_mode): + if verbose_mode: + print('arg:filename=',args.filename) + print('omega =',args.omega) + + sigma = 0.5 * omega / (np.sqrt(2.0*np.log(2.0))) + + #def g(x): + # g = (0.939437 / omega) * np.exp(-2.77259 * (x ** 2.0 / omega ** 2.0)) + # return g + def g(x): + g = (1.0 / (sigma*np.sqrt(2.0*np.pi))) * np.exp(-0.5 * x ** 2.0 / sigma ** 2.0) + return g + + number_of_lines = int(len(Clines)) + number_of_header_lines = 4 + if verbose_mode: + print("number_of_lines =", number_of_lines) + print("number_of_header_lines =", number_of_header_lines) + + #degree_list = [] + #C_list = [] + + # Read the file header + line = Clines[0] + #print("file header :", line) + line = Clines[1] + #print("file header :", line) + #sys.exit() + line = line.replace(",", "") + data = line.split() + #print(data) + number_of_azimuth_angles = int(data[0]) + number_of_glancing_angles = int(data[1]) + number_of_beams = int(data[2]) + + if verbose_mode: + print("number of azimuth angles = ", number_of_azimuth_angles) + print("number of glancing angles = ", number_of_glancing_angles) + print("number of beams = ", number_of_beams) + + # Define the array for the rocking curve data. + # Note the components with (beam-index)=0 are the degree data + RC_data_org = np.zeros((number_of_glancing_angles, number_of_beams+1)) + RC_data_cnv = np.zeros((number_of_glancing_angles, number_of_beams+1)) + + # Read the file header + line = Clines[2] + #print("file header :", line, end="") + line = Clines[3] + #print("file header :", line, end="") + line = line.replace(",", "") + data = line.split() + #print(data) + + if verbose_mode: + print("beam index (p,q): i p_i q_i") + for beam_index in range(number_of_beams): + print(beam_index, data[beam_index*2], data[beam_index*2+1]) + + for g_angle_index in range(number_of_glancing_angles): + line_index = number_of_header_lines + g_angle_index + line = Clines[ line_index ] + # print("data line: ", line_index, g_angle_index, line) + line = line.replace(",", "") + data = line.split() + # print(data) + RC_data_org[g_angle_index,0]=float(data[0]) + RC_data_cnv[g_angle_index,0]=float(data[0]) + for beam_index in range(number_of_beams): + RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] + + angle_interval = RC_data_org[1,0] - RC_data_org[0,0] + + if verbose_mode: + print('angle_ interval=', angle_interval) + + for beam_index in range(number_of_beams): + for index in range(number_of_glancing_angles): + integral = 0.0 + for index2 in range(number_of_glancing_angles): + integral += RC_data_org[index2,beam_index+1] * g(RC_data_org[index,0] - RC_data_org[index2,0]) * angle_interval + RC_data_cnv[index, beam_index+1]=integral + + #np.savetxt("convolution.txt", RC_data_cnv, fmt="%.5e") + return RC_data_cnv + +#np.savetxt("original.txt", RC_data_org, fmt="%.5e") diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py new file mode 100644 index 00000000..24c8a8be --- /dev/null +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -0,0 +1,1123 @@ +from typing import List +import itertools +import os +import os.path +import shutil +from pathlib import Path +import subprocess +import time +from . import lib_make_convolution + +import numpy as np + +import py2dmat +from py2dmat import exception, mpi + +import ctypes + +from typing import TYPE_CHECKING + +import sys +import copy + +class Solver(py2dmat.solver.SolverBase): + path_to_solver: Path + + def __init__(self, info: py2dmat.Info): + super().__init__(info) + self.mpicomm = mpi.comm() + self.mpisize = mpi.size() + self.mpirank = mpi.rank() + + self._name = "sim_trhepd_rheed_mb_connect" + + self.run_scheme = info.solver.get("run_scheme",None) + scheme_list = ["subprocess","connect_so"] + scheme_judge = [i == self.run_scheme for i in scheme_list] + + if not any(scheme_judge): + raise exception.InputError( + "ERROR : Input scheme is incorrect." + ) + + if self.run_scheme == "connect_so": + self.load_so() + + elif self.run_scheme == "subprocess": + #path to surf.exe + p2solver = info.solver["config"].get("surface_exec_file", "surf.exe") + if os.path.dirname(p2solver) != "": + # ignore ENV[PATH] + self.path_to_solver = self.root_dir / Path(p2solver).expanduser() + else: + for P in itertools.chain([self.root_dir], os.environ["PATH"].split(":")): + self.path_to_solver = Path(P) / p2solver + if os.access(self.path_to_solver, mode=os.X_OK): + break + if not os.access(self.path_to_solver, mode=os.X_OK): + raise exception.InputError(f"ERROR: solver ({p2solver}) is not found") + self.input = Solver.Input(info) + self.output = Solver.Output(info) + + self.input.run_scheme = self.run_scheme + self.output.run_scheme = self.run_scheme + + if self.run_scheme == "connect_so": + self.load_so() + + elif self.run_scheme == "subprocess": + #path to surf.exe + p2solver = info.solver["config"].get("surface_exec_file", "surf.exe") + if os.path.dirname(p2solver) != "": + # ignore ENV[PATH] + self.path_to_solver = self.root_dir / Path(p2solver).expanduser() + else: + for P in itertools.chain([self.root_dir], os.environ["PATH"].split(":")): + self.path_to_solver = Path(P) / p2solver + if os.access(self.path_to_solver, mode=os.X_OK): + break + if not os.access(self.path_to_solver, mode=os.X_OK): + raise exception.InputError(f"ERROR: solver ({p2solver}) is not found") + + self.generate_rocking_curve = info.solver.get("generate_rocking_curve", False) + #print(f" info.solver = {info.solver}") + self.input.generate_rocking_curve = self.generate_rocking_curve + self.output.generate_rocking_curve = self.generate_rocking_curve + + #add + if True: + self.detail_timer = {} + self.detail_timer["prepare_Log-directory"] = 0 + self.detail_timer["make_surf_input"] = 0 + self.detail_timer["launch_STR"] = 0 + self.detail_timer["load_STR_result"] = 0 + self.detail_timer["convolution"] = 0 + self.detail_timer["calculate_R-factor"] = 0 + self.detail_timer["make_RockingCurve.txt"] = 0 + self.detail_timer["delete_Log-directory"] = 0 + self.input.detail_timer = self.detail_timer + self.output.detail_timer = self.detail_timer + + def default_run_scheme(self): + """ + Return + ------- + str + run_scheme. + """ + return self.run_scheme + + def command(self) -> List[str]: + """Command to invoke solver""" + return [str(self.path_to_solver)] + + def prepare(self, message: py2dmat.Message) -> None: + fitted_x_list, subdir = self.input.prepare(message) + self.work_dir = self.proc_dir / Path(subdir) + + self.output.prepare(fitted_x_list) + + def get_results(self) -> float: + return self.output.get_results(self.work_dir) + + def load_so(self): + self.lib = np.ctypeslib.load_library("surf.so",os.path.dirname(__file__) ) + self.lib.surf_so.argtypes = ( + ctypes.POINTER(ctypes.c_int), + ctypes.POINTER(ctypes.c_int), + np.ctypeslib.ndpointer(), + ctypes.POINTER(ctypes.c_int), + ctypes.POINTER(ctypes.c_int), + np.ctypeslib.ndpointer(), + np.ctypeslib.ndpointer() + ) + self.lib.surf_so.restype = ctypes.c_void_p + + def launch_so(self): + + #debug + #print(os.getcwd()) + ###### debug ############ + ''' + #make surf.txt + for line in self.input.template_file: + #f = open('surf.txt','w') + l = line.decode().rstrip() + print(l) + #f.write(l) + #f.write('\n') + + #f.close() + #sys.exit() + ''' + ######################### + + #fn = ctypes.byref(ctypes.c_int(n)) + #fm = ctypes.byref(ctypes.c_int(m)) + #print(self.input.template_file) + #sys.exit() + n_template_file = len(self.input.template_file) + m_template_file = self.input.surf_tempalte_width_for_fortran + n_bulk_file = len(self.input.bulk_file) + m_bulk_file = self.input.bulk_out_width_for_fortran + + emp_str = ' '*20480 + self.output.surf_output = np.array([emp_str.encode()]) + #for i in range(n_bulk_file): + # print(len(self.input.bulk_file[i])) + + #import sys + #sys.exit() + #print(self.input.template_file) + #print(self.input.bulk_file) + #print('launch so') + self.lib.surf_so( + ctypes.byref(ctypes.c_int(n_template_file)), + ctypes.byref(ctypes.c_int(m_template_file)), + self.input.template_file, + ctypes.byref(ctypes.c_int(n_bulk_file)), + ctypes.byref(ctypes.c_int(m_bulk_file)), + self.input.bulk_file, + self.output.surf_output + ) + #print('finish so') + self.output.surf_output = self.output.surf_output[0].decode().splitlines() + ''' + print('----------in python----------') + f = open('surf-bulkP.s','w') + for i in range(len(self.output.surf_output)): + f.write(self.output.surf_output[i]i.rstrip()) + f.write('\n') + + f.close() + import sys + sys.exit() + ''' + + class Input(object): + root_dir: Path + output_dir: Path + dimension: int + string_list: List[str] + bulk_output_file: Path + surface_input_file: Path + surface_template_file: Path + + def __init__(self, info): + self.mpicomm = mpi.comm() + self.mpisize = mpi.size() + self.mpirank = mpi.rank() + + self.root_dir = info.base["root_dir"] + self.output_dir = info.base["output_dir"] + + if "dimension" in info.solver: + self.dimension = info.solver["dimension"] + else: + self.dimension = info.base["dimension"] + + info_s = info.solver + self.run_scheme = info_s["run_scheme"] + # + self.surf_tempalte_width_for_fortran = 128 + self.bulk_out_width_for_fortran = 1024 + # + + info_param = info_s.get("param", {}) + v = info_param.setdefault("string_list", ["value_01", "value_02"]) + if len(v) != self.dimension: + raise exception.InputError( + f"ERROR: len(string_list) != dimension ({len(v)} != {self.dimension})" + ) + self.string_list = v + + info_config = info_s.get("config", {}) + self.surface_input_file = Path( + info_config.get("surface_input_file", "surf.txt") + ) + + filename = info_config.get("surface_template_file", "template.txt") + filename = Path(filename).expanduser().resolve() + self.surface_template_file = self.root_dir / filename + if not self.surface_template_file.exists(): + raise exception.InputError( + f"ERROR: surface_template_file ({self.surface_template_file}) does not exist" + ) + + self._check_template() + + #if False: + if True: + if self.mpirank == 0: + temp_origin = self.load_surface_template_file(filename) + else: + temp_origin = None + self.template_file_origin = self.mpicomm.bcast(temp_origin,root=0) + #if self.mpirank == 0: + # print(temp_origin,"\n") + # print(self.template_file_origin) + # print(len(temp_origin)==len(self.template_file_origin)) + # print("for i in range(len(temp_origin))") + # for i in range(len(temp_origin)): + # print(temp_origin[i]==self.template_file_origin[i]) + # print("end") + # print(temp_origin==self.template_file_origin) + else : + self.template_file_origin = self.load_surface_template_file(filename) + + if self.run_scheme == "connect_so": + filename = info_config.get("bulk_output_file", "bulkP.txt") + filename = Path(filename).expanduser().resolve() + self.bulk_output_file = self.root_dir / filename + if not self.bulk_output_file.exists(): + raise exception.InputError( + f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" + ) + + #if False: + if True: + if self.mpirank == 0: + bulk_f = self.load_bulk_output_file(filename) + #print(bulk_f) + #print(bulk_f.dtype) + #print(bulk_f.shape) + else: + bulk_f = None + self.bulk_file = self.mpicomm.bcast(bulk_f,root=0) + #print(self.bulk_file) + #print(self.bulk_file.dtype) + #print(self.bulk_file.shape) + #if self.mpirank == 0: + # print(len(bulk_f)==len(self.bulk_file)) + # print("for i in range(len(bulk_f))") + # for i in range(len(bulk_f)): + # print(bulk_f[i]==self.bulk_file[i]) + # print("end") + # print(bulk_f==self.bulk_file) + else: + self.bulk_file = self.load_bulk_output_file(filename) + + else: + filename = info_config.get("bulk_output_file", "bulkP.b") + filename = Path(filename).expanduser().resolve() + self.bulk_output_file = self.root_dir / filename + if not self.bulk_output_file.exists(): + raise exception.InputError( + f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" + ) + + def load_surface_template_file(self, filename): + template_file = [] + with open(self.surface_template_file) as f: + for line in f: + template_file.append(line) + #print(f'load {filename}') + return template_file + + def load_bulk_output_file(self, filename) : + bulk_file = [] + #a = [] + with open(self.bulk_output_file) as f: + for line in f: + line = line.replace("\t", " ").replace("\n", " ") + line = line.encode().ljust(self.bulk_out_width_for_fortran) + #a.append(len(line)) + bulk_file.append(line) + bulk_f = np.array(bulk_file) + #self.bulk_file = np.array(bulk_file) + #print(f'load {filename}') + return bulk_f + + def prepare(self, message: py2dmat.Message): + if self.detail_timer is not None : time_sta = time.perf_counter() + # + x_list = message.x + step = message.step + #extra = False + extra = message.set > 0 + + #### ADHOC_MPPING! ###" + adhoc_mapping = False + if adhoc_mapping: + if self.mpirank==0 and step==1: + print(f"NOTICE: adhoc_mapping is {adhoc_mapping}") + A_array = np.array( + [[1,2], + [3,4]] + ) + B_array = np.array([10,11]) + x_list = np.dot(A_array,x_list) + B_array + + dimension = self.dimension + string_list = self.string_list + bulk_output_file = self.bulk_output_file + solver_input_file = self.surface_input_file + fitted_x_list = [] + for index in range(dimension): + fitted_value = " " if x_list[index] >= 0 else "" + fitted_value += format(x_list[index], ".8f") + fitted_value = fitted_value[: len(string_list[index])] + fitted_x_list.append(fitted_value) + #for index in range(dimension): + # print(string_list[index], "=", fitted_x_list[index]) + # + if self.detail_timer is not None : + time_end = time.perf_counter() + self.detail_timer["make_surf_input"] += time_end - time_sta + + + if self.detail_timer is not None : time_sta = time.perf_counter() + # + if self.generate_rocking_curve: + folder_name = self._pre_bulk(step, bulk_output_file, extra) + else: + if self.run_scheme == "connect_so": + folder_name = "." + + elif self.run_scheme == "subprocess": + #make workdir and copy bulk output file + folder_name = self._pre_bulk(step, bulk_output_file, extra) + # + if self.detail_timer is not None : + time_end = time.perf_counter() + self.detail_timer["prepare_Log-directory"] += time_end - time_sta + + if self.detail_timer is not None : time_sta = time.perf_counter() + # + self._replace(fitted_x_list, folder_name) + # + if self.detail_timer is not None : + time_end = time.perf_counter() + self.detail_timer["make_surf_input"] += time_end - time_sta + + return fitted_x_list, folder_name + + def _pre_bulk(self, Log_number, bulk_output_file, extra): + if extra: + folder_name = "Extra_Log{:08d}".format(Log_number) + else: + folder_name = "Log{:08d}".format(Log_number) + os.makedirs(folder_name, exist_ok=True) + if self.run_scheme == "connect_so": + pass + else: #self.run_scheme == "subprocess": + shutil.copy( + bulk_output_file, os.path.join(folder_name, bulk_output_file.name) + ) + return folder_name + + def _replace(self, fitted_x_list, folder_name): + template_file = [] + if self.run_scheme == "subprocess": + file_output = open(os.path.join(folder_name, self.surface_input_file), "w") + for line in self.template_file_origin: + for index in range(self.dimension): + if line.find(self.string_list[index]) != -1: + line = line.replace( + self.string_list[index], + fitted_x_list[index] + ) + + + if self.run_scheme == "connect_so": + line = line.replace("\t", " ").replace("\n", " ") + line = line.encode().ljust(self.surf_tempalte_width_for_fortran) + template_file.append(line) + #print(line) + + elif self.run_scheme == "subprocess": + file_output.write(line) + + + if self.run_scheme == "connect_so": + self.template_file = np.array(template_file) + elif self.run_scheme == "subprocess": + file_output.close() + + ''' + with open(self.surface_template_file, "r") as file_input, open( + os.path.join(folder_name, self.surface_input_file), "w" + ) as file_output: + for line in file_input: + for index in range(self.dimension): + if line.find(self.string_list[index]) != -1: + line = line.replace( + self.string_list[index], + fitted_x_list[index], + ) + file_output.write(line) + ''' + + def _check_template(self) -> None: + found = [False] * self.dimension + with open(self.surface_template_file, "r") as file_input: + for line in file_input: + for index, placeholder in enumerate(self.string_list): + if line.find(placeholder) != -1: + found[index] = True + if not np.all(found): + msg = "ERROR: the following labels do not appear in the template file:" + for label, f in zip(self.string_list, found): + if not f: + msg += "\n" + msg += label + raise exception.InputError(msg) + + class Output(object): + """ + Output manager. + """ + + dimension: int + string_list: List[str] + surface_output_file: str + normalization: str + Rfactor_type: str + calculated_first_line: int + calculated_last_line: int + row_number: int + degree_max: float + degree_list: List[float] + + reference: List[float] + reference_norm: float + reference_normalized: List[float] + degree_list: List[float] + + def __init__(self, info): + self.mpicomm = mpi.comm() + self.mpisize = mpi.size() + self.mpirank = mpi.rank() + + if "dimension" in info.solver: + self.dimension = info.solver["dimension"] + else: + self.dimension = info.base["dimension"] + + info_s = info.solver + self.run_scheme = info_s["run_scheme"] + + # solver.config + info_config = info_s.get("config", {}) + self.surface_output_file = info_config.get( + "surface_output_file", "surf-bulkP.s" + ) + + v = info_config.get("calculated_first_line", 5) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: calculated_first_line should be non-negative integer" + ) + self.calculated_first_line = v + + v = info_config.get("calculated_last_line", 60) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: calculated_last_line should be non-negative integer" + ) + self.calculated_last_line = v + + v = info_config.get("row_number", 8) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: row_number should be non-negative integer" + ) + self.row_number = v + + v = info_config.get("cal_number",None) + #print(v,type(v)) + #sys.exit() + + if v == None : + raise exception.InputError( + "ERROR: You have to set the 'cal_number'." + ) + + if not isinstance(v, list): + raise exception.InputError( + "ERROR: 'cal_number' must be a list type." + ) + + self.cal_number = v + + # solver.post + info_post = info_s.get("post", {}) + v = info_post.get("normalization", "TOTAL") + if v not in ["TOTAL", "MAX", "MS_NORM", "MS_NORM_SET_WGT"]: + raise exception.InputError("ERROR: normalization must be MS_NORM, TOTAL or MAX") + self.normalization = v + + v = info_post.get("Rfactor_type", "A") + if v not in ["A", "B", "A2"]: + raise exception.InputError("ERROR: Rfactor_type must be A, A2 or B") + if self.normalization=="MS_NORM_SET_WGT": + if (v!="A") and (v!="A2") : + raise exception.InputError( + 'ERROR: When normalization="MS_NORM_SET_WGT" is set, only Rfactor_type="A" or Rfactor_type="A2" is valid.' + ) + self.Rfactor_type = v + + v = info_post.get("omega", 0.5) + if v <= 0.0: + raise exception.InputError("ERROR: omega should be positive") + self.omega = v + + self.remove_work_dir = info_post.get("remove_work_dir", False) + + if self.normalization=="MS_NORM_SET_WGT": + v = info_post.get("spot_weight", None) + if v is None: + raise exception.InputError('ERROR:If normalization="MS_NORM_SET_WGT", the weight must be set in solver.post.') + if len(v) != len(self.cal_number): + raise exception.InputError( + "len('cal_number') and len('spot_weight') do not match." + ) + + self.spot_weight = np.array(v)/sum(v) + #debug + #print(f"spot_weight(non_norm) = {v}") + #print(f"self.spot_weight = {self.spot_weight}") + + + # solver.param + info_param = info_s.get("param", {}) + v = info_param.setdefault("string_list", ["value_01", "value_02"]) + if len(v) != self.dimension: + raise exception.InputError( + f"ERROR: len(string_list) != dimension ({len(v)} != {self.dimension})" + ) + self.string_list = v + + v = info_param.get("degree_max", 6.0) + self.degree_max = v + + # solver.reference + info_ref = info_s.get("reference", {}) + reference_path = info_ref.get("path", "experiment.txt") + + v = info_ref.setdefault("first", 1) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: reference_first_line should be non-negative integer" + ) + firstline = v + + v = info_ref.setdefault("last", 56) + if not (isinstance(v, int) and v >= firstline): + raise exception.InputError( + "ERROR: reference_last_line < reference_first_line" + ) + lastline = v + + + # Read experiment-data + + #debug + #print(os.getcwd()) + #if False: + if True: + if self.mpirank == 0: + data_e = np.loadtxt(reference_path) + else: + data_e = None + data_experiment = self.mpicomm.bcast(data_e,root=0) + #print(data_experiment) + #print(data_experiment.dtype) + #print(data_experiment.shape) + #if self.mpirank == 0: + # print(len(data_e)==len(data_experiment)) + # print("for i in range(len(data_e))") + # for i in range(len(data_e)): + # print(data_e[i]==data_experiment[i]) + # print("end") + # print(data_e==data_experiment) + else: + data_experiment = np.loadtxt(reference_path) + + self.beam_number_experiment = data_experiment.shape[1] + self.angle_number_experiment = data_experiment.shape[0] + + v = info_ref.get("exp_number", None) + #print(v,type(v)) + #sys.exit() + if v == None : + raise exception.InputError( + "ERROR: You have to set the 'exp_number'." + ) + + if not isinstance(v, list): + raise exception.InputError( + "ERROR: 'exp_number' must be a list type." + ) + + if max(v) > self.beam_number_experiment: + raise exception.InputError( + "ERROR: The 'exp_number' setting is wrong." + ) + + if self.normalization=="MS_NORM_SET_WGT": + if len(v) != len(self.spot_weight): + raise exception.InputError( + "len('exp_number') and len('spot_weight') do not match." + ) + + self.exp_number = v + number_ex = self.exp_number + sum_experiment = 0 + #for i in range(1,self.beam_number_experiment): + for i in number_ex: + sum_experiment += sum(data_experiment[::,i]) + + #debug + #print(f'number_ex = {number_ex}') + + self.degree_list = (data_experiment[::,0]) + #debug + #print("data_experiment=\n",data_experiment) + self.all_reference_normalized = [] + for index, j in enumerate(number_ex): + self.reference = (data_experiment[::,j]) + #debug + #print(f'index,j={index},{j}\nself.reference=\n{self.reference}') + + self.reference_norm = 0.0 + if self.normalization == "TOTAL": + self.reference_norm = sum_experiment + self.reference_normalized = [ + I_exp / self.reference_norm for I_exp in self.reference + ] + for p in self.reference_normalized: + self.all_reference_normalized.append(p) + + elif self.normalization == "MS_NORM": + if j == number_ex[0]: #first loop + self.reference_norm_1st = np.array([np.sum(self.reference)]) + self.reference_1st_normed = np.array([self.reference/self.reference_norm_1st[-1]]) + else : # N-th loop + self.reference_norm_1st = np.block([self.reference_norm_1st, np.sum(self.reference)]) + self.reference_1st_normed = np.block([[self.reference_1st_normed],[self.reference/self.reference_norm_1st[-1]]]) + #debug + #print(f"j={j}") + #print(f"self.reference_1st_normed=\n{self.reference_1st_normed}") + #print(f"self.reference_norm_1st={self.reference_norm_1st}") + + elif self.normalization == "MS_NORM_SET_WGT": + if index == 0: #first loop + self.reference_norm_l = np.array( + [np.sum(self.reference)] + ) + self.reference_normed_not_sptwgt = np.array( + [self.reference/self.reference_norm_l[-1]] + ) + self.reference_normed = self._multiply_spot_weight( + self.reference_normed_not_sptwgt, + self.spot_weight[index]) + else : # N-th loop + self.reference_norm_l = np.block( + [self.reference_norm_l, + np.sum(self.reference)] + ) + self.reference_normed_not_sptwgt = np.block( + [[self.reference_normed_not_sptwgt], + [self.reference/self.reference_norm_l[-1]]] + ) + self.reference_normed = np.block( + [[self.reference_normed], + [self._multiply_spot_weight( + self.reference_normed_not_sptwgt[-1,:], + self.spot_weight[index]) ] ] + ) + self.all_reference_normalized.extend( + self.reference_normed[-1,:].tolist() + ) + #debug + #print(f"j={j},index={index}") + #print(f"self.reference_norm_l={self.reference_norm_l}") + #print(f"self.reference_normed_not_sptwgt=\n{self.reference_normed_not_sptwgt}") + #print(f"self.reference_normed=\n{self.reference_normed}") + #print(f"self.all_reference_normalized=\n{self.all_reference_normalized}") + + else: # self.normalization == "MAX": + self.reference_norm = max(self.reference) + self.reference_normalized = [ + I_exp / self.reference_norm for I_exp in self.reference + ] + for p in self.reference_normalized: + self.all_reference_normalized.append(p) + + #debug + #print('self.all_reference_normalized=') + #print(self.all_reference_normalized) + #print(f"self.reference_norm_1st=\n{self.reference_norm_1st}") + #print(f"self.reference_1st_normed=\n{self.reference_1st_normed}") + + def prepare(self, fitted_x_list): + self.fitted_x_list = fitted_x_list + + def get_results(self, work_dir) -> float: + """ + Get Rfactor obtained by the solver program. + Returns + ------- + """ + # Calculate Rfactor and Output numerical results + cwd = os.getcwd() + os.chdir(work_dir) + Rfactor = self._post(self.fitted_x_list) + os.chdir(cwd) + + #delete Log-directory + if self.detail_timer is not None : time_sta = time.perf_counter() + # + if self.run_scheme == "subprocess": + if self.remove_work_dir: + def rmtree_error_handler(function, path, excinfo): + print(f"WARNING: Failed to remove a working directory, {path}") + shutil.rmtree(work_dir, onerror=rmtree_error_handler) + + elif self.run_scheme == "connect_so": + pass + # + if self.detail_timer is not None : + time_end = time.perf_counter() + self.detail_timer["delete_Log-directory"] += time_end - time_sta + ## + + return Rfactor + + def _post(self, fitted_x_list): + degree_list = self.degree_list + I_experiment_norm = self.reference_norm + I_experiment_list = self.reference + + ( + all_convolution_I_calculated_list_normalized, + I_calculated_norm, + convolution_I_calculated_list, + ) = self._calc_I_from_file() + + ### + if self.detail_timer is not None : time_sta = time.perf_counter() + Rfactor = self._calc_Rfactor(all_convolution_I_calculated_list_normalized) + #print("R-factor =", Rfactor) + if self.detail_timer is not None : + time_end = time.perf_counter() + self.detail_timer["calculate_R-factor"] += time_end - time_sta + ### + + dimension = self.dimension + string_list = self.string_list + + if self.generate_rocking_curve : + if self.detail_timer is not None : time_sta = time.perf_counter() + with open("RockingCurve.txt", "w") as file_RC: + # Write headers + file_RC.write("#") + for index in range(dimension): + file_RC.write( + "{} = {} ".format(string_list[index], fitted_x_list[index]) + ) + file_RC.write("\n") + file_RC.write(f"#Rfactor_type = {self.Rfactor_type}") + file_RC.write("\n") + file_RC.write(f"#normalization = {self.normalization}") + file_RC.write("\n") + file_RC.write("#R-factor = {}\n".format(Rfactor)) + file_RC.write("#cal_number = {}\n".format(self.cal_number)) + file_RC.write("#spot_weight = {}\n".format(self.spot_weight)) + + file_RC.write("#") + file_RC.write("\n") + file_RC.write("#NOTICE : The listed intensities are NOT multiplied by spot_weight.") + file_RC.write("\n") + file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.") + file_RC.write("\n") + file_RC.write("#sum( I_(spot) ) = 1") + file_RC.write("\n") + + file_RC.write("#") + file_RC.write("\n") + + label_column = ["glancing_angle"] + fmt_rc = '%.5f' + for i in range(len(self.cal_number)): + label_column.append(f"cal_number={self.cal_number[i]}") + fmt_rc += " %.15e" + + for i in range(len(label_column)): + file_RC.write(f"# #{i} {label_column[i]}") + file_RC.write("\n") + + angle_for_rc = np.array([self.glancing_angle]) + np.savetxt( + file_RC, + np.block( + [angle_for_rc.T, + self.convolution_I_calculated_list_normalized_not_spotwgt_array.T] + ), + fmt=fmt_rc + ) + + + + if self.detail_timer is not None : + time_end = time.perf_counter() + self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta + + """ + with open("RockingCurve.txt", "w") as file_RC: + I_experiment_list_normalized = self.reference_normalized + # Write headers + file_RC.write("#") + for index in range(dimension): + file_RC.write( + "{} = {} ".format(string_list[index], fitted_x_list[index]) + ) + file_RC.write("\n") + file_RC.write("#R-factor = {}\n".format(Rfactor)) + if self.normalization == "TOTAL": + file_RC.write("#I_calculated_total={}\n".format(I_calculated_norm)) + file_RC.write("#I_experiment_total={}\n".format(I_experiment_norm)) + else: # self.normalization == "MAX" + file_RC.write("#I_calculated_max={}\n".format(I_calculated_norm)) + file_RC.write("#I_experiment_max={}\n".format(I_experiment_norm)) + file_RC.write("#") + for xname in ( + "degree", + "convolution_I_calculated", + "I_experiment", + "convolution_I_calculated(normalized)", + "I_experiment(normalized)", + "I_calculated", + ): + file_RC.write(xname) + file_RC.write(" ") + file_RC.write("\n") + + # Write rocking curve + for index in range(len(degree_list)): + file_RC.write( + "{} {} {} {} {}\n".format( + degree_list[index], + convolution_I_calculated_list[index], + I_experiment_list[index], + all_convolution_I_calculated_list_normalized[index], + I_experiment_list_normalized[index], + ) + ) + """ + return Rfactor + + def _g(self, x): + g = (0.939437 / self.omega) * np.exp( + -2.77259 * (x ** 2.0 / self.omega ** 2.0) + ) + return g + + def _calc_I_from_file(self): + if self.detail_timer is not None : time_sta = time.perf_counter() + # + surface_output_file = self.surface_output_file + calculated_first_line = self.calculated_first_line + calculated_last_line = self.calculated_last_line + row_number = self.row_number + degree_max = self.degree_max + degree_list = self.degree_list + + nlines = calculated_last_line - calculated_first_line + 1 + # TODO: handling error + assert 0 < nlines + + # TODO: nlines == len(degree_list) ? + # assert nlines == len(degree_list) + if self.run_scheme == "connect_so": + Clines = self.surf_output + + elif self.run_scheme == "subprocess": + file_input = open(self.surface_output_file, "r") + Clines = file_input.readlines() + file_input.close() + # + if self.detail_timer is not None : + time_end = time.perf_counter() + self.detail_timer["load_STR_result"] += time_end - time_sta + + + ##### convolution ##### + + """ + beam = [0,0,0.5,0,1.0,0,1.5,0,2.0,0] + bulk_data = np.loadtxt("/Users/ichinosehayato/mv_2DMAT/2DMAT_MB_ICHINOSE/sample/py2dmat/minsearch/bulk.txt") + denominator_H = float(bulk_data[0,0]) + denominator_K = float(bulk_data[0,1]) + for H in beam[0::2]: + beamnum_H = H*denominator_H + beamnum.append(beamnum_H) + for K in beam[1::2]: + beamnum_K = K*denominator_K + beamnum.append(beamnum_K) + break + print(beamnum) + + for n in beamnum[0::2]: + number.append(n*2) + print(number) + """ + + #print(os.getcwd()) + ############# + if self.detail_timer is not None : time_sta = time.perf_counter() + verbose_mode = False + data_convolution = lib_make_convolution.calc( + Clines, self.omega, verbose_mode + ) + #print("data_convolution=") + #print(data_convolution) + + self.all_convolution_I_calculated_list_normalized = [] + #print(f"data_convolution=\n{data_convolution}") + + #number = [7,8,9,10,11] + number = self.cal_number + angle_number_convolution = data_convolution.shape[0] + self.glancing_angle = data_convolution[:,0] + + if self.angle_number_experiment !=angle_number_convolution: + raise exception.InputError( + "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." + ) + + self.beam_number_convolution = data_convolution.shape[1] + #for s in range(1,self.beam_number_convolution): + sum_convolution = np.sum(data_convolution[:,number]) + #debug + #print(f'sum_convolution = {sum_convolution}') + + for i in range(len(number)): + convolution_I_calculated_list = data_convolution[:,number[i]] + #debug + #print(f'convolution_I_calculated_list=\n{convolution_I_calculated_list}') + + if self.normalization == "TOTAL": + I_calculated_norm = sum_convolution + convolution_I_calculated_list_normalized = [ + c / I_calculated_norm for c in convolution_I_calculated_list + ] + + elif self.normalization == "MS_NORM": + if i == 0: + self.reference_2nd_normed = copy.deepcopy(self.reference_1st_normed) + self.all_reference_normalized = [] + I_calculated_norm = sum_convolution + convolution_I_calculated_list_normalized = [ + c / I_calculated_norm for c in convolution_I_calculated_list + ] + I_calc_norm_sum_spot = sum(convolution_I_calculated_list_normalized) + self.reference_2nd_normed[i,:] *= I_calc_norm_sum_spot + self.all_reference_normalized.extend(self.reference_2nd_normed[i,:].tolist()) + #debug + #print(f"i={i}, number[i]={number[i]}") + #print(f"convolution_I_calculated_list_normalized={convolution_I_calculated_list_normalized}") + #print(f"I_calc_norm_sum_spot={I_calc_norm_sum_spot}") + #print(f"self.reference_2nd_normed=\n{self.reference_2nd_normed}") + #print(f"self.all_reference_normalized={self.all_reference_normalized}") + + elif self.normalization == "MS_NORM_SET_WGT": + if i == 0: #first loop + I_calculated_norm = np.array( + [np.sum(convolution_I_calculated_list)] + ) + self.convolution_I_calculated_list_normalized_not_spotwgt_array = np.array( + [convolution_I_calculated_list/I_calculated_norm[-1]] + ) + convolution_I_calculated_list_normalized_array = self._multiply_spot_weight( + self.convolution_I_calculated_list_normalized_not_spotwgt_array, + self.spot_weight[i]) + #convolution_I_calculated_list_normalized = convolution_I_calculated_list_normalized_array[:].copy() + else: # N-th loop + I_calculated_norm = np.block( + [I_calculated_norm, + np.sum(convolution_I_calculated_list)] + ) + self.convolution_I_calculated_list_normalized_not_spotwgt_array = np.block( + [[self.convolution_I_calculated_list_normalized_not_spotwgt_array], + [convolution_I_calculated_list/I_calculated_norm[-1]]] + ) + convolution_I_calculated_list_normalized_array = np.block( + [[convolution_I_calculated_list_normalized_array], + [ self._multiply_spot_weight( + self.convolution_I_calculated_list_normalized_not_spotwgt_array[-1,:], + self.spot_weight[i]) ] ] + ) + convolution_I_calculated_list_normalized = convolution_I_calculated_list_normalized_array[-1,:].copy() + #debug + #print(f"i={i}, number[i]={number[i]}") + #print(f"I_calculated_norm={I_calculated_norm}") + #print(f"self.convolution_I_calculated_list_normalized_not_spotwgt_array=\n{self.convolution_I_calculated_list_normalized_not_spotwgt_array}") + #print(f"convolution_I_calculated_list_normalized_array=\n{convolution_I_calculated_list_normalized_array}") + #print(f"convolution_I_calculated_list_normalized=\n{convolution_I_calculated_list_normalized}") + + else: # self.normalization == "MAX" + print('self.normalization == "MAX" mb対応検討中') + I_calculated_norm = max(convolution_I_calculated_list) + convolution_I_calculated_list_normalized = [ + c / I_calculated_norm for c in convolution_I_calculated_list + ] + for h in convolution_I_calculated_list_normalized: + self.all_convolution_I_calculated_list_normalized.append(h) + + if self.detail_timer is not None : + time_end = time.perf_counter() + self.detail_timer["convolution"] += time_end - time_sta + + #debug + #print('self.all_convolution_I_calculated_list_normalized=') + #print(self.all_convolution_I_calculated_list_normalized) + + #print("self.all_convolution_I_calculated_list_normalized=") + #print(self.all_convolution_I_calculated_list_normalized) + return ( + self.all_convolution_I_calculated_list_normalized, + I_calculated_norm, + convolution_I_calculated_list, + ) + + + def _calc_Rfactor(self, calc_result): + I_experiment_list_normalized = self.all_reference_normalized + if self.Rfactor_type == "A": + R = 0.0 + for I_exp, I_calc in zip(I_experiment_list_normalized, calc_result): + R += (I_exp - I_calc) ** 2 + R = np.sqrt(R) + + elif self.Rfactor_type == "A2": + R = 0.0 + for I_exp, I_calc in zip(I_experiment_list_normalized, calc_result): + R += (I_exp - I_calc) ** 2 + #debug + #print(f"I_exp, I_calc, I_exp-I_calc = {I_exp}, {I_calc}, {I_exp-I_calc}") + #print(f"R-factor = {R}") + else: # self.Rfactor_type == "B" + y1 = 0.0 + y2 = 0.0 + y3 = 0.0 + for I_exp, I_calc in zip(I_experiment_list_normalized, calc_result): + y1 += (I_exp - I_calc) ** 2 + y2 += I_exp ** 2 + y3 += I_calc ** 2 + R = y1 / (y2 + y3) + return R + + def _multiply_spot_weight(self,I_not_multiplied_spotwgt,s_weight): + if self.Rfactor_type=="A": + I_multiplied = s_weight*I_not_multiplied_spotwgt + + elif self.Rfactor_type=="A2": + I_multiplied = np.sqrt(s_weight)*I_not_multiplied_spotwgt + + else: + raise exception.InputError( + 'ERROR: When normalization="MS_NORM_SET_WGT" is set, only Rfactor_type="A" or Rfactor_type="A2" is valid.' + ) + return I_multiplied From f0cb3ee0e5e92bed70b1fbe2da6e3457dc8d4151 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Thu, 27 Jul 2023 13:56:41 +0900 Subject: [PATCH 02/67] add: solver="sim-trhepd-rheed-mb_connect" is available. --- src/py2dmat/_main.py | 2 ++ src/py2dmat/solver/lib_make_convolution.py | 21 ++++++++++++++----- .../solver/sim_trhepd_rheed_mb_connect.py | 6 ++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/py2dmat/_main.py b/src/py2dmat/_main.py index 951aa390..60bc35e8 100644 --- a/src/py2dmat/_main.py +++ b/src/py2dmat/_main.py @@ -74,6 +74,8 @@ def main(): from .solver.leed import Solver elif solvername == "analytical": from .solver.analytical import Solver + elif solvername == "sim-trhepd-rheed-mb_connect": + from .solver.sim_trhepd_rheed_mb_connect import Solver else: print(f"ERROR: Unknown solver ({solvername})") exit(1) diff --git a/src/py2dmat/solver/lib_make_convolution.py b/src/py2dmat/solver/lib_make_convolution.py index 438dc4eb..8c4c09eb 100644 --- a/src/py2dmat/solver/lib_make_convolution.py +++ b/src/py2dmat/solver/lib_make_convolution.py @@ -16,7 +16,8 @@ def g(x): return g number_of_lines = int(len(Clines)) - number_of_header_lines = 4 + #number_of_header_lines = 4 + alpha_lines + #Nakano_write('+ 1') if verbose_mode: print("number_of_lines =", number_of_lines) print("number_of_header_lines =", number_of_header_lines) @@ -26,13 +27,23 @@ def g(x): # Read the file header line = Clines[0] + if verbose_mode: + print("debug:lib_make_convolution.py") + print(f"Clines[0:5]=",Clines[0:5]) + #print(line) + if line == ' FILE OUTPUT for UNIT3\n': + alpha_lines = 1 + else: + alpha_lines = 0 + if verbose_mode: print("debug alpha_lines=",alpha_lines) + number_of_header_lines = 4 + alpha_lines #print("file header :", line) - line = Clines[1] + line = Clines[1 + alpha_lines] #print("file header :", line) #sys.exit() line = line.replace(",", "") data = line.split() - #print(data) + number_of_azimuth_angles = int(data[0]) number_of_glancing_angles = int(data[1]) number_of_beams = int(data[2]) @@ -48,9 +59,9 @@ def g(x): RC_data_cnv = np.zeros((number_of_glancing_angles, number_of_beams+1)) # Read the file header - line = Clines[2] + line = Clines[2+ alpha_lines] #print("file header :", line, end="") - line = Clines[3] + line = Clines[3+ alpha_lines] #print("file header :", line, end="") line = line.replace(",", "") data = line.split() diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index 24c8a8be..6be3c443 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -193,6 +193,12 @@ def launch_so(self): import sys sys.exit() ''' + def run(self, nprocs: int = 1, nthreads: int = 1) -> None: + if self.run_scheme == "connect_so": + self.launch_so() + elif self.run_scheme == "subprocess": + self._run_by_subprocess([str(self.path_to_solver)]) + class Input(object): root_dir: Path From 46c38805cd5991c0befa5e86f570df87bef302f3 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 2 Aug 2023 19:10:36 +0900 Subject: [PATCH 03/67] normalization = "MS_NORM_SET_WGT" and Rfactor_type = "A" is aveilable. --- src/py2dmat/solver/lib_make_convolution.py | 41 +++++++++++++------ .../solver/sim_trhepd_rheed_mb_connect.py | 8 ++-- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/py2dmat/solver/lib_make_convolution.py b/src/py2dmat/solver/lib_make_convolution.py index 8c4c09eb..379e6a28 100644 --- a/src/py2dmat/solver/lib_make_convolution.py +++ b/src/py2dmat/solver/lib_make_convolution.py @@ -3,8 +3,8 @@ def calc(Clines, omega, verbose_mode): if verbose_mode: - print('arg:filename=',args.filename) - print('omega =',args.omega) + #print('arg:filename=',args.filename) + print('omega =',omega) sigma = 0.5 * omega / (np.sqrt(2.0*np.log(2.0))) @@ -13,30 +13,34 @@ def calc(Clines, omega, verbose_mode): # return g def g(x): g = (1.0 / (sigma*np.sqrt(2.0*np.pi))) * np.exp(-0.5 * x ** 2.0 / sigma ** 2.0) - return g - - number_of_lines = int(len(Clines)) - #number_of_header_lines = 4 + alpha_lines - #Nakano_write('+ 1') - if verbose_mode: - print("number_of_lines =", number_of_lines) - print("number_of_header_lines =", number_of_header_lines) - #degree_list = [] - #C_list = [] + return g # Read the file header - line = Clines[0] if verbose_mode: print("debug:lib_make_convolution.py") print(f"Clines[0:5]=",Clines[0:5]) #print(line) + + line = Clines[0] + if line == ' FILE OUTPUT for UNIT3\n': alpha_lines = 1 else: alpha_lines = 0 + if verbose_mode: print("debug alpha_lines=",alpha_lines) + + number_of_lines = int(len(Clines)) number_of_header_lines = 4 + alpha_lines + + if verbose_mode: + print("number_of_lines =", number_of_lines) + print("number_of_header_lines =", number_of_header_lines) + + #degree_list = [] + #C_list = [] + #print("file header :", line) line = Clines[1 + alpha_lines] #print("file header :", line) @@ -68,9 +72,12 @@ def g(x): #print(data) if verbose_mode: + """ print("beam index (p,q): i p_i q_i") for beam_index in range(number_of_beams): print(beam_index, data[beam_index*2], data[beam_index*2+1]) + """ + pass for g_angle_index in range(number_of_glancing_angles): line_index = number_of_header_lines + g_angle_index @@ -87,6 +94,8 @@ def g(x): angle_interval = RC_data_org[1,0] - RC_data_org[0,0] if verbose_mode: + print("RC_data_org =\n",RC_data_org) + print("RC_data_cnv =\n",RC_data_cnv) print('angle_ interval=', angle_interval) for beam_index in range(number_of_beams): @@ -94,9 +103,15 @@ def g(x): integral = 0.0 for index2 in range(number_of_glancing_angles): integral += RC_data_org[index2,beam_index+1] * g(RC_data_org[index,0] - RC_data_org[index2,0]) * angle_interval + if verbose_mode: + print("beam_index, index, index2, g(RC_data_org[index,0] - RC_data_org[index2,0]) =",beam_index, index, index2, g(RC_data_org[index,0] - RC_data_org[index2,0])) RC_data_cnv[index, beam_index+1]=integral #np.savetxt("convolution.txt", RC_data_cnv, fmt="%.5e") + + if verbose_mode: + print("RC_data_cnv =\n",RC_data_cnv) + return RC_data_cnv #np.savetxt("original.txt", RC_data_org, fmt="%.5e") diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index 6be3c443..a26bc668 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -974,6 +974,7 @@ def _calc_I_from_file(self): ############# if self.detail_timer is not None : time_sta = time.perf_counter() verbose_mode = False + #print("debug: Clines:",Clines) data_convolution = lib_make_convolution.calc( Clines, self.omega, verbose_mode ) @@ -1116,12 +1117,9 @@ def _calc_Rfactor(self, calc_result): return R def _multiply_spot_weight(self,I_not_multiplied_spotwgt,s_weight): - if self.Rfactor_type=="A": - I_multiplied = s_weight*I_not_multiplied_spotwgt - - elif self.Rfactor_type=="A2": + if (self.Rfactor_type=="A") or (self.Rfactor_type=="A2") : I_multiplied = np.sqrt(s_weight)*I_not_multiplied_spotwgt - + else: raise exception.InputError( 'ERROR: When normalization="MS_NORM_SET_WGT" is set, only Rfactor_type="A" or Rfactor_type="A2" is valid.' From fc9322fa71bdbc9f12cdc489d20d484773780e18 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sun, 13 Aug 2023 22:10:41 +0900 Subject: [PATCH 04/67] mod : Keep the rocking curve data as "self.calc_rocking_curve". --- .../solver/sim_trhepd_rheed_mb_connect.py | 100 ++++++++++-------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index a26bc668..ffd980bb 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -815,54 +815,55 @@ def _post(self, fitted_x_list): string_list = self.string_list if self.generate_rocking_curve : - if self.detail_timer is not None : time_sta = time.perf_counter() - with open("RockingCurve.txt", "w") as file_RC: - # Write headers - file_RC.write("#") - for index in range(dimension): - file_RC.write( - "{} = {} ".format(string_list[index], fitted_x_list[index]) - ) - file_RC.write("\n") - file_RC.write(f"#Rfactor_type = {self.Rfactor_type}") - file_RC.write("\n") - file_RC.write(f"#normalization = {self.normalization}") - file_RC.write("\n") - file_RC.write("#R-factor = {}\n".format(Rfactor)) - file_RC.write("#cal_number = {}\n".format(self.cal_number)) - file_RC.write("#spot_weight = {}\n".format(self.spot_weight)) - - file_RC.write("#") - file_RC.write("\n") - file_RC.write("#NOTICE : The listed intensities are NOT multiplied by spot_weight.") - file_RC.write("\n") - file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.") - file_RC.write("\n") - file_RC.write("#sum( I_(spot) ) = 1") - file_RC.write("\n") - - file_RC.write("#") - file_RC.write("\n") - - label_column = ["glancing_angle"] - fmt_rc = '%.5f' - for i in range(len(self.cal_number)): - label_column.append(f"cal_number={self.cal_number[i]}") - fmt_rc += " %.15e" - - for i in range(len(label_column)): - file_RC.write(f"# #{i} {label_column[i]}") - file_RC.write("\n") - - angle_for_rc = np.array([self.glancing_angle]) - np.savetxt( - file_RC, - np.block( - [angle_for_rc.T, - self.convolution_I_calculated_list_normalized_not_spotwgt_array.T] - ), - fmt=fmt_rc + if self.normalization == "MS_NORM": + print('NOTICE: The output of rocking curve is not implemented when the following settings are made: self.normalization == "MS_NORM".') + else: + if self.detail_timer is not None : time_sta = time.perf_counter() + with open("RockingCurve.txt", "w") as file_RC: + # Write headers + file_RC.write("#") + for index in range(dimension): + file_RC.write( + "{} = {} ".format(string_list[index], fitted_x_list[index]) ) + file_RC.write("\n") + file_RC.write(f"#Rfactor_type = {self.Rfactor_type}") + file_RC.write("\n") + file_RC.write(f"#normalization = {self.normalization}") + file_RC.write("\n") + file_RC.write("#R-factor = {}\n".format(Rfactor)) + file_RC.write("#cal_number = {}\n".format(self.cal_number)) + if self.normalization == "MS_NORM_SET_WGT" : + file_RC.write("#spot_weight = {}\n".format(self.spot_weight)) + file_RC.write("#NOTICE : The listed intensities are NOT multiplied by spot_weight.") + file_RC.write("\n") + file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.") + file_RC.write("\n") + file_RC.write("#sum( I_(spot) ) = 1") + file_RC.write("\n") + + file_RC.write("#") + file_RC.write("\n") + + label_column = ["glancing_angle"] + fmt_rc = '%.5f' + for i in range(len(self.cal_number)): + label_column.append(f"cal_number={self.cal_number[i]}") + fmt_rc += " %.15e" + + for i in range(len(label_column)): + file_RC.write(f"# #{i} {label_column[i]}") + file_RC.write("\n") + + angle_for_rc = np.array([self.glancing_angle]) + np.savetxt( + file_RC, + np.block( + [angle_for_rc.T, + self.calc_rocking_curve.T] + ), + fmt=fmt_rc + ) @@ -1010,6 +1011,8 @@ def _calc_I_from_file(self): convolution_I_calculated_list_normalized = [ c / I_calculated_norm for c in convolution_I_calculated_list ] + self.calc_rocking_curve = np.array([copy.deepcopy(convolution_I_calculated_list_normalized)]) + #print("convolution_I_calculated_list_normalized=",convolution_I_calculated_list_normalized) elif self.normalization == "MS_NORM": if i == 0: @@ -1057,6 +1060,7 @@ def _calc_I_from_file(self): self.spot_weight[i]) ] ] ) convolution_I_calculated_list_normalized = convolution_I_calculated_list_normalized_array[-1,:].copy() + self.calc_rocking_curve = np.copy(self.convolution_I_calculated_list_normalized_not_spotwgt_array) #debug #print(f"i={i}, number[i]={number[i]}") #print(f"I_calculated_norm={I_calculated_norm}") @@ -1070,6 +1074,8 @@ def _calc_I_from_file(self): convolution_I_calculated_list_normalized = [ c / I_calculated_norm for c in convolution_I_calculated_list ] + self.calc_rocking_curve = np.array([copy.deepcopy(convolution_I_calculated_list_normalized)]) + for h in convolution_I_calculated_list_normalized: self.all_convolution_I_calculated_list_normalized.append(h) From 109a33ceaa98e79928ee7e056a4193b8842d7f6f Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 26 Aug 2023 16:25:47 +0900 Subject: [PATCH 05/67] Only MPIrank=0 process executes _check_template. --- src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index ffd980bb..a900aa79 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -250,11 +250,11 @@ def __init__(self, info): f"ERROR: surface_template_file ({self.surface_template_file}) does not exist" ) - self._check_template() #if False: if True: if self.mpirank == 0: + self._check_template() temp_origin = self.load_surface_template_file(filename) else: temp_origin = None From b8cb4871234cc1217c41952aa0b889f1799406c2 Mon Sep 17 00:00:00 2001 From: "H.Iwamoto" <74635361+H-Iwamoto-research@users.noreply.github.com> Date: Thu, 7 Sep 2023 09:43:05 +0900 Subject: [PATCH 06/67] Update sim-trhepd-rheed.rst (WIP) edit manual --- doc/ja/source/solver/sim-trhepd-rheed.rst | 43 ++++++++++++----------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/doc/ja/source/solver/sim-trhepd-rheed.rst b/doc/ja/source/solver/sim-trhepd-rheed.rst index c769c489..0b6e3e67 100644 --- a/doc/ja/source/solver/sim-trhepd-rheed.rst +++ b/doc/ja/source/solver/sim-trhepd-rheed.rst @@ -20,10 +20,25 @@ 入力パラメータ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``solver`` セクション中のサブセクション +``solver`` セクションとセクション中のサブセクション ``config``, ``post``, ``param``, ``reference`` を利用します。 -[``config``] セクション +[``solver``] セクション +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- ``run_scheme`` + + 形式: string型。"subprocess"または"connect_so"のいずれかをとります。 + + 説明: ソルバーとして使用するファイルを指定します。前者は ``surf.exe`` 、後者は ``surf.so`` を使用したいときに指定します。 + +- ``generate_rocking_curve`` + + 形式: 真偽値 (default: false) + + 説明: ``RockingCurve.txt`` の生成をするかどうか + + +[``config``] セクション(サブセクション) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``surface_exec_file`` @@ -50,25 +65,13 @@ 説明: 表面構造のアウトプットファイル。 -- ``calculated_first_line`` - - 形式: 整数型 (default: 5) - - 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む最初の行を指定。 - -- ``calculated_last_line`` - - 形式: 整数型 (default: 60) - - 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む最後の行を指定。 - -- ``row_number`` +- ``cal_number`` - 形式: 整数型 (default: 8) + 形式: 整数型のリスト。 - 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む列を指定。 + 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む列を指定。複数指定が可能。 -[``post``] セクション +[``post``] セクション(サブセクション) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``normalization`` @@ -100,7 +103,7 @@ 説明: R-factor を読み取った後に作業ディレクトリ ``Log%%%_###`` を削除するかどうか -[``param``] セクション +[``param``] セクション(サブセクション) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``string_list`` @@ -115,7 +118,7 @@ 説明: 最大角度(度単位)の指定 -[``reference``] セクション +[``reference``] セクション(サブセクション) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``path`` From 91c031ba82af0df4508bb36c8fe933fef9e71b38 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Fri, 8 Sep 2023 00:19:36 +0900 Subject: [PATCH 07/67] fix : iset and LogXXX_XXX directory --- src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index a900aa79..d59d6469 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -339,8 +339,7 @@ def prepare(self, message: py2dmat.Message): # x_list = message.x step = message.step - #extra = False - extra = message.set > 0 + iset = message.set #### ADHOC_MPPING! ###" adhoc_mapping = False @@ -375,14 +374,14 @@ def prepare(self, message: py2dmat.Message): if self.detail_timer is not None : time_sta = time.perf_counter() # if self.generate_rocking_curve: - folder_name = self._pre_bulk(step, bulk_output_file, extra) + folder_name = self._pre_bulk(step, bulk_output_file, iset) else: if self.run_scheme == "connect_so": folder_name = "." elif self.run_scheme == "subprocess": #make workdir and copy bulk output file - folder_name = self._pre_bulk(step, bulk_output_file, extra) + folder_name = self._pre_bulk(step, bulk_output_file, iset) # if self.detail_timer is not None : time_end = time.perf_counter() @@ -398,11 +397,8 @@ def prepare(self, message: py2dmat.Message): return fitted_x_list, folder_name - def _pre_bulk(self, Log_number, bulk_output_file, extra): - if extra: - folder_name = "Extra_Log{:08d}".format(Log_number) - else: - folder_name = "Log{:08d}".format(Log_number) + def _pre_bulk(self, Log_number, bulk_output_file, iset): + folder_name = "Log{:08d}_{:08d}".format(Log_number, iset) os.makedirs(folder_name, exist_ok=True) if self.run_scheme == "connect_so": pass From 29a5e2727828d0d165cfa67b69ded5dc0f115d53 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Fri, 8 Sep 2023 15:37:57 +0900 Subject: [PATCH 08/67] fix errors in sim-trhepd-rheed.rst --- doc/ja/source/solver/sim-trhepd-rheed.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/ja/source/solver/sim-trhepd-rheed.rst b/doc/ja/source/solver/sim-trhepd-rheed.rst index 0b6e3e67..bdd609f5 100644 --- a/doc/ja/source/solver/sim-trhepd-rheed.rst +++ b/doc/ja/source/solver/sim-trhepd-rheed.rst @@ -39,7 +39,7 @@ [``config``] セクション(サブセクション) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``surface_exec_file`` @@ -72,7 +72,7 @@ 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む列を指定。複数指定が可能。 [``post``] セクション(サブセクション) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``normalization`` @@ -104,7 +104,7 @@ [``param``] セクション(サブセクション) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``string_list`` @@ -119,7 +119,7 @@ 説明: 最大角度(度単位)の指定 [``reference``] セクション(サブセクション) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``path`` From e376f02b4c2ab27d82d8470a5a5af3c6758ed8ac Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sun, 10 Sep 2023 20:19:36 +0900 Subject: [PATCH 09/67] Removed redundant comments and debugging code. --- .../solver/sim_trhepd_rheed_mb_connect.py | 350 ++---------------- 1 file changed, 31 insertions(+), 319 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index d59d6469..b485edf4 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -17,7 +17,6 @@ from typing import TYPE_CHECKING -import sys import copy class Solver(py2dmat.solver.SolverBase): @@ -62,29 +61,10 @@ def __init__(self, info: py2dmat.Info): self.input.run_scheme = self.run_scheme self.output.run_scheme = self.run_scheme - if self.run_scheme == "connect_so": - self.load_so() - - elif self.run_scheme == "subprocess": - #path to surf.exe - p2solver = info.solver["config"].get("surface_exec_file", "surf.exe") - if os.path.dirname(p2solver) != "": - # ignore ENV[PATH] - self.path_to_solver = self.root_dir / Path(p2solver).expanduser() - else: - for P in itertools.chain([self.root_dir], os.environ["PATH"].split(":")): - self.path_to_solver = Path(P) / p2solver - if os.access(self.path_to_solver, mode=os.X_OK): - break - if not os.access(self.path_to_solver, mode=os.X_OK): - raise exception.InputError(f"ERROR: solver ({p2solver}) is not found") - self.generate_rocking_curve = info.solver.get("generate_rocking_curve", False) - #print(f" info.solver = {info.solver}") self.input.generate_rocking_curve = self.generate_rocking_curve self.output.generate_rocking_curve = self.generate_rocking_curve - #add if True: self.detail_timer = {} self.detail_timer["prepare_Log-directory"] = 0 @@ -135,27 +115,6 @@ def load_so(self): def launch_so(self): - #debug - #print(os.getcwd()) - ###### debug ############ - ''' - #make surf.txt - for line in self.input.template_file: - #f = open('surf.txt','w') - l = line.decode().rstrip() - print(l) - #f.write(l) - #f.write('\n') - - #f.close() - #sys.exit() - ''' - ######################### - - #fn = ctypes.byref(ctypes.c_int(n)) - #fm = ctypes.byref(ctypes.c_int(m)) - #print(self.input.template_file) - #sys.exit() n_template_file = len(self.input.template_file) m_template_file = self.input.surf_tempalte_width_for_fortran n_bulk_file = len(self.input.bulk_file) @@ -163,14 +122,6 @@ def launch_so(self): emp_str = ' '*20480 self.output.surf_output = np.array([emp_str.encode()]) - #for i in range(n_bulk_file): - # print(len(self.input.bulk_file[i])) - - #import sys - #sys.exit() - #print(self.input.template_file) - #print(self.input.bulk_file) - #print('launch so') self.lib.surf_so( ctypes.byref(ctypes.c_int(n_template_file)), ctypes.byref(ctypes.c_int(m_template_file)), @@ -180,26 +131,14 @@ def launch_so(self): self.input.bulk_file, self.output.surf_output ) - #print('finish so') self.output.surf_output = self.output.surf_output[0].decode().splitlines() - ''' - print('----------in python----------') - f = open('surf-bulkP.s','w') - for i in range(len(self.output.surf_output)): - f.write(self.output.surf_output[i]i.rstrip()) - f.write('\n') - - f.close() - import sys - sys.exit() - ''' + def run(self, nprocs: int = 1, nthreads: int = 1) -> None: if self.run_scheme == "connect_so": self.launch_so() elif self.run_scheme == "subprocess": self._run_by_subprocess([str(self.path_to_solver)]) - class Input(object): root_dir: Path output_dir: Path @@ -224,11 +163,10 @@ def __init__(self, info): info_s = info.solver self.run_scheme = info_s["run_scheme"] - # + self.surf_tempalte_width_for_fortran = 128 self.bulk_out_width_for_fortran = 1024 - # - + info_param = info_s.get("param", {}) v = info_param.setdefault("string_list", ["value_01", "value_02"]) if len(v) != self.dimension: @@ -249,27 +187,13 @@ def __init__(self, info): raise exception.InputError( f"ERROR: surface_template_file ({self.surface_template_file}) does not exist" ) - - #if False: - if True: - if self.mpirank == 0: - self._check_template() - temp_origin = self.load_surface_template_file(filename) - else: - temp_origin = None - self.template_file_origin = self.mpicomm.bcast(temp_origin,root=0) - #if self.mpirank == 0: - # print(temp_origin,"\n") - # print(self.template_file_origin) - # print(len(temp_origin)==len(self.template_file_origin)) - # print("for i in range(len(temp_origin))") - # for i in range(len(temp_origin)): - # print(temp_origin[i]==self.template_file_origin[i]) - # print("end") - # print(temp_origin==self.template_file_origin) - else : - self.template_file_origin = self.load_surface_template_file(filename) + if self.mpirank == 0: + self._check_template() + temp_origin = self.load_surface_template_file(filename) + else: + temp_origin = None + self.template_file_origin = self.mpicomm.bcast(temp_origin,root=0) if self.run_scheme == "connect_so": filename = info_config.get("bulk_output_file", "bulkP.txt") @@ -280,28 +204,11 @@ def __init__(self, info): f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" ) - #if False: - if True: - if self.mpirank == 0: - bulk_f = self.load_bulk_output_file(filename) - #print(bulk_f) - #print(bulk_f.dtype) - #print(bulk_f.shape) - else: - bulk_f = None - self.bulk_file = self.mpicomm.bcast(bulk_f,root=0) - #print(self.bulk_file) - #print(self.bulk_file.dtype) - #print(self.bulk_file.shape) - #if self.mpirank == 0: - # print(len(bulk_f)==len(self.bulk_file)) - # print("for i in range(len(bulk_f))") - # for i in range(len(bulk_f)): - # print(bulk_f[i]==self.bulk_file[i]) - # print("end") - # print(bulk_f==self.bulk_file) + if self.mpirank == 0: + bulk_f = self.load_bulk_output_file(filename) else: - self.bulk_file = self.load_bulk_output_file(filename) + bulk_f = None + self.bulk_file = self.mpicomm.bcast(bulk_f,root=0) else: filename = info_config.get("bulk_output_file", "bulkP.b") @@ -317,42 +224,25 @@ def load_surface_template_file(self, filename): with open(self.surface_template_file) as f: for line in f: template_file.append(line) - #print(f'load {filename}') return template_file def load_bulk_output_file(self, filename) : bulk_file = [] - #a = [] with open(self.bulk_output_file) as f: for line in f: line = line.replace("\t", " ").replace("\n", " ") line = line.encode().ljust(self.bulk_out_width_for_fortran) - #a.append(len(line)) bulk_file.append(line) bulk_f = np.array(bulk_file) - #self.bulk_file = np.array(bulk_file) - #print(f'load {filename}') return bulk_f def prepare(self, message: py2dmat.Message): if self.detail_timer is not None : time_sta = time.perf_counter() - # + x_list = message.x step = message.step iset = message.set - #### ADHOC_MPPING! ###" - adhoc_mapping = False - if adhoc_mapping: - if self.mpirank==0 and step==1: - print(f"NOTICE: adhoc_mapping is {adhoc_mapping}") - A_array = np.array( - [[1,2], - [3,4]] - ) - B_array = np.array([10,11]) - x_list = np.dot(A_array,x_list) + B_array - dimension = self.dimension string_list = self.string_list bulk_output_file = self.bulk_output_file @@ -363,16 +253,13 @@ def prepare(self, message: py2dmat.Message): fitted_value += format(x_list[index], ".8f") fitted_value = fitted_value[: len(string_list[index])] fitted_x_list.append(fitted_value) - #for index in range(dimension): - # print(string_list[index], "=", fitted_x_list[index]) - # + if self.detail_timer is not None : time_end = time.perf_counter() self.detail_timer["make_surf_input"] += time_end - time_sta - if self.detail_timer is not None : time_sta = time.perf_counter() - # + if self.generate_rocking_curve: folder_name = self._pre_bulk(step, bulk_output_file, iset) else: @@ -382,15 +269,15 @@ def prepare(self, message: py2dmat.Message): elif self.run_scheme == "subprocess": #make workdir and copy bulk output file folder_name = self._pre_bulk(step, bulk_output_file, iset) - # + if self.detail_timer is not None : time_end = time.perf_counter() self.detail_timer["prepare_Log-directory"] += time_end - time_sta if self.detail_timer is not None : time_sta = time.perf_counter() - # + self._replace(fitted_x_list, folder_name) - # + if self.detail_timer is not None : time_end = time.perf_counter() self.detail_timer["make_surf_input"] += time_end - time_sta @@ -420,12 +307,10 @@ def _replace(self, fitted_x_list, folder_name): fitted_x_list[index] ) - if self.run_scheme == "connect_so": line = line.replace("\t", " ").replace("\n", " ") line = line.encode().ljust(self.surf_tempalte_width_for_fortran) template_file.append(line) - #print(line) elif self.run_scheme == "subprocess": file_output.write(line) @@ -435,20 +320,6 @@ def _replace(self, fitted_x_list, folder_name): self.template_file = np.array(template_file) elif self.run_scheme == "subprocess": file_output.close() - - ''' - with open(self.surface_template_file, "r") as file_input, open( - os.path.join(folder_name, self.surface_input_file), "w" - ) as file_output: - for line in file_input: - for index in range(self.dimension): - if line.find(self.string_list[index]) != -1: - line = line.replace( - self.string_list[index], - fitted_x_list[index], - ) - file_output.write(line) - ''' def _check_template(self) -> None: found = [False] * self.dimension @@ -527,8 +398,6 @@ def __init__(self, info): self.row_number = v v = info_config.get("cal_number",None) - #print(v,type(v)) - #sys.exit() if v == None : raise exception.InputError( @@ -576,11 +445,7 @@ def __init__(self, info): ) self.spot_weight = np.array(v)/sum(v) - #debug - #print(f"spot_weight(non_norm) = {v}") - #print(f"self.spot_weight = {self.spot_weight}") - # solver.param info_param = info_s.get("param", {}) v = info_param.setdefault("string_list", ["value_01", "value_02"]) @@ -612,36 +477,18 @@ def __init__(self, info): lastline = v - # Read experiment-data - - #debug - #print(os.getcwd()) - #if False: - if True: - if self.mpirank == 0: - data_e = np.loadtxt(reference_path) - else: - data_e = None - data_experiment = self.mpicomm.bcast(data_e,root=0) - #print(data_experiment) - #print(data_experiment.dtype) - #print(data_experiment.shape) - #if self.mpirank == 0: - # print(len(data_e)==len(data_experiment)) - # print("for i in range(len(data_e))") - # for i in range(len(data_e)): - # print(data_e[i]==data_experiment[i]) - # print("end") - # print(data_e==data_experiment) + # Read experiment data + if self.mpirank == 0: + data_e = np.loadtxt(reference_path) else: - data_experiment = np.loadtxt(reference_path) + data_e = None + data_experiment = self.mpicomm.bcast(data_e,root=0) self.beam_number_experiment = data_experiment.shape[1] self.angle_number_experiment = data_experiment.shape[0] v = info_ref.get("exp_number", None) - #print(v,type(v)) - #sys.exit() + if v == None : raise exception.InputError( "ERROR: You have to set the 'exp_number'." @@ -666,21 +513,13 @@ def __init__(self, info): self.exp_number = v number_ex = self.exp_number sum_experiment = 0 - #for i in range(1,self.beam_number_experiment): for i in number_ex: sum_experiment += sum(data_experiment[::,i]) - #debug - #print(f'number_ex = {number_ex}') - self.degree_list = (data_experiment[::,0]) - #debug - #print("data_experiment=\n",data_experiment) self.all_reference_normalized = [] for index, j in enumerate(number_ex): self.reference = (data_experiment[::,j]) - #debug - #print(f'index,j={index},{j}\nself.reference=\n{self.reference}') self.reference_norm = 0.0 if self.normalization == "TOTAL": @@ -698,10 +537,6 @@ def __init__(self, info): else : # N-th loop self.reference_norm_1st = np.block([self.reference_norm_1st, np.sum(self.reference)]) self.reference_1st_normed = np.block([[self.reference_1st_normed],[self.reference/self.reference_norm_1st[-1]]]) - #debug - #print(f"j={j}") - #print(f"self.reference_1st_normed=\n{self.reference_1st_normed}") - #print(f"self.reference_norm_1st={self.reference_norm_1st}") elif self.normalization == "MS_NORM_SET_WGT": if index == 0: #first loop @@ -732,12 +567,6 @@ def __init__(self, info): self.all_reference_normalized.extend( self.reference_normed[-1,:].tolist() ) - #debug - #print(f"j={j},index={index}") - #print(f"self.reference_norm_l={self.reference_norm_l}") - #print(f"self.reference_normed_not_sptwgt=\n{self.reference_normed_not_sptwgt}") - #print(f"self.reference_normed=\n{self.reference_normed}") - #print(f"self.all_reference_normalized=\n{self.all_reference_normalized}") else: # self.normalization == "MAX": self.reference_norm = max(self.reference) @@ -746,13 +575,7 @@ def __init__(self, info): ] for p in self.reference_normalized: self.all_reference_normalized.append(p) - - #debug - #print('self.all_reference_normalized=') - #print(self.all_reference_normalized) - #print(f"self.reference_norm_1st=\n{self.reference_norm_1st}") - #print(f"self.reference_1st_normed=\n{self.reference_1st_normed}") - + def prepare(self, fitted_x_list): self.fitted_x_list = fitted_x_list @@ -770,20 +593,16 @@ def get_results(self, work_dir) -> float: #delete Log-directory if self.detail_timer is not None : time_sta = time.perf_counter() - # + if self.run_scheme == "subprocess": if self.remove_work_dir: def rmtree_error_handler(function, path, excinfo): print(f"WARNING: Failed to remove a working directory, {path}") shutil.rmtree(work_dir, onerror=rmtree_error_handler) - - elif self.run_scheme == "connect_so": - pass - # + if self.detail_timer is not None : time_end = time.perf_counter() self.detail_timer["delete_Log-directory"] += time_end - time_sta - ## return Rfactor @@ -798,14 +617,11 @@ def _post(self, fitted_x_list): convolution_I_calculated_list, ) = self._calc_I_from_file() - ### if self.detail_timer is not None : time_sta = time.perf_counter() Rfactor = self._calc_Rfactor(all_convolution_I_calculated_list_normalized) - #print("R-factor =", Rfactor) if self.detail_timer is not None : time_end = time.perf_counter() self.detail_timer["calculate_R-factor"] += time_end - time_sta - ### dimension = self.dimension string_list = self.string_list @@ -837,7 +653,6 @@ def _post(self, fitted_x_list): file_RC.write("\n") file_RC.write("#sum( I_(spot) ) = 1") file_RC.write("\n") - file_RC.write("#") file_RC.write("\n") @@ -861,54 +676,10 @@ def _post(self, fitted_x_list): fmt=fmt_rc ) - - if self.detail_timer is not None : time_end = time.perf_counter() self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta - """ - with open("RockingCurve.txt", "w") as file_RC: - I_experiment_list_normalized = self.reference_normalized - # Write headers - file_RC.write("#") - for index in range(dimension): - file_RC.write( - "{} = {} ".format(string_list[index], fitted_x_list[index]) - ) - file_RC.write("\n") - file_RC.write("#R-factor = {}\n".format(Rfactor)) - if self.normalization == "TOTAL": - file_RC.write("#I_calculated_total={}\n".format(I_calculated_norm)) - file_RC.write("#I_experiment_total={}\n".format(I_experiment_norm)) - else: # self.normalization == "MAX" - file_RC.write("#I_calculated_max={}\n".format(I_calculated_norm)) - file_RC.write("#I_experiment_max={}\n".format(I_experiment_norm)) - file_RC.write("#") - for xname in ( - "degree", - "convolution_I_calculated", - "I_experiment", - "convolution_I_calculated(normalized)", - "I_experiment(normalized)", - "I_calculated", - ): - file_RC.write(xname) - file_RC.write(" ") - file_RC.write("\n") - - # Write rocking curve - for index in range(len(degree_list)): - file_RC.write( - "{} {} {} {} {}\n".format( - degree_list[index], - convolution_I_calculated_list[index], - I_experiment_list[index], - all_convolution_I_calculated_list_normalized[index], - I_experiment_list_normalized[index], - ) - ) - """ return Rfactor def _g(self, x): @@ -919,7 +690,7 @@ def _g(self, x): def _calc_I_from_file(self): if self.detail_timer is not None : time_sta = time.perf_counter() - # + surface_output_file = self.surface_output_file calculated_first_line = self.calculated_first_line calculated_last_line = self.calculated_last_line @@ -928,11 +699,8 @@ def _calc_I_from_file(self): degree_list = self.degree_list nlines = calculated_last_line - calculated_first_line + 1 - # TODO: handling error assert 0 < nlines - # TODO: nlines == len(degree_list) ? - # assert nlines == len(degree_list) if self.run_scheme == "connect_so": Clines = self.surf_output @@ -940,48 +708,19 @@ def _calc_I_from_file(self): file_input = open(self.surface_output_file, "r") Clines = file_input.readlines() file_input.close() - # + if self.detail_timer is not None : time_end = time.perf_counter() self.detail_timer["load_STR_result"] += time_end - time_sta - - ##### convolution ##### - - """ - beam = [0,0,0.5,0,1.0,0,1.5,0,2.0,0] - bulk_data = np.loadtxt("/Users/ichinosehayato/mv_2DMAT/2DMAT_MB_ICHINOSE/sample/py2dmat/minsearch/bulk.txt") - denominator_H = float(bulk_data[0,0]) - denominator_K = float(bulk_data[0,1]) - for H in beam[0::2]: - beamnum_H = H*denominator_H - beamnum.append(beamnum_H) - for K in beam[1::2]: - beamnum_K = K*denominator_K - beamnum.append(beamnum_K) - break - print(beamnum) - - for n in beamnum[0::2]: - number.append(n*2) - print(number) - """ - - #print(os.getcwd()) - ############# if self.detail_timer is not None : time_sta = time.perf_counter() verbose_mode = False - #print("debug: Clines:",Clines) data_convolution = lib_make_convolution.calc( Clines, self.omega, verbose_mode ) - #print("data_convolution=") - #print(data_convolution) self.all_convolution_I_calculated_list_normalized = [] - #print(f"data_convolution=\n{data_convolution}") - #number = [7,8,9,10,11] number = self.cal_number angle_number_convolution = data_convolution.shape[0] self.glancing_angle = data_convolution[:,0] @@ -992,15 +731,10 @@ def _calc_I_from_file(self): ) self.beam_number_convolution = data_convolution.shape[1] - #for s in range(1,self.beam_number_convolution): sum_convolution = np.sum(data_convolution[:,number]) - #debug - #print(f'sum_convolution = {sum_convolution}') for i in range(len(number)): convolution_I_calculated_list = data_convolution[:,number[i]] - #debug - #print(f'convolution_I_calculated_list=\n{convolution_I_calculated_list}') if self.normalization == "TOTAL": I_calculated_norm = sum_convolution @@ -1008,7 +742,6 @@ def _calc_I_from_file(self): c / I_calculated_norm for c in convolution_I_calculated_list ] self.calc_rocking_curve = np.array([copy.deepcopy(convolution_I_calculated_list_normalized)]) - #print("convolution_I_calculated_list_normalized=",convolution_I_calculated_list_normalized) elif self.normalization == "MS_NORM": if i == 0: @@ -1021,12 +754,6 @@ def _calc_I_from_file(self): I_calc_norm_sum_spot = sum(convolution_I_calculated_list_normalized) self.reference_2nd_normed[i,:] *= I_calc_norm_sum_spot self.all_reference_normalized.extend(self.reference_2nd_normed[i,:].tolist()) - #debug - #print(f"i={i}, number[i]={number[i]}") - #print(f"convolution_I_calculated_list_normalized={convolution_I_calculated_list_normalized}") - #print(f"I_calc_norm_sum_spot={I_calc_norm_sum_spot}") - #print(f"self.reference_2nd_normed=\n{self.reference_2nd_normed}") - #print(f"self.all_reference_normalized={self.all_reference_normalized}") elif self.normalization == "MS_NORM_SET_WGT": if i == 0: #first loop @@ -1039,7 +766,6 @@ def _calc_I_from_file(self): convolution_I_calculated_list_normalized_array = self._multiply_spot_weight( self.convolution_I_calculated_list_normalized_not_spotwgt_array, self.spot_weight[i]) - #convolution_I_calculated_list_normalized = convolution_I_calculated_list_normalized_array[:].copy() else: # N-th loop I_calculated_norm = np.block( [I_calculated_norm, @@ -1057,12 +783,6 @@ def _calc_I_from_file(self): ) convolution_I_calculated_list_normalized = convolution_I_calculated_list_normalized_array[-1,:].copy() self.calc_rocking_curve = np.copy(self.convolution_I_calculated_list_normalized_not_spotwgt_array) - #debug - #print(f"i={i}, number[i]={number[i]}") - #print(f"I_calculated_norm={I_calculated_norm}") - #print(f"self.convolution_I_calculated_list_normalized_not_spotwgt_array=\n{self.convolution_I_calculated_list_normalized_not_spotwgt_array}") - #print(f"convolution_I_calculated_list_normalized_array=\n{convolution_I_calculated_list_normalized_array}") - #print(f"convolution_I_calculated_list_normalized=\n{convolution_I_calculated_list_normalized}") else: # self.normalization == "MAX" print('self.normalization == "MAX" mb対応検討中') @@ -1079,12 +799,6 @@ def _calc_I_from_file(self): time_end = time.perf_counter() self.detail_timer["convolution"] += time_end - time_sta - #debug - #print('self.all_convolution_I_calculated_list_normalized=') - #print(self.all_convolution_I_calculated_list_normalized) - - #print("self.all_convolution_I_calculated_list_normalized=") - #print(self.all_convolution_I_calculated_list_normalized) return ( self.all_convolution_I_calculated_list_normalized, I_calculated_norm, @@ -1104,9 +818,7 @@ def _calc_Rfactor(self, calc_result): R = 0.0 for I_exp, I_calc in zip(I_experiment_list_normalized, calc_result): R += (I_exp - I_calc) ** 2 - #debug - #print(f"I_exp, I_calc, I_exp-I_calc = {I_exp}, {I_calc}, {I_exp-I_calc}") - #print(f"R-factor = {R}") + else: # self.Rfactor_type == "B" y1 = 0.0 y2 = 0.0 From ad1c34c1dc79f0a1234a8f5342b7e91f385e48a5 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 13 Sep 2023 10:35:19 +0900 Subject: [PATCH 10/67] Add test data of sim_trepd_rheed_mb_connect. Created by N.Kinoshita (Tottori U). --- .../manybeam/mapper_ms_norm/MeshData.txt | 10 +++ .../manybeam/mapper_ms_norm/bulk.txt | 14 +++++ .../manybeam/mapper_ms_norm/experiment.txt | 61 +++++++++++++++++++ .../manybeam/mapper_ms_norm/input.toml | 43 +++++++++++++ .../manybeam/mapper_ms_norm/ref_ColorMap.txt | 10 +++ .../manybeam/mapper_ms_norm/template.txt | 16 +++++ .../mapper_ms_norm_set_wgt/MeshData.txt | 10 +++ .../manybeam/mapper_ms_norm_set_wgt/bulk.txt | 14 +++++ .../mapper_ms_norm_set_wgt/experiment.txt | 61 +++++++++++++++++++ .../mapper_ms_norm_set_wgt/input.toml | 44 +++++++++++++ .../mapper_ms_norm_set_wgt/ref_ColorMap.txt | 10 +++ .../mapper_ms_norm_set_wgt/template.txt | 16 +++++ .../manybeam/minsearch_ms_norm/bulk.txt | 14 +++++ .../manybeam/minsearch_ms_norm/experiment.txt | 61 +++++++++++++++++++ .../manybeam/minsearch_ms_norm/input.toml | 49 +++++++++++++++ .../manybeam/minsearch_ms_norm/ref.txt | 10 +++ .../manybeam/minsearch_ms_norm/template.txt | 16 +++++ .../minsearch_ms_norm_set_wgt/bulk.txt | 14 +++++ .../minsearch_ms_norm_set_wgt/experiment.txt | 61 +++++++++++++++++++ .../minsearch_ms_norm_set_wgt/input.toml | 50 +++++++++++++++ .../minsearch_ms_norm_set_wgt/ref.txt | 10 +++ .../minsearch_ms_norm_set_wgt/template.txt | 16 +++++ 22 files changed, 610 insertions(+) create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/MeshData.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/bulk.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/experiment.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/input.toml create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/ref_ColorMap.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/template.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/MeshData.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/bulk.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/experiment.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/input.toml create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/ref_ColorMap.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/template.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/bulk.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/experiment.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/input.toml create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/ref.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/template.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/bulk.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/experiment.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/input.toml create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/ref.txt create mode 100644 sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/template.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/MeshData.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/MeshData.txt new file mode 100644 index 00000000..71d1b50c --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/MeshData.txt @@ -0,0 +1,10 @@ +0 0.5 1.0 1.5 1.5 5.4 4.8 3.8 2.1 2.0 +1 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 +2 4.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 +3 5.0 4.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 +4 5.0 5.0 4.0 5.0 5.0 5.0 5.0 5.0 5.0 +5 5.0 5.0 5.0 4.0 5.0 5.0 5.0 5.0 5.0 +6 5.0 5.0 5.0 5.0 4.0 5.0 5.0 5.0 5.0 +7 5.0 5.0 5.0 5.0 5.0 4.0 5.0 5.0 5.0 +8 5.0 5.0 5.0 5.0 5.0 5.0 4.0 5.0 5.0 +9 5.0 5.0 5.0 5.0 5.0 5.0 5.0 4.0 5.0 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/bulk.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/bulk.txt new file mode 100644 index 00000000..a321798b --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/bulk.txt @@ -0,0 +1,14 @@ +2,1,2 ,NH,NK,NDOM, -------- Ge(001) bulk +7,15 ,(NB,I=1,NDOM) +0,90 ,(RDOM,I=1,NDOM) +0,0,0,1,0,-1,0,2,0,-2,0,3,0,-3 ,(IH(I),IK(I),I=1,NB) +0,0,1,0,-1,0,2,0,-2,0,3,0,-3,0,4,0,-4,0,5,0,-5,0,6,0,-6,0,7,0,-7,0 ,(IH(I),IK(I),I=1,NB) +10,0,0,0,0.3,6.3,0.1 ,BE,AZI,AZF,DAZ,GI,GF,DG +0.1,100 ,DZ,ML +1 ,NELM +32,1.2,0.15 ,Ge Z,da1,sap +0.4,0.4,0.4 ,BH(I),BK(I),BZ(I) +6,4.01319,4.01319,90,2.83770,0.5,0.5 ,NSG,AA,BB,GAM,CC,DX,DY +2 ,NATM +1,1.0,0.00000,0.50000, 2.12833 ,IELM(I),ocr(I),X(I),Y(I),Z(I) +1,1.0,0.00000,0.00000, 0.70948 ,IELM(I),ocr(I),X(I),Y(I),Z(I) diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/experiment.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/experiment.txt new file mode 100644 index 00000000..d2075d33 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/experiment.txt @@ -0,0 +1,61 @@ +3.00000e-01 8.20372e-03 2.54229e-06 2.54229e-06 9.88860e-15 9.88860e-15 6.88084e-33 6.88084e-33 4.60049e-54 4.60049e-54 4.51983e-87 4.51983e-87 3.53221e-125 3.53221e-125 2.28323e-173 2.28323e-173 +4.00000e-01 1.14751e-02 1.04244e-05 1.04244e-05 2.49203e-13 2.49203e-13 1.26542e-30 1.26542e-30 4.98289e-51 4.98289e-51 3.60151e-83 3.60151e-83 2.07188e-120 2.07188e-120 9.85900e-168 9.85900e-168 +5.00000e-01 1.46340e-02 3.58730e-05 3.58730e-05 5.04417e-12 5.04417e-12 1.86515e-28 1.86515e-28 4.32416e-48 4.32416e-48 2.29890e-79 2.29890e-79 9.73541e-116 9.73541e-116 3.41025e-162 3.41025e-162 +6.00000e-01 1.74036e-02 1.04606e-04 1.04606e-04 8.20593e-11 8.20593e-11 2.20358e-26 2.20358e-26 3.00666e-45 3.00666e-45 1.17553e-75 1.17553e-75 3.66450e-111 3.66450e-111 9.44952e-157 9.44952e-157 +7.00000e-01 1.96261e-02 2.61079e-04 2.61079e-04 1.07379e-09 1.07379e-09 2.08711e-24 2.08711e-24 1.67514e-42 1.67514e-42 4.81525e-72 4.81525e-72 1.10496e-106 1.10496e-106 2.09751e-151 2.09751e-151 +8.00000e-01 2.11810e-02 5.62998e-04 5.62998e-04 1.13137e-08 1.13137e-08 1.58509e-22 1.58509e-22 7.47877e-40 7.47877e-40 1.58009e-68 1.58009e-68 2.66901e-102 2.66901e-102 3.72967e-146 3.72967e-146 +9.00000e-01 2.19506e-02 1.05701e-03 1.05701e-03 9.61019e-08 9.61019e-08 9.65510e-21 9.65510e-21 2.67582e-37 2.67582e-37 4.15360e-65 4.15360e-65 5.16449e-98 5.16449e-98 5.31259e-141 5.31259e-141 +1.00000e+00 2.18837e-02 1.73666e-03 1.73666e-03 6.59148e-07 6.59148e-07 4.71837e-19 4.71837e-19 7.67314e-35 7.67314e-35 8.74678e-62 8.74678e-62 8.00527e-94 8.00527e-94 6.06197e-136 6.06197e-136 +1.10000e+00 2.11118e-02 2.50352e-03 2.50352e-03 3.65776e-06 3.65776e-06 1.85068e-17 1.85068e-17 1.76374e-32 1.76374e-32 1.47555e-58 1.47555e-58 9.94026e-90 9.94026e-90 5.54106e-131 5.54106e-131 +1.20000e+00 2.00197e-02 3.17036e-03 3.17036e-03 1.64630e-05 1.64630e-05 5.82895e-16 5.82895e-16 3.25019e-30 3.25019e-30 1.99411e-55 1.99411e-55 9.88767e-86 9.88767e-86 4.05736e-126 4.05736e-126 +1.30000e+00 1.91652e-02 3.53255e-03 3.53255e-03 6.02887e-05 6.02887e-05 1.47520e-14 1.47520e-14 4.80262e-28 4.80262e-28 2.15890e-52 2.15890e-52 7.87888e-82 7.87888e-82 2.37994e-121 2.37994e-121 +1.40000e+00 1.90127e-02 3.48189e-03 3.48189e-03 1.80376e-04 1.80376e-04 3.00236e-13 3.00236e-13 5.69175e-26 5.69175e-26 1.87246e-49 1.87246e-49 5.02934e-78 5.02934e-78 1.11831e-116 1.11831e-116 +1.50000e+00 1.95992e-02 3.08705e-03 3.08705e-03 4.43302e-04 4.43302e-04 4.91905e-12 4.91905e-12 5.41178e-24 5.41178e-24 1.30105e-46 1.30105e-46 2.57178e-74 2.57178e-74 4.20947e-112 4.20947e-112 +1.60000e+00 2.03890e-02 2.57618e-03 2.57618e-03 9.01644e-04 9.01644e-04 6.49662e-11 6.49662e-11 4.12970e-22 4.12970e-22 7.24244e-44 7.24244e-44 1.05351e-70 1.05351e-70 1.26931e-107 1.26931e-107 +1.70000e+00 2.05290e-02 2.22146e-03 2.22146e-03 1.53385e-03 1.53385e-03 6.92826e-10 6.92826e-10 2.53031e-20 2.53031e-20 3.22996e-41 3.22996e-41 3.45717e-67 3.45717e-67 3.06607e-103 3.06607e-103 +1.80000e+00 1.94096e-02 2.18932e-03 2.18932e-03 2.21633e-03 2.21633e-03 5.97919e-09 5.97919e-09 1.24551e-18 1.24551e-18 1.15409e-38 1.15409e-38 9.08840e-64 9.08840e-64 5.93296e-99 5.93296e-99 +1.90000e+00 1.71097e-02 2.45030e-03 2.45030e-03 2.78148e-03 2.78148e-03 4.18750e-08 4.18750e-08 4.92860e-17 4.92860e-17 3.30394e-36 3.30394e-36 1.91400e-60 1.91400e-60 9.19679e-95 9.19679e-95 +2.00000e+00 1.43591e-02 2.81912e-03 2.81912e-03 3.12490e-03 3.12490e-03 2.38836e-07 2.38836e-07 1.56913e-15 1.56913e-15 7.57864e-34 7.57864e-34 3.22913e-57 3.22913e-57 1.14203e-90 1.14203e-90 +2.10000e+00 1.20865e-02 3.10041e-03 3.10041e-03 3.25578e-03 3.25578e-03 1.11435e-06 1.11435e-06 4.02329e-14 4.02329e-14 1.39297e-31 1.39297e-31 4.36442e-54 4.36442e-54 1.13605e-86 1.13605e-86 +2.20000e+00 1.09633e-02 3.21399e-03 3.21399e-03 3.24916e-03 3.24916e-03 4.27726e-06 4.27726e-06 8.31769e-13 8.31769e-13 2.05172e-29 2.05172e-29 4.72574e-51 4.72574e-51 9.05318e-83 9.05318e-83 +2.30000e+00 1.12236e-02 3.19005e-03 3.19005e-03 3.17788e-03 3.17788e-03 1.36022e-05 1.36022e-05 1.38846e-11 1.38846e-11 2.42190e-27 2.42190e-27 4.09943e-48 4.09943e-48 5.77945e-79 5.77945e-79 +2.40000e+00 1.26847e-02 3.06482e-03 3.06482e-03 3.10461e-03 3.10461e-03 3.61631e-05 3.61631e-05 1.87457e-10 1.87457e-10 2.29143e-25 2.29143e-25 2.84903e-45 2.84903e-45 2.95569e-75 2.95569e-75 +2.50000e+00 1.47993e-02 2.81322e-03 2.81322e-03 3.10625e-03 3.10625e-03 8.13202e-05 8.13202e-05 2.05098e-09 2.05098e-09 1.73793e-23 1.73793e-23 1.58637e-42 1.58637e-42 1.21094e-71 1.21094e-71 +2.60000e+00 1.67805e-02 2.39686e-03 2.39686e-03 3.24955e-03 3.24955e-03 1.57036e-04 1.57036e-04 1.82269e-08 1.82269e-08 1.05686e-21 1.05686e-21 7.07715e-40 7.07715e-40 3.97449e-68 3.97449e-68 +2.70000e+00 1.79264e-02 1.85723e-03 1.85723e-03 3.51557e-03 3.51557e-03 2.65495e-04 2.65495e-04 1.31923e-07 1.31923e-07 5.15425e-20 5.15425e-20 2.52977e-37 2.52977e-37 1.04506e-64 1.04506e-64 +2.80000e+00 1.79907e-02 1.33093e-03 1.33093e-03 3.76876e-03 3.76876e-03 4.01966e-04 4.01966e-04 7.80115e-07 7.80115e-07 2.01655e-18 2.01655e-18 7.24591e-35 7.24591e-35 2.20148e-61 2.20148e-61 +2.90000e+00 1.72421e-02 9.65817e-04 9.65817e-04 3.83828e-03 3.83828e-03 5.57429e-04 5.57429e-04 3.78303e-06 3.78303e-06 6.33181e-17 6.33181e-17 1.66313e-32 1.66313e-32 3.71541e-58 3.71541e-58 +3.00000e+00 1.61322e-02 8.30083e-04 8.30083e-04 3.64961e-03 3.64961e-03 7.20742e-04 7.20742e-04 1.51116e-05 1.51116e-05 1.59643e-15 1.59643e-15 3.05929e-30 3.05929e-30 5.02379e-55 5.02379e-55 +3.10000e+00 1.49123e-02 8.92997e-04 8.92997e-04 3.27932e-03 3.27932e-03 8.78263e-04 8.78263e-04 5.00004e-05 5.00004e-05 3.23432e-14 3.23432e-14 4.51043e-28 4.51043e-28 5.44257e-52 5.44257e-52 +3.20000e+00 1.35465e-02 1.06737e-03 1.06737e-03 2.88348e-03 2.88348e-03 1.01433e-03 1.01433e-03 1.37994e-04 1.37994e-04 5.27039e-13 5.27039e-13 5.33063e-26 5.33063e-26 4.72436e-49 4.72436e-49 +3.30000e+00 1.19172e-02 1.26022e-03 1.26022e-03 2.57067e-03 2.57067e-03 1.11335e-03 1.11335e-03 3.20529e-04 3.20529e-04 6.91671e-12 6.91671e-12 5.05096e-24 5.05096e-24 3.28603e-46 3.28603e-46 +3.40000e+00 1.00537e-02 1.40135e-03 1.40135e-03 2.33714e-03 2.33714e-03 1.15940e-03 1.15940e-03 6.33766e-04 6.33766e-04 7.32418e-11 7.32418e-11 3.83791e-22 3.83791e-22 1.83156e-43 1.83156e-43 +3.50000e+00 8.17053e-03 1.45385e-03 1.45385e-03 2.12304e-03 2.12304e-03 1.13607e-03 1.13607e-03 1.08143e-03 1.08143e-03 6.27478e-10 6.27478e-10 2.33911e-20 2.33911e-20 8.18137e-41 8.18137e-41 +3.60000e+00 6.53572e-03 1.41927e-03 1.41927e-03 1.92999e-03 1.92999e-03 1.03519e-03 1.03519e-03 1.61626e-03 1.61626e-03 4.36723e-09 4.36723e-09 1.14389e-18 1.14389e-18 2.92909e-38 2.92909e-38 +3.70000e+00 5.35999e-03 1.33367e-03 1.33367e-03 1.86928e-03 1.86928e-03 8.70233e-04 8.70233e-04 2.14410e-03 2.14410e-03 2.48549e-08 2.48549e-08 4.49016e-17 4.49016e-17 8.40612e-36 8.40612e-36 +3.80000e+00 4.81712e-03 1.24066e-03 1.24066e-03 2.07870e-03 2.07870e-03 6.75861e-04 6.75861e-04 2.54646e-03 2.54646e-03 1.16900e-07 1.16900e-07 1.41547e-15 1.41547e-15 1.93413e-33 1.93413e-33 +3.90000e+00 5.09106e-03 1.15259e-03 1.15259e-03 2.58615e-03 2.58615e-03 4.89391e-04 4.89391e-04 2.71476e-03 2.71476e-03 4.62218e-07 4.62218e-07 3.58560e-14 3.58560e-14 3.56849e-31 3.56849e-31 +4.00000e+00 6.27917e-03 1.04113e-03 1.04113e-03 3.25723e-03 3.25723e-03 3.33325e-04 3.33325e-04 2.59542e-03 2.59542e-03 1.57650e-06 1.57650e-06 7.30420e-13 7.30420e-13 5.28077e-29 5.28077e-29 +4.10000e+00 8.18460e-03 8.74899e-04 8.74899e-04 3.88244e-03 3.88244e-03 2.14609e-04 2.14609e-04 2.22842e-03 2.22842e-03 4.79133e-06 4.79133e-06 1.19766e-11 1.19766e-11 6.26976e-27 6.26976e-27 +4.20000e+00 1.02521e-02 6.63215e-04 6.63215e-04 4.31701e-03 4.31701e-03 1.33479e-04 1.33479e-04 1.74106e-03 1.74106e-03 1.33460e-05 1.33460e-05 1.58248e-10 1.58248e-10 5.97443e-25 5.97443e-25 +4.30000e+00 1.18201e-02 4.56534e-04 4.56534e-04 4.53705e-03 4.53705e-03 8.83076e-05 8.83076e-05 1.28846e-03 1.28846e-03 3.43304e-05 3.43304e-05 1.68730e-09 1.68730e-09 4.57109e-23 4.57109e-23 +4.40000e+00 1.25166e-02 3.07901e-04 3.07901e-04 4.58438e-03 4.58438e-03 7.48076e-05 7.48076e-05 9.85554e-04 9.85554e-04 8.01387e-05 8.01387e-05 1.45425e-08 1.45425e-08 2.80956e-21 2.80956e-21 +4.50000e+00 1.24346e-02 2.39831e-04 2.39831e-04 4.49553e-03 4.49553e-03 8.47877e-05 8.47877e-05 8.78596e-04 8.78596e-04 1.64859e-04 1.64859e-04 1.01531e-07 1.01531e-07 1.38807e-19 1.38807e-19 +4.60000e+00 1.19322e-02 2.40983e-04 2.40983e-04 4.28955e-03 4.28955e-03 1.06907e-04 1.06907e-04 9.55939e-04 9.55939e-04 2.91399e-04 2.91399e-04 5.75738e-07 5.75738e-07 5.51622e-18 5.51622e-18 +4.70000e+00 1.12782e-02 2.80574e-04 2.80574e-04 3.99474e-03 3.99474e-03 1.30423e-04 1.30423e-04 1.16635e-03 1.16635e-03 4.36262e-04 4.36262e-04 2.66058e-06 2.66058e-06 1.76470e-16 1.76470e-16 +4.80000e+00 1.04800e-02 3.23137e-04 3.23137e-04 3.66468e-03 3.66468e-03 1.51930e-04 1.51930e-04 1.42843e-03 1.42843e-03 5.51828e-04 5.51828e-04 1.00645e-05 1.00645e-05 4.54869e-15 4.54869e-15 +4.90000e+00 9.40087e-03 3.40575e-04 3.40575e-04 3.35809e-03 3.35809e-03 1.78878e-04 1.78878e-04 1.64275e-03 1.64275e-03 5.95529e-04 5.95529e-04 3.13600e-05 3.13600e-05 9.45602e-14 9.45602e-14 +5.00000e+00 7.98100e-03 3.21858e-04 3.21858e-04 3.09388e-03 3.09388e-03 2.21316e-04 2.21316e-04 1.72244e-03 1.72244e-03 5.62367e-04 5.62367e-04 8.12272e-05 8.12272e-05 1.58702e-12 1.58702e-12 +5.10000e+00 6.33564e-03 2.75141e-04 2.75141e-04 2.83349e-03 2.83349e-03 2.75830e-04 2.75830e-04 1.63475e-03 1.63475e-03 4.86986e-04 4.86986e-04 1.77338e-04 1.77338e-04 2.15260e-11 2.15260e-11 +5.20000e+00 4.69185e-03 2.20277e-04 2.20277e-04 2.53384e-03 2.53384e-03 3.20101e-04 3.20101e-04 1.42421e-03 1.42421e-03 4.14585e-04 4.14585e-04 3.33162e-04 3.33162e-04 2.36204e-10 2.36204e-10 +5.30000e+00 3.27797e-03 1.79027e-04 1.79027e-04 2.23107e-03 2.23107e-03 3.29667e-04 3.29667e-04 1.19533e-03 1.19533e-03 3.71111e-04 3.71111e-04 5.53645e-04 5.53645e-04 2.09869e-09 2.09869e-09 +5.40000e+00 2.24753e-03 1.70825e-04 1.70825e-04 2.05873e-03 2.05873e-03 3.03413e-04 3.03413e-04 1.06400e-03 1.06400e-03 3.55457e-04 3.55457e-04 8.37552e-04 8.37552e-04 1.51103e-08 1.51103e-08 +5.50000e+00 1.64073e-03 2.12816e-04 2.12816e-04 2.15862e-03 2.15862e-03 2.71480e-04 2.71480e-04 1.10647e-03 1.10647e-03 3.52311e-04 3.52311e-04 1.17414e-03 1.17414e-03 8.82030e-08 8.82030e-08 +5.60000e+00 1.38305e-03 3.15679e-04 3.15679e-04 2.54923e-03 2.54923e-03 2.75242e-04 2.75242e-04 1.32726e-03 1.32726e-03 3.51425e-04 3.51425e-04 1.52290e-03 1.52290e-03 4.17530e-07 4.17530e-07 +5.70000e+00 1.33614e-03 4.70705e-04 4.70705e-04 3.06735e-03 3.06735e-03 3.34875e-04 3.34875e-04 1.65095e-03 1.65095e-03 3.56333e-04 3.56333e-04 1.80197e-03 1.80197e-03 1.60275e-06 1.60275e-06 +5.80000e+00 1.37924e-03 6.38137e-04 6.38137e-04 3.44882e-03 3.44882e-03 4.30290e-04 4.30290e-04 1.94223e-03 1.94223e-03 3.73991e-04 3.73991e-04 1.92617e-03 1.92617e-03 4.98731e-06 4.98731e-06 +5.90000e+00 1.45483e-03 7.55599e-04 7.55599e-04 3.49617e-03 3.49617e-03 5.11150e-04 5.11150e-04 2.06289e-03 2.06289e-03 3.97725e-04 3.97725e-04 1.87370e-03 1.87370e-03 1.25727e-05 1.25727e-05 +6.00000e+00 1.53948e-03 7.70601e-04 7.70601e-04 3.19202e-03 3.19202e-03 5.29865e-04 5.29865e-04 1.94599e-03 1.94599e-03 4.05916e-04 4.05916e-04 1.70002e-03 1.70002e-03 2.56570e-05 2.56570e-05 +6.10000e+00 1.58568e-03 6.73822e-04 6.73822e-04 2.66436e-03 2.66436e-03 4.72139e-04 4.72139e-04 1.62943e-03 1.62943e-03 3.79582e-04 3.79582e-04 1.47514e-03 1.47514e-03 4.23429e-05 4.23429e-05 +6.20000e+00 1.51599e-03 5.04199e-04 5.04199e-04 2.06232e-03 2.06232e-03 3.61528e-04 3.61528e-04 1.21767e-03 1.21767e-03 3.17962e-04 3.17962e-04 1.22482e-03 1.22482e-03 5.64558e-05 5.64558e-05 +6.30000e+00 1.28486e-03 3.22258e-04 3.22258e-04 1.47827e-03 1.47827e-03 2.38643e-04 2.38643e-04 8.14408e-04 8.14408e-04 2.36637e-04 2.36637e-04 9.44342e-04 9.44342e-04 6.07488e-05 6.07488e-05 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/input.toml b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/input.toml new file mode 100644 index 00000000..228104b8 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/input.toml @@ -0,0 +1,43 @@ +[base] +dimension = 9 +output_dir = "output" + +[solver] +name = "sim-trhepd-rheed-mb_connect" +run_scheme = "subprocess" +generate_rocking_curve = false + +[solver.config] +#calculated_first_line =5 +#calculated_last_line = 65 +#row_number = 2 +surface_exec_file = "~/tool/sim-trhepd-rheed/src/surf.exe" +bulk_output_file = "bulkP.b" +surface_template_file = "template.txt" +cal_number = [1, 2, 4, 6, 8] + + +[solver.post] +normalization = "MS_NORM" #"TOTAL" for Integration or "MAX" for MAX value +Rfactor_type = "A2" #"A" for Ichimiya's or "B" for Pendry's or "A2" for squared Weight + Ichimiya's +omega = 0.5 +remove_work_dir = false + +[solver.param] +string_list = ["value_01", "value_02","value_03", "value_04","value_05", "value_06", "value_07","value_08", "value_09"] +#degree_max = 6.5 + + +[solver.reference] +path = "experiment.txt" +exp_number = [1, 2, 4, 6, 8] +#first =1 +#last = 63 + + +[algorithm] +name = "mapper" +label_list = ["X1", "X2", "X3", "Y3", "Z1", "Z2", "Z3", "Z4", "Z5"] + +[algorithm.param] +mesh_path = "MeshData.txt" diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/ref_ColorMap.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/ref_ColorMap.txt new file mode 100644 index 00000000..81dd323e --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/ref_ColorMap.txt @@ -0,0 +1,10 @@ +0.500000 1.000000 1.500000 1.500000 5.400000 4.800000 3.800000 2.100000 2.000000 0.000000 +5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.001948 +4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.001807 +5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.001807 +5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.001808 +5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.001948 +5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 0.002115 +5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 0.002115 +5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 0.002114 +5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 0.001927 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/template.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/template.txt new file mode 100644 index 00000000..8469cd87 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/template.txt @@ -0,0 +1,16 @@ +2 ,NELMS, -------- Ge(001)-c4x2 +32,1.2,0.15 ,Ge Z,da1,sap +0.6,0.6,0.6 ,BH(I),BK(I),BZ(I) +32,1.2,0.15 ,Ge Z,da1,sap +0.4,0.4,0.4 ,BH(I),BK(I),BZ(I) +9,4,0,0,2,1.7,-0.5,0.5 ,NSGS,msa,msb,nsa,nsb,dthick,DXS,DYS +8 ,NATM +1, 1.0, value_01, 1.00000, value_05 ,IELM(I),ocr(I),X(I),Y(I),Z(I +1, 1.0, value_02, 1.00000, value_06 +2, 1.0, value_03, value_04, value_07 +2, 1.0, 2.00000, 1.49751, value_08 +2, 1.0, 1.00000, 1.50000, value_09 +2, 1.0, 0.00000, 1.00000, 0.849425 +2, 1.0, 2.00000, 1.00000, 0.809425 +2, 1.0, 1.00997, 1.00000, 0.599425 +1,1 ,(WDOM,I=1,NDOM) diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/MeshData.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/MeshData.txt new file mode 100644 index 00000000..71d1b50c --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/MeshData.txt @@ -0,0 +1,10 @@ +0 0.5 1.0 1.5 1.5 5.4 4.8 3.8 2.1 2.0 +1 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 +2 4.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 +3 5.0 4.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 +4 5.0 5.0 4.0 5.0 5.0 5.0 5.0 5.0 5.0 +5 5.0 5.0 5.0 4.0 5.0 5.0 5.0 5.0 5.0 +6 5.0 5.0 5.0 5.0 4.0 5.0 5.0 5.0 5.0 +7 5.0 5.0 5.0 5.0 5.0 4.0 5.0 5.0 5.0 +8 5.0 5.0 5.0 5.0 5.0 5.0 4.0 5.0 5.0 +9 5.0 5.0 5.0 5.0 5.0 5.0 5.0 4.0 5.0 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/bulk.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/bulk.txt new file mode 100644 index 00000000..a321798b --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/bulk.txt @@ -0,0 +1,14 @@ +2,1,2 ,NH,NK,NDOM, -------- Ge(001) bulk +7,15 ,(NB,I=1,NDOM) +0,90 ,(RDOM,I=1,NDOM) +0,0,0,1,0,-1,0,2,0,-2,0,3,0,-3 ,(IH(I),IK(I),I=1,NB) +0,0,1,0,-1,0,2,0,-2,0,3,0,-3,0,4,0,-4,0,5,0,-5,0,6,0,-6,0,7,0,-7,0 ,(IH(I),IK(I),I=1,NB) +10,0,0,0,0.3,6.3,0.1 ,BE,AZI,AZF,DAZ,GI,GF,DG +0.1,100 ,DZ,ML +1 ,NELM +32,1.2,0.15 ,Ge Z,da1,sap +0.4,0.4,0.4 ,BH(I),BK(I),BZ(I) +6,4.01319,4.01319,90,2.83770,0.5,0.5 ,NSG,AA,BB,GAM,CC,DX,DY +2 ,NATM +1,1.0,0.00000,0.50000, 2.12833 ,IELM(I),ocr(I),X(I),Y(I),Z(I) +1,1.0,0.00000,0.00000, 0.70948 ,IELM(I),ocr(I),X(I),Y(I),Z(I) diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/experiment.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/experiment.txt new file mode 100644 index 00000000..d2075d33 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/experiment.txt @@ -0,0 +1,61 @@ +3.00000e-01 8.20372e-03 2.54229e-06 2.54229e-06 9.88860e-15 9.88860e-15 6.88084e-33 6.88084e-33 4.60049e-54 4.60049e-54 4.51983e-87 4.51983e-87 3.53221e-125 3.53221e-125 2.28323e-173 2.28323e-173 +4.00000e-01 1.14751e-02 1.04244e-05 1.04244e-05 2.49203e-13 2.49203e-13 1.26542e-30 1.26542e-30 4.98289e-51 4.98289e-51 3.60151e-83 3.60151e-83 2.07188e-120 2.07188e-120 9.85900e-168 9.85900e-168 +5.00000e-01 1.46340e-02 3.58730e-05 3.58730e-05 5.04417e-12 5.04417e-12 1.86515e-28 1.86515e-28 4.32416e-48 4.32416e-48 2.29890e-79 2.29890e-79 9.73541e-116 9.73541e-116 3.41025e-162 3.41025e-162 +6.00000e-01 1.74036e-02 1.04606e-04 1.04606e-04 8.20593e-11 8.20593e-11 2.20358e-26 2.20358e-26 3.00666e-45 3.00666e-45 1.17553e-75 1.17553e-75 3.66450e-111 3.66450e-111 9.44952e-157 9.44952e-157 +7.00000e-01 1.96261e-02 2.61079e-04 2.61079e-04 1.07379e-09 1.07379e-09 2.08711e-24 2.08711e-24 1.67514e-42 1.67514e-42 4.81525e-72 4.81525e-72 1.10496e-106 1.10496e-106 2.09751e-151 2.09751e-151 +8.00000e-01 2.11810e-02 5.62998e-04 5.62998e-04 1.13137e-08 1.13137e-08 1.58509e-22 1.58509e-22 7.47877e-40 7.47877e-40 1.58009e-68 1.58009e-68 2.66901e-102 2.66901e-102 3.72967e-146 3.72967e-146 +9.00000e-01 2.19506e-02 1.05701e-03 1.05701e-03 9.61019e-08 9.61019e-08 9.65510e-21 9.65510e-21 2.67582e-37 2.67582e-37 4.15360e-65 4.15360e-65 5.16449e-98 5.16449e-98 5.31259e-141 5.31259e-141 +1.00000e+00 2.18837e-02 1.73666e-03 1.73666e-03 6.59148e-07 6.59148e-07 4.71837e-19 4.71837e-19 7.67314e-35 7.67314e-35 8.74678e-62 8.74678e-62 8.00527e-94 8.00527e-94 6.06197e-136 6.06197e-136 +1.10000e+00 2.11118e-02 2.50352e-03 2.50352e-03 3.65776e-06 3.65776e-06 1.85068e-17 1.85068e-17 1.76374e-32 1.76374e-32 1.47555e-58 1.47555e-58 9.94026e-90 9.94026e-90 5.54106e-131 5.54106e-131 +1.20000e+00 2.00197e-02 3.17036e-03 3.17036e-03 1.64630e-05 1.64630e-05 5.82895e-16 5.82895e-16 3.25019e-30 3.25019e-30 1.99411e-55 1.99411e-55 9.88767e-86 9.88767e-86 4.05736e-126 4.05736e-126 +1.30000e+00 1.91652e-02 3.53255e-03 3.53255e-03 6.02887e-05 6.02887e-05 1.47520e-14 1.47520e-14 4.80262e-28 4.80262e-28 2.15890e-52 2.15890e-52 7.87888e-82 7.87888e-82 2.37994e-121 2.37994e-121 +1.40000e+00 1.90127e-02 3.48189e-03 3.48189e-03 1.80376e-04 1.80376e-04 3.00236e-13 3.00236e-13 5.69175e-26 5.69175e-26 1.87246e-49 1.87246e-49 5.02934e-78 5.02934e-78 1.11831e-116 1.11831e-116 +1.50000e+00 1.95992e-02 3.08705e-03 3.08705e-03 4.43302e-04 4.43302e-04 4.91905e-12 4.91905e-12 5.41178e-24 5.41178e-24 1.30105e-46 1.30105e-46 2.57178e-74 2.57178e-74 4.20947e-112 4.20947e-112 +1.60000e+00 2.03890e-02 2.57618e-03 2.57618e-03 9.01644e-04 9.01644e-04 6.49662e-11 6.49662e-11 4.12970e-22 4.12970e-22 7.24244e-44 7.24244e-44 1.05351e-70 1.05351e-70 1.26931e-107 1.26931e-107 +1.70000e+00 2.05290e-02 2.22146e-03 2.22146e-03 1.53385e-03 1.53385e-03 6.92826e-10 6.92826e-10 2.53031e-20 2.53031e-20 3.22996e-41 3.22996e-41 3.45717e-67 3.45717e-67 3.06607e-103 3.06607e-103 +1.80000e+00 1.94096e-02 2.18932e-03 2.18932e-03 2.21633e-03 2.21633e-03 5.97919e-09 5.97919e-09 1.24551e-18 1.24551e-18 1.15409e-38 1.15409e-38 9.08840e-64 9.08840e-64 5.93296e-99 5.93296e-99 +1.90000e+00 1.71097e-02 2.45030e-03 2.45030e-03 2.78148e-03 2.78148e-03 4.18750e-08 4.18750e-08 4.92860e-17 4.92860e-17 3.30394e-36 3.30394e-36 1.91400e-60 1.91400e-60 9.19679e-95 9.19679e-95 +2.00000e+00 1.43591e-02 2.81912e-03 2.81912e-03 3.12490e-03 3.12490e-03 2.38836e-07 2.38836e-07 1.56913e-15 1.56913e-15 7.57864e-34 7.57864e-34 3.22913e-57 3.22913e-57 1.14203e-90 1.14203e-90 +2.10000e+00 1.20865e-02 3.10041e-03 3.10041e-03 3.25578e-03 3.25578e-03 1.11435e-06 1.11435e-06 4.02329e-14 4.02329e-14 1.39297e-31 1.39297e-31 4.36442e-54 4.36442e-54 1.13605e-86 1.13605e-86 +2.20000e+00 1.09633e-02 3.21399e-03 3.21399e-03 3.24916e-03 3.24916e-03 4.27726e-06 4.27726e-06 8.31769e-13 8.31769e-13 2.05172e-29 2.05172e-29 4.72574e-51 4.72574e-51 9.05318e-83 9.05318e-83 +2.30000e+00 1.12236e-02 3.19005e-03 3.19005e-03 3.17788e-03 3.17788e-03 1.36022e-05 1.36022e-05 1.38846e-11 1.38846e-11 2.42190e-27 2.42190e-27 4.09943e-48 4.09943e-48 5.77945e-79 5.77945e-79 +2.40000e+00 1.26847e-02 3.06482e-03 3.06482e-03 3.10461e-03 3.10461e-03 3.61631e-05 3.61631e-05 1.87457e-10 1.87457e-10 2.29143e-25 2.29143e-25 2.84903e-45 2.84903e-45 2.95569e-75 2.95569e-75 +2.50000e+00 1.47993e-02 2.81322e-03 2.81322e-03 3.10625e-03 3.10625e-03 8.13202e-05 8.13202e-05 2.05098e-09 2.05098e-09 1.73793e-23 1.73793e-23 1.58637e-42 1.58637e-42 1.21094e-71 1.21094e-71 +2.60000e+00 1.67805e-02 2.39686e-03 2.39686e-03 3.24955e-03 3.24955e-03 1.57036e-04 1.57036e-04 1.82269e-08 1.82269e-08 1.05686e-21 1.05686e-21 7.07715e-40 7.07715e-40 3.97449e-68 3.97449e-68 +2.70000e+00 1.79264e-02 1.85723e-03 1.85723e-03 3.51557e-03 3.51557e-03 2.65495e-04 2.65495e-04 1.31923e-07 1.31923e-07 5.15425e-20 5.15425e-20 2.52977e-37 2.52977e-37 1.04506e-64 1.04506e-64 +2.80000e+00 1.79907e-02 1.33093e-03 1.33093e-03 3.76876e-03 3.76876e-03 4.01966e-04 4.01966e-04 7.80115e-07 7.80115e-07 2.01655e-18 2.01655e-18 7.24591e-35 7.24591e-35 2.20148e-61 2.20148e-61 +2.90000e+00 1.72421e-02 9.65817e-04 9.65817e-04 3.83828e-03 3.83828e-03 5.57429e-04 5.57429e-04 3.78303e-06 3.78303e-06 6.33181e-17 6.33181e-17 1.66313e-32 1.66313e-32 3.71541e-58 3.71541e-58 +3.00000e+00 1.61322e-02 8.30083e-04 8.30083e-04 3.64961e-03 3.64961e-03 7.20742e-04 7.20742e-04 1.51116e-05 1.51116e-05 1.59643e-15 1.59643e-15 3.05929e-30 3.05929e-30 5.02379e-55 5.02379e-55 +3.10000e+00 1.49123e-02 8.92997e-04 8.92997e-04 3.27932e-03 3.27932e-03 8.78263e-04 8.78263e-04 5.00004e-05 5.00004e-05 3.23432e-14 3.23432e-14 4.51043e-28 4.51043e-28 5.44257e-52 5.44257e-52 +3.20000e+00 1.35465e-02 1.06737e-03 1.06737e-03 2.88348e-03 2.88348e-03 1.01433e-03 1.01433e-03 1.37994e-04 1.37994e-04 5.27039e-13 5.27039e-13 5.33063e-26 5.33063e-26 4.72436e-49 4.72436e-49 +3.30000e+00 1.19172e-02 1.26022e-03 1.26022e-03 2.57067e-03 2.57067e-03 1.11335e-03 1.11335e-03 3.20529e-04 3.20529e-04 6.91671e-12 6.91671e-12 5.05096e-24 5.05096e-24 3.28603e-46 3.28603e-46 +3.40000e+00 1.00537e-02 1.40135e-03 1.40135e-03 2.33714e-03 2.33714e-03 1.15940e-03 1.15940e-03 6.33766e-04 6.33766e-04 7.32418e-11 7.32418e-11 3.83791e-22 3.83791e-22 1.83156e-43 1.83156e-43 +3.50000e+00 8.17053e-03 1.45385e-03 1.45385e-03 2.12304e-03 2.12304e-03 1.13607e-03 1.13607e-03 1.08143e-03 1.08143e-03 6.27478e-10 6.27478e-10 2.33911e-20 2.33911e-20 8.18137e-41 8.18137e-41 +3.60000e+00 6.53572e-03 1.41927e-03 1.41927e-03 1.92999e-03 1.92999e-03 1.03519e-03 1.03519e-03 1.61626e-03 1.61626e-03 4.36723e-09 4.36723e-09 1.14389e-18 1.14389e-18 2.92909e-38 2.92909e-38 +3.70000e+00 5.35999e-03 1.33367e-03 1.33367e-03 1.86928e-03 1.86928e-03 8.70233e-04 8.70233e-04 2.14410e-03 2.14410e-03 2.48549e-08 2.48549e-08 4.49016e-17 4.49016e-17 8.40612e-36 8.40612e-36 +3.80000e+00 4.81712e-03 1.24066e-03 1.24066e-03 2.07870e-03 2.07870e-03 6.75861e-04 6.75861e-04 2.54646e-03 2.54646e-03 1.16900e-07 1.16900e-07 1.41547e-15 1.41547e-15 1.93413e-33 1.93413e-33 +3.90000e+00 5.09106e-03 1.15259e-03 1.15259e-03 2.58615e-03 2.58615e-03 4.89391e-04 4.89391e-04 2.71476e-03 2.71476e-03 4.62218e-07 4.62218e-07 3.58560e-14 3.58560e-14 3.56849e-31 3.56849e-31 +4.00000e+00 6.27917e-03 1.04113e-03 1.04113e-03 3.25723e-03 3.25723e-03 3.33325e-04 3.33325e-04 2.59542e-03 2.59542e-03 1.57650e-06 1.57650e-06 7.30420e-13 7.30420e-13 5.28077e-29 5.28077e-29 +4.10000e+00 8.18460e-03 8.74899e-04 8.74899e-04 3.88244e-03 3.88244e-03 2.14609e-04 2.14609e-04 2.22842e-03 2.22842e-03 4.79133e-06 4.79133e-06 1.19766e-11 1.19766e-11 6.26976e-27 6.26976e-27 +4.20000e+00 1.02521e-02 6.63215e-04 6.63215e-04 4.31701e-03 4.31701e-03 1.33479e-04 1.33479e-04 1.74106e-03 1.74106e-03 1.33460e-05 1.33460e-05 1.58248e-10 1.58248e-10 5.97443e-25 5.97443e-25 +4.30000e+00 1.18201e-02 4.56534e-04 4.56534e-04 4.53705e-03 4.53705e-03 8.83076e-05 8.83076e-05 1.28846e-03 1.28846e-03 3.43304e-05 3.43304e-05 1.68730e-09 1.68730e-09 4.57109e-23 4.57109e-23 +4.40000e+00 1.25166e-02 3.07901e-04 3.07901e-04 4.58438e-03 4.58438e-03 7.48076e-05 7.48076e-05 9.85554e-04 9.85554e-04 8.01387e-05 8.01387e-05 1.45425e-08 1.45425e-08 2.80956e-21 2.80956e-21 +4.50000e+00 1.24346e-02 2.39831e-04 2.39831e-04 4.49553e-03 4.49553e-03 8.47877e-05 8.47877e-05 8.78596e-04 8.78596e-04 1.64859e-04 1.64859e-04 1.01531e-07 1.01531e-07 1.38807e-19 1.38807e-19 +4.60000e+00 1.19322e-02 2.40983e-04 2.40983e-04 4.28955e-03 4.28955e-03 1.06907e-04 1.06907e-04 9.55939e-04 9.55939e-04 2.91399e-04 2.91399e-04 5.75738e-07 5.75738e-07 5.51622e-18 5.51622e-18 +4.70000e+00 1.12782e-02 2.80574e-04 2.80574e-04 3.99474e-03 3.99474e-03 1.30423e-04 1.30423e-04 1.16635e-03 1.16635e-03 4.36262e-04 4.36262e-04 2.66058e-06 2.66058e-06 1.76470e-16 1.76470e-16 +4.80000e+00 1.04800e-02 3.23137e-04 3.23137e-04 3.66468e-03 3.66468e-03 1.51930e-04 1.51930e-04 1.42843e-03 1.42843e-03 5.51828e-04 5.51828e-04 1.00645e-05 1.00645e-05 4.54869e-15 4.54869e-15 +4.90000e+00 9.40087e-03 3.40575e-04 3.40575e-04 3.35809e-03 3.35809e-03 1.78878e-04 1.78878e-04 1.64275e-03 1.64275e-03 5.95529e-04 5.95529e-04 3.13600e-05 3.13600e-05 9.45602e-14 9.45602e-14 +5.00000e+00 7.98100e-03 3.21858e-04 3.21858e-04 3.09388e-03 3.09388e-03 2.21316e-04 2.21316e-04 1.72244e-03 1.72244e-03 5.62367e-04 5.62367e-04 8.12272e-05 8.12272e-05 1.58702e-12 1.58702e-12 +5.10000e+00 6.33564e-03 2.75141e-04 2.75141e-04 2.83349e-03 2.83349e-03 2.75830e-04 2.75830e-04 1.63475e-03 1.63475e-03 4.86986e-04 4.86986e-04 1.77338e-04 1.77338e-04 2.15260e-11 2.15260e-11 +5.20000e+00 4.69185e-03 2.20277e-04 2.20277e-04 2.53384e-03 2.53384e-03 3.20101e-04 3.20101e-04 1.42421e-03 1.42421e-03 4.14585e-04 4.14585e-04 3.33162e-04 3.33162e-04 2.36204e-10 2.36204e-10 +5.30000e+00 3.27797e-03 1.79027e-04 1.79027e-04 2.23107e-03 2.23107e-03 3.29667e-04 3.29667e-04 1.19533e-03 1.19533e-03 3.71111e-04 3.71111e-04 5.53645e-04 5.53645e-04 2.09869e-09 2.09869e-09 +5.40000e+00 2.24753e-03 1.70825e-04 1.70825e-04 2.05873e-03 2.05873e-03 3.03413e-04 3.03413e-04 1.06400e-03 1.06400e-03 3.55457e-04 3.55457e-04 8.37552e-04 8.37552e-04 1.51103e-08 1.51103e-08 +5.50000e+00 1.64073e-03 2.12816e-04 2.12816e-04 2.15862e-03 2.15862e-03 2.71480e-04 2.71480e-04 1.10647e-03 1.10647e-03 3.52311e-04 3.52311e-04 1.17414e-03 1.17414e-03 8.82030e-08 8.82030e-08 +5.60000e+00 1.38305e-03 3.15679e-04 3.15679e-04 2.54923e-03 2.54923e-03 2.75242e-04 2.75242e-04 1.32726e-03 1.32726e-03 3.51425e-04 3.51425e-04 1.52290e-03 1.52290e-03 4.17530e-07 4.17530e-07 +5.70000e+00 1.33614e-03 4.70705e-04 4.70705e-04 3.06735e-03 3.06735e-03 3.34875e-04 3.34875e-04 1.65095e-03 1.65095e-03 3.56333e-04 3.56333e-04 1.80197e-03 1.80197e-03 1.60275e-06 1.60275e-06 +5.80000e+00 1.37924e-03 6.38137e-04 6.38137e-04 3.44882e-03 3.44882e-03 4.30290e-04 4.30290e-04 1.94223e-03 1.94223e-03 3.73991e-04 3.73991e-04 1.92617e-03 1.92617e-03 4.98731e-06 4.98731e-06 +5.90000e+00 1.45483e-03 7.55599e-04 7.55599e-04 3.49617e-03 3.49617e-03 5.11150e-04 5.11150e-04 2.06289e-03 2.06289e-03 3.97725e-04 3.97725e-04 1.87370e-03 1.87370e-03 1.25727e-05 1.25727e-05 +6.00000e+00 1.53948e-03 7.70601e-04 7.70601e-04 3.19202e-03 3.19202e-03 5.29865e-04 5.29865e-04 1.94599e-03 1.94599e-03 4.05916e-04 4.05916e-04 1.70002e-03 1.70002e-03 2.56570e-05 2.56570e-05 +6.10000e+00 1.58568e-03 6.73822e-04 6.73822e-04 2.66436e-03 2.66436e-03 4.72139e-04 4.72139e-04 1.62943e-03 1.62943e-03 3.79582e-04 3.79582e-04 1.47514e-03 1.47514e-03 4.23429e-05 4.23429e-05 +6.20000e+00 1.51599e-03 5.04199e-04 5.04199e-04 2.06232e-03 2.06232e-03 3.61528e-04 3.61528e-04 1.21767e-03 1.21767e-03 3.17962e-04 3.17962e-04 1.22482e-03 1.22482e-03 5.64558e-05 5.64558e-05 +6.30000e+00 1.28486e-03 3.22258e-04 3.22258e-04 1.47827e-03 1.47827e-03 2.38643e-04 2.38643e-04 8.14408e-04 8.14408e-04 2.36637e-04 2.36637e-04 9.44342e-04 9.44342e-04 6.07488e-05 6.07488e-05 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/input.toml b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/input.toml new file mode 100644 index 00000000..d1aef925 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/input.toml @@ -0,0 +1,44 @@ +[base] +dimension = 9 +output_dir = "output" + +[solver] +name = "sim-trhepd-rheed-mb_connect" +run_scheme = "subprocess" +generate_rocking_curve = false + +[solver.config] +#calculated_first_line =5 +#calculated_last_line = 65 +#row_number = 2 +surface_exec_file = "~/tool/sim-trhepd-rheed/src/surf.exe" +bulk_output_file = "bulkP.b" +surface_template_file = "template.txt" +cal_number = [1, 2, 4, 6, 8] + + +[solver.post] +normalization = "MS_NORM_SET_WGT" #"TOTAL" for Integration or "MAX" for MAX value +Rfactor_type = "A2" #"A" for Ichimiya's or "B" for Pendry's or "A2" for squared Weight + Ichimiya's +omega = 0.5 +spot_weight = [0.933, 0.026, 0.036, 0.003, 0.002] +remove_work_dir = false + +[solver.param] +string_list = ["value_01", "value_02","value_03", "value_04","value_05", "value_06", "value_07","value_08", "value_09"] +#degree_max = 6.5 + + +[solver.reference] +path = "experiment.txt" +exp_number = [1, 2, 4, 6, 8] +#first =1 +#last = 63 + + +[algorithm] +name = "mapper" +label_list = ["X1", "X2", "X3", "Y3", "Z1", "Z2", "Z3", "Z4", "Z5"] + +[algorithm.param] +mesh_path = "MeshData.txt" diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/ref_ColorMap.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/ref_ColorMap.txt new file mode 100644 index 00000000..46550f5a --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/ref_ColorMap.txt @@ -0,0 +1,10 @@ +0.500000 1.000000 1.500000 1.500000 5.400000 4.800000 3.800000 2.100000 2.000000 0.000000 +5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.003431 +4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.003161 +5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.003161 +5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.003163 +5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.003431 +5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 0.003575 +5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 0.003575 +5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 0.003571 +5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 0.004136 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/template.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/template.txt new file mode 100644 index 00000000..8469cd87 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/template.txt @@ -0,0 +1,16 @@ +2 ,NELMS, -------- Ge(001)-c4x2 +32,1.2,0.15 ,Ge Z,da1,sap +0.6,0.6,0.6 ,BH(I),BK(I),BZ(I) +32,1.2,0.15 ,Ge Z,da1,sap +0.4,0.4,0.4 ,BH(I),BK(I),BZ(I) +9,4,0,0,2,1.7,-0.5,0.5 ,NSGS,msa,msb,nsa,nsb,dthick,DXS,DYS +8 ,NATM +1, 1.0, value_01, 1.00000, value_05 ,IELM(I),ocr(I),X(I),Y(I),Z(I +1, 1.0, value_02, 1.00000, value_06 +2, 1.0, value_03, value_04, value_07 +2, 1.0, 2.00000, 1.49751, value_08 +2, 1.0, 1.00000, 1.50000, value_09 +2, 1.0, 0.00000, 1.00000, 0.849425 +2, 1.0, 2.00000, 1.00000, 0.809425 +2, 1.0, 1.00997, 1.00000, 0.599425 +1,1 ,(WDOM,I=1,NDOM) diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/bulk.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/bulk.txt new file mode 100644 index 00000000..a321798b --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/bulk.txt @@ -0,0 +1,14 @@ +2,1,2 ,NH,NK,NDOM, -------- Ge(001) bulk +7,15 ,(NB,I=1,NDOM) +0,90 ,(RDOM,I=1,NDOM) +0,0,0,1,0,-1,0,2,0,-2,0,3,0,-3 ,(IH(I),IK(I),I=1,NB) +0,0,1,0,-1,0,2,0,-2,0,3,0,-3,0,4,0,-4,0,5,0,-5,0,6,0,-6,0,7,0,-7,0 ,(IH(I),IK(I),I=1,NB) +10,0,0,0,0.3,6.3,0.1 ,BE,AZI,AZF,DAZ,GI,GF,DG +0.1,100 ,DZ,ML +1 ,NELM +32,1.2,0.15 ,Ge Z,da1,sap +0.4,0.4,0.4 ,BH(I),BK(I),BZ(I) +6,4.01319,4.01319,90,2.83770,0.5,0.5 ,NSG,AA,BB,GAM,CC,DX,DY +2 ,NATM +1,1.0,0.00000,0.50000, 2.12833 ,IELM(I),ocr(I),X(I),Y(I),Z(I) +1,1.0,0.00000,0.00000, 0.70948 ,IELM(I),ocr(I),X(I),Y(I),Z(I) diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/experiment.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/experiment.txt new file mode 100644 index 00000000..d2075d33 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/experiment.txt @@ -0,0 +1,61 @@ +3.00000e-01 8.20372e-03 2.54229e-06 2.54229e-06 9.88860e-15 9.88860e-15 6.88084e-33 6.88084e-33 4.60049e-54 4.60049e-54 4.51983e-87 4.51983e-87 3.53221e-125 3.53221e-125 2.28323e-173 2.28323e-173 +4.00000e-01 1.14751e-02 1.04244e-05 1.04244e-05 2.49203e-13 2.49203e-13 1.26542e-30 1.26542e-30 4.98289e-51 4.98289e-51 3.60151e-83 3.60151e-83 2.07188e-120 2.07188e-120 9.85900e-168 9.85900e-168 +5.00000e-01 1.46340e-02 3.58730e-05 3.58730e-05 5.04417e-12 5.04417e-12 1.86515e-28 1.86515e-28 4.32416e-48 4.32416e-48 2.29890e-79 2.29890e-79 9.73541e-116 9.73541e-116 3.41025e-162 3.41025e-162 +6.00000e-01 1.74036e-02 1.04606e-04 1.04606e-04 8.20593e-11 8.20593e-11 2.20358e-26 2.20358e-26 3.00666e-45 3.00666e-45 1.17553e-75 1.17553e-75 3.66450e-111 3.66450e-111 9.44952e-157 9.44952e-157 +7.00000e-01 1.96261e-02 2.61079e-04 2.61079e-04 1.07379e-09 1.07379e-09 2.08711e-24 2.08711e-24 1.67514e-42 1.67514e-42 4.81525e-72 4.81525e-72 1.10496e-106 1.10496e-106 2.09751e-151 2.09751e-151 +8.00000e-01 2.11810e-02 5.62998e-04 5.62998e-04 1.13137e-08 1.13137e-08 1.58509e-22 1.58509e-22 7.47877e-40 7.47877e-40 1.58009e-68 1.58009e-68 2.66901e-102 2.66901e-102 3.72967e-146 3.72967e-146 +9.00000e-01 2.19506e-02 1.05701e-03 1.05701e-03 9.61019e-08 9.61019e-08 9.65510e-21 9.65510e-21 2.67582e-37 2.67582e-37 4.15360e-65 4.15360e-65 5.16449e-98 5.16449e-98 5.31259e-141 5.31259e-141 +1.00000e+00 2.18837e-02 1.73666e-03 1.73666e-03 6.59148e-07 6.59148e-07 4.71837e-19 4.71837e-19 7.67314e-35 7.67314e-35 8.74678e-62 8.74678e-62 8.00527e-94 8.00527e-94 6.06197e-136 6.06197e-136 +1.10000e+00 2.11118e-02 2.50352e-03 2.50352e-03 3.65776e-06 3.65776e-06 1.85068e-17 1.85068e-17 1.76374e-32 1.76374e-32 1.47555e-58 1.47555e-58 9.94026e-90 9.94026e-90 5.54106e-131 5.54106e-131 +1.20000e+00 2.00197e-02 3.17036e-03 3.17036e-03 1.64630e-05 1.64630e-05 5.82895e-16 5.82895e-16 3.25019e-30 3.25019e-30 1.99411e-55 1.99411e-55 9.88767e-86 9.88767e-86 4.05736e-126 4.05736e-126 +1.30000e+00 1.91652e-02 3.53255e-03 3.53255e-03 6.02887e-05 6.02887e-05 1.47520e-14 1.47520e-14 4.80262e-28 4.80262e-28 2.15890e-52 2.15890e-52 7.87888e-82 7.87888e-82 2.37994e-121 2.37994e-121 +1.40000e+00 1.90127e-02 3.48189e-03 3.48189e-03 1.80376e-04 1.80376e-04 3.00236e-13 3.00236e-13 5.69175e-26 5.69175e-26 1.87246e-49 1.87246e-49 5.02934e-78 5.02934e-78 1.11831e-116 1.11831e-116 +1.50000e+00 1.95992e-02 3.08705e-03 3.08705e-03 4.43302e-04 4.43302e-04 4.91905e-12 4.91905e-12 5.41178e-24 5.41178e-24 1.30105e-46 1.30105e-46 2.57178e-74 2.57178e-74 4.20947e-112 4.20947e-112 +1.60000e+00 2.03890e-02 2.57618e-03 2.57618e-03 9.01644e-04 9.01644e-04 6.49662e-11 6.49662e-11 4.12970e-22 4.12970e-22 7.24244e-44 7.24244e-44 1.05351e-70 1.05351e-70 1.26931e-107 1.26931e-107 +1.70000e+00 2.05290e-02 2.22146e-03 2.22146e-03 1.53385e-03 1.53385e-03 6.92826e-10 6.92826e-10 2.53031e-20 2.53031e-20 3.22996e-41 3.22996e-41 3.45717e-67 3.45717e-67 3.06607e-103 3.06607e-103 +1.80000e+00 1.94096e-02 2.18932e-03 2.18932e-03 2.21633e-03 2.21633e-03 5.97919e-09 5.97919e-09 1.24551e-18 1.24551e-18 1.15409e-38 1.15409e-38 9.08840e-64 9.08840e-64 5.93296e-99 5.93296e-99 +1.90000e+00 1.71097e-02 2.45030e-03 2.45030e-03 2.78148e-03 2.78148e-03 4.18750e-08 4.18750e-08 4.92860e-17 4.92860e-17 3.30394e-36 3.30394e-36 1.91400e-60 1.91400e-60 9.19679e-95 9.19679e-95 +2.00000e+00 1.43591e-02 2.81912e-03 2.81912e-03 3.12490e-03 3.12490e-03 2.38836e-07 2.38836e-07 1.56913e-15 1.56913e-15 7.57864e-34 7.57864e-34 3.22913e-57 3.22913e-57 1.14203e-90 1.14203e-90 +2.10000e+00 1.20865e-02 3.10041e-03 3.10041e-03 3.25578e-03 3.25578e-03 1.11435e-06 1.11435e-06 4.02329e-14 4.02329e-14 1.39297e-31 1.39297e-31 4.36442e-54 4.36442e-54 1.13605e-86 1.13605e-86 +2.20000e+00 1.09633e-02 3.21399e-03 3.21399e-03 3.24916e-03 3.24916e-03 4.27726e-06 4.27726e-06 8.31769e-13 8.31769e-13 2.05172e-29 2.05172e-29 4.72574e-51 4.72574e-51 9.05318e-83 9.05318e-83 +2.30000e+00 1.12236e-02 3.19005e-03 3.19005e-03 3.17788e-03 3.17788e-03 1.36022e-05 1.36022e-05 1.38846e-11 1.38846e-11 2.42190e-27 2.42190e-27 4.09943e-48 4.09943e-48 5.77945e-79 5.77945e-79 +2.40000e+00 1.26847e-02 3.06482e-03 3.06482e-03 3.10461e-03 3.10461e-03 3.61631e-05 3.61631e-05 1.87457e-10 1.87457e-10 2.29143e-25 2.29143e-25 2.84903e-45 2.84903e-45 2.95569e-75 2.95569e-75 +2.50000e+00 1.47993e-02 2.81322e-03 2.81322e-03 3.10625e-03 3.10625e-03 8.13202e-05 8.13202e-05 2.05098e-09 2.05098e-09 1.73793e-23 1.73793e-23 1.58637e-42 1.58637e-42 1.21094e-71 1.21094e-71 +2.60000e+00 1.67805e-02 2.39686e-03 2.39686e-03 3.24955e-03 3.24955e-03 1.57036e-04 1.57036e-04 1.82269e-08 1.82269e-08 1.05686e-21 1.05686e-21 7.07715e-40 7.07715e-40 3.97449e-68 3.97449e-68 +2.70000e+00 1.79264e-02 1.85723e-03 1.85723e-03 3.51557e-03 3.51557e-03 2.65495e-04 2.65495e-04 1.31923e-07 1.31923e-07 5.15425e-20 5.15425e-20 2.52977e-37 2.52977e-37 1.04506e-64 1.04506e-64 +2.80000e+00 1.79907e-02 1.33093e-03 1.33093e-03 3.76876e-03 3.76876e-03 4.01966e-04 4.01966e-04 7.80115e-07 7.80115e-07 2.01655e-18 2.01655e-18 7.24591e-35 7.24591e-35 2.20148e-61 2.20148e-61 +2.90000e+00 1.72421e-02 9.65817e-04 9.65817e-04 3.83828e-03 3.83828e-03 5.57429e-04 5.57429e-04 3.78303e-06 3.78303e-06 6.33181e-17 6.33181e-17 1.66313e-32 1.66313e-32 3.71541e-58 3.71541e-58 +3.00000e+00 1.61322e-02 8.30083e-04 8.30083e-04 3.64961e-03 3.64961e-03 7.20742e-04 7.20742e-04 1.51116e-05 1.51116e-05 1.59643e-15 1.59643e-15 3.05929e-30 3.05929e-30 5.02379e-55 5.02379e-55 +3.10000e+00 1.49123e-02 8.92997e-04 8.92997e-04 3.27932e-03 3.27932e-03 8.78263e-04 8.78263e-04 5.00004e-05 5.00004e-05 3.23432e-14 3.23432e-14 4.51043e-28 4.51043e-28 5.44257e-52 5.44257e-52 +3.20000e+00 1.35465e-02 1.06737e-03 1.06737e-03 2.88348e-03 2.88348e-03 1.01433e-03 1.01433e-03 1.37994e-04 1.37994e-04 5.27039e-13 5.27039e-13 5.33063e-26 5.33063e-26 4.72436e-49 4.72436e-49 +3.30000e+00 1.19172e-02 1.26022e-03 1.26022e-03 2.57067e-03 2.57067e-03 1.11335e-03 1.11335e-03 3.20529e-04 3.20529e-04 6.91671e-12 6.91671e-12 5.05096e-24 5.05096e-24 3.28603e-46 3.28603e-46 +3.40000e+00 1.00537e-02 1.40135e-03 1.40135e-03 2.33714e-03 2.33714e-03 1.15940e-03 1.15940e-03 6.33766e-04 6.33766e-04 7.32418e-11 7.32418e-11 3.83791e-22 3.83791e-22 1.83156e-43 1.83156e-43 +3.50000e+00 8.17053e-03 1.45385e-03 1.45385e-03 2.12304e-03 2.12304e-03 1.13607e-03 1.13607e-03 1.08143e-03 1.08143e-03 6.27478e-10 6.27478e-10 2.33911e-20 2.33911e-20 8.18137e-41 8.18137e-41 +3.60000e+00 6.53572e-03 1.41927e-03 1.41927e-03 1.92999e-03 1.92999e-03 1.03519e-03 1.03519e-03 1.61626e-03 1.61626e-03 4.36723e-09 4.36723e-09 1.14389e-18 1.14389e-18 2.92909e-38 2.92909e-38 +3.70000e+00 5.35999e-03 1.33367e-03 1.33367e-03 1.86928e-03 1.86928e-03 8.70233e-04 8.70233e-04 2.14410e-03 2.14410e-03 2.48549e-08 2.48549e-08 4.49016e-17 4.49016e-17 8.40612e-36 8.40612e-36 +3.80000e+00 4.81712e-03 1.24066e-03 1.24066e-03 2.07870e-03 2.07870e-03 6.75861e-04 6.75861e-04 2.54646e-03 2.54646e-03 1.16900e-07 1.16900e-07 1.41547e-15 1.41547e-15 1.93413e-33 1.93413e-33 +3.90000e+00 5.09106e-03 1.15259e-03 1.15259e-03 2.58615e-03 2.58615e-03 4.89391e-04 4.89391e-04 2.71476e-03 2.71476e-03 4.62218e-07 4.62218e-07 3.58560e-14 3.58560e-14 3.56849e-31 3.56849e-31 +4.00000e+00 6.27917e-03 1.04113e-03 1.04113e-03 3.25723e-03 3.25723e-03 3.33325e-04 3.33325e-04 2.59542e-03 2.59542e-03 1.57650e-06 1.57650e-06 7.30420e-13 7.30420e-13 5.28077e-29 5.28077e-29 +4.10000e+00 8.18460e-03 8.74899e-04 8.74899e-04 3.88244e-03 3.88244e-03 2.14609e-04 2.14609e-04 2.22842e-03 2.22842e-03 4.79133e-06 4.79133e-06 1.19766e-11 1.19766e-11 6.26976e-27 6.26976e-27 +4.20000e+00 1.02521e-02 6.63215e-04 6.63215e-04 4.31701e-03 4.31701e-03 1.33479e-04 1.33479e-04 1.74106e-03 1.74106e-03 1.33460e-05 1.33460e-05 1.58248e-10 1.58248e-10 5.97443e-25 5.97443e-25 +4.30000e+00 1.18201e-02 4.56534e-04 4.56534e-04 4.53705e-03 4.53705e-03 8.83076e-05 8.83076e-05 1.28846e-03 1.28846e-03 3.43304e-05 3.43304e-05 1.68730e-09 1.68730e-09 4.57109e-23 4.57109e-23 +4.40000e+00 1.25166e-02 3.07901e-04 3.07901e-04 4.58438e-03 4.58438e-03 7.48076e-05 7.48076e-05 9.85554e-04 9.85554e-04 8.01387e-05 8.01387e-05 1.45425e-08 1.45425e-08 2.80956e-21 2.80956e-21 +4.50000e+00 1.24346e-02 2.39831e-04 2.39831e-04 4.49553e-03 4.49553e-03 8.47877e-05 8.47877e-05 8.78596e-04 8.78596e-04 1.64859e-04 1.64859e-04 1.01531e-07 1.01531e-07 1.38807e-19 1.38807e-19 +4.60000e+00 1.19322e-02 2.40983e-04 2.40983e-04 4.28955e-03 4.28955e-03 1.06907e-04 1.06907e-04 9.55939e-04 9.55939e-04 2.91399e-04 2.91399e-04 5.75738e-07 5.75738e-07 5.51622e-18 5.51622e-18 +4.70000e+00 1.12782e-02 2.80574e-04 2.80574e-04 3.99474e-03 3.99474e-03 1.30423e-04 1.30423e-04 1.16635e-03 1.16635e-03 4.36262e-04 4.36262e-04 2.66058e-06 2.66058e-06 1.76470e-16 1.76470e-16 +4.80000e+00 1.04800e-02 3.23137e-04 3.23137e-04 3.66468e-03 3.66468e-03 1.51930e-04 1.51930e-04 1.42843e-03 1.42843e-03 5.51828e-04 5.51828e-04 1.00645e-05 1.00645e-05 4.54869e-15 4.54869e-15 +4.90000e+00 9.40087e-03 3.40575e-04 3.40575e-04 3.35809e-03 3.35809e-03 1.78878e-04 1.78878e-04 1.64275e-03 1.64275e-03 5.95529e-04 5.95529e-04 3.13600e-05 3.13600e-05 9.45602e-14 9.45602e-14 +5.00000e+00 7.98100e-03 3.21858e-04 3.21858e-04 3.09388e-03 3.09388e-03 2.21316e-04 2.21316e-04 1.72244e-03 1.72244e-03 5.62367e-04 5.62367e-04 8.12272e-05 8.12272e-05 1.58702e-12 1.58702e-12 +5.10000e+00 6.33564e-03 2.75141e-04 2.75141e-04 2.83349e-03 2.83349e-03 2.75830e-04 2.75830e-04 1.63475e-03 1.63475e-03 4.86986e-04 4.86986e-04 1.77338e-04 1.77338e-04 2.15260e-11 2.15260e-11 +5.20000e+00 4.69185e-03 2.20277e-04 2.20277e-04 2.53384e-03 2.53384e-03 3.20101e-04 3.20101e-04 1.42421e-03 1.42421e-03 4.14585e-04 4.14585e-04 3.33162e-04 3.33162e-04 2.36204e-10 2.36204e-10 +5.30000e+00 3.27797e-03 1.79027e-04 1.79027e-04 2.23107e-03 2.23107e-03 3.29667e-04 3.29667e-04 1.19533e-03 1.19533e-03 3.71111e-04 3.71111e-04 5.53645e-04 5.53645e-04 2.09869e-09 2.09869e-09 +5.40000e+00 2.24753e-03 1.70825e-04 1.70825e-04 2.05873e-03 2.05873e-03 3.03413e-04 3.03413e-04 1.06400e-03 1.06400e-03 3.55457e-04 3.55457e-04 8.37552e-04 8.37552e-04 1.51103e-08 1.51103e-08 +5.50000e+00 1.64073e-03 2.12816e-04 2.12816e-04 2.15862e-03 2.15862e-03 2.71480e-04 2.71480e-04 1.10647e-03 1.10647e-03 3.52311e-04 3.52311e-04 1.17414e-03 1.17414e-03 8.82030e-08 8.82030e-08 +5.60000e+00 1.38305e-03 3.15679e-04 3.15679e-04 2.54923e-03 2.54923e-03 2.75242e-04 2.75242e-04 1.32726e-03 1.32726e-03 3.51425e-04 3.51425e-04 1.52290e-03 1.52290e-03 4.17530e-07 4.17530e-07 +5.70000e+00 1.33614e-03 4.70705e-04 4.70705e-04 3.06735e-03 3.06735e-03 3.34875e-04 3.34875e-04 1.65095e-03 1.65095e-03 3.56333e-04 3.56333e-04 1.80197e-03 1.80197e-03 1.60275e-06 1.60275e-06 +5.80000e+00 1.37924e-03 6.38137e-04 6.38137e-04 3.44882e-03 3.44882e-03 4.30290e-04 4.30290e-04 1.94223e-03 1.94223e-03 3.73991e-04 3.73991e-04 1.92617e-03 1.92617e-03 4.98731e-06 4.98731e-06 +5.90000e+00 1.45483e-03 7.55599e-04 7.55599e-04 3.49617e-03 3.49617e-03 5.11150e-04 5.11150e-04 2.06289e-03 2.06289e-03 3.97725e-04 3.97725e-04 1.87370e-03 1.87370e-03 1.25727e-05 1.25727e-05 +6.00000e+00 1.53948e-03 7.70601e-04 7.70601e-04 3.19202e-03 3.19202e-03 5.29865e-04 5.29865e-04 1.94599e-03 1.94599e-03 4.05916e-04 4.05916e-04 1.70002e-03 1.70002e-03 2.56570e-05 2.56570e-05 +6.10000e+00 1.58568e-03 6.73822e-04 6.73822e-04 2.66436e-03 2.66436e-03 4.72139e-04 4.72139e-04 1.62943e-03 1.62943e-03 3.79582e-04 3.79582e-04 1.47514e-03 1.47514e-03 4.23429e-05 4.23429e-05 +6.20000e+00 1.51599e-03 5.04199e-04 5.04199e-04 2.06232e-03 2.06232e-03 3.61528e-04 3.61528e-04 1.21767e-03 1.21767e-03 3.17962e-04 3.17962e-04 1.22482e-03 1.22482e-03 5.64558e-05 5.64558e-05 +6.30000e+00 1.28486e-03 3.22258e-04 3.22258e-04 1.47827e-03 1.47827e-03 2.38643e-04 2.38643e-04 8.14408e-04 8.14408e-04 2.36637e-04 2.36637e-04 9.44342e-04 9.44342e-04 6.07488e-05 6.07488e-05 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/input.toml b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/input.toml new file mode 100644 index 00000000..2a7df8bc --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/input.toml @@ -0,0 +1,49 @@ +[base] +dimension = 9 +output_dir = "output" + +[solver] +name = "sim-trhepd-rheed-mb_connect" +run_scheme = "subprocess" + +[solver.config] +surface_exec_file = "/home/kinoshita/tool/sim-trhepd-rheed/src/surf.exe" +bulk_output_file = "bulkP.b" +surface_template_file = "template.txt" +cal_number = [1, 2, 4, 6, 8] +#calculated_first_line =5 +#calculated_last_line = 67 +#row_number = 2 + +[solver.post] +normalization = "MS_NORM" #"TOTAL" for Integration or "MAX" for MAX value +Rfactor_type = "A2" #"A" for Ichimiya's or "B" for Pendry's or "A2" for squared Weight + Ichimiya's +omega = 0.5 + +remove_work_dir = false + +[solver.param] +string_list = ["value_01", "value_02", "value_03", "value_04", "value_05", "value_06", "value_07", "value_08", "value_09"] +#degree_max = 6.5 + +[solver.reference] +path = "experiment.txt" +exp_number = [1, 2, 4, 6, 8] +#first =1 +#last = 63 + +[algorithm] +name = "minsearch" +label_list = ["X1", "X2", "X3", "Y3","Z1", "Z2", "Z3", "Z4", "Z5"] + +[algorithm.param] +initial_list = [0.49800, 0.98000, 1.49800, 1.49800, 5.390000, 4.790000, 3.790000, 2.090000, 1.990000] +min_list = [0.00000, 0.50000, 1.00000, 1.00000, 4.400000, 3.800000, 2.800000, 1.100000, 1.000000] +max_list = [1.00000, 1.50000, 2.00000, 2.00000, 6.400000, 5.800000, 4.800000, 3.100000, 3.000000] + +[algorithm.minimize] +fatol = 0.01 +xatol = 0.001 +initial_scale_list = [ 0.0025, 0.0025, 0.0025, 0.0025, 0.01, 0.01, 0.01, 0.01, 0.01 ] +maxiter = 1000 +maxfev = 10000 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/ref.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/ref.txt new file mode 100644 index 00000000..cf49da3f --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/ref.txt @@ -0,0 +1,10 @@ +fx = 6.3938405423961675e-09 +X1 = 0.5004690263563492 +X2 = 0.9864825395902956 +X3 = 1.500736054255837 +Y3 = 1.49846022838361 +Z1 = 5.401681359233681 +Z2 = 4.801963397208427 +Z3 = 3.8008746121421977 +Z4 = 2.1004447161065523 +Z5 = 2.000919674433793 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/template.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/template.txt new file mode 100644 index 00000000..8469cd87 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/template.txt @@ -0,0 +1,16 @@ +2 ,NELMS, -------- Ge(001)-c4x2 +32,1.2,0.15 ,Ge Z,da1,sap +0.6,0.6,0.6 ,BH(I),BK(I),BZ(I) +32,1.2,0.15 ,Ge Z,da1,sap +0.4,0.4,0.4 ,BH(I),BK(I),BZ(I) +9,4,0,0,2,1.7,-0.5,0.5 ,NSGS,msa,msb,nsa,nsb,dthick,DXS,DYS +8 ,NATM +1, 1.0, value_01, 1.00000, value_05 ,IELM(I),ocr(I),X(I),Y(I),Z(I +1, 1.0, value_02, 1.00000, value_06 +2, 1.0, value_03, value_04, value_07 +2, 1.0, 2.00000, 1.49751, value_08 +2, 1.0, 1.00000, 1.50000, value_09 +2, 1.0, 0.00000, 1.00000, 0.849425 +2, 1.0, 2.00000, 1.00000, 0.809425 +2, 1.0, 1.00997, 1.00000, 0.599425 +1,1 ,(WDOM,I=1,NDOM) diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/bulk.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/bulk.txt new file mode 100644 index 00000000..a321798b --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/bulk.txt @@ -0,0 +1,14 @@ +2,1,2 ,NH,NK,NDOM, -------- Ge(001) bulk +7,15 ,(NB,I=1,NDOM) +0,90 ,(RDOM,I=1,NDOM) +0,0,0,1,0,-1,0,2,0,-2,0,3,0,-3 ,(IH(I),IK(I),I=1,NB) +0,0,1,0,-1,0,2,0,-2,0,3,0,-3,0,4,0,-4,0,5,0,-5,0,6,0,-6,0,7,0,-7,0 ,(IH(I),IK(I),I=1,NB) +10,0,0,0,0.3,6.3,0.1 ,BE,AZI,AZF,DAZ,GI,GF,DG +0.1,100 ,DZ,ML +1 ,NELM +32,1.2,0.15 ,Ge Z,da1,sap +0.4,0.4,0.4 ,BH(I),BK(I),BZ(I) +6,4.01319,4.01319,90,2.83770,0.5,0.5 ,NSG,AA,BB,GAM,CC,DX,DY +2 ,NATM +1,1.0,0.00000,0.50000, 2.12833 ,IELM(I),ocr(I),X(I),Y(I),Z(I) +1,1.0,0.00000,0.00000, 0.70948 ,IELM(I),ocr(I),X(I),Y(I),Z(I) diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/experiment.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/experiment.txt new file mode 100644 index 00000000..d2075d33 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/experiment.txt @@ -0,0 +1,61 @@ +3.00000e-01 8.20372e-03 2.54229e-06 2.54229e-06 9.88860e-15 9.88860e-15 6.88084e-33 6.88084e-33 4.60049e-54 4.60049e-54 4.51983e-87 4.51983e-87 3.53221e-125 3.53221e-125 2.28323e-173 2.28323e-173 +4.00000e-01 1.14751e-02 1.04244e-05 1.04244e-05 2.49203e-13 2.49203e-13 1.26542e-30 1.26542e-30 4.98289e-51 4.98289e-51 3.60151e-83 3.60151e-83 2.07188e-120 2.07188e-120 9.85900e-168 9.85900e-168 +5.00000e-01 1.46340e-02 3.58730e-05 3.58730e-05 5.04417e-12 5.04417e-12 1.86515e-28 1.86515e-28 4.32416e-48 4.32416e-48 2.29890e-79 2.29890e-79 9.73541e-116 9.73541e-116 3.41025e-162 3.41025e-162 +6.00000e-01 1.74036e-02 1.04606e-04 1.04606e-04 8.20593e-11 8.20593e-11 2.20358e-26 2.20358e-26 3.00666e-45 3.00666e-45 1.17553e-75 1.17553e-75 3.66450e-111 3.66450e-111 9.44952e-157 9.44952e-157 +7.00000e-01 1.96261e-02 2.61079e-04 2.61079e-04 1.07379e-09 1.07379e-09 2.08711e-24 2.08711e-24 1.67514e-42 1.67514e-42 4.81525e-72 4.81525e-72 1.10496e-106 1.10496e-106 2.09751e-151 2.09751e-151 +8.00000e-01 2.11810e-02 5.62998e-04 5.62998e-04 1.13137e-08 1.13137e-08 1.58509e-22 1.58509e-22 7.47877e-40 7.47877e-40 1.58009e-68 1.58009e-68 2.66901e-102 2.66901e-102 3.72967e-146 3.72967e-146 +9.00000e-01 2.19506e-02 1.05701e-03 1.05701e-03 9.61019e-08 9.61019e-08 9.65510e-21 9.65510e-21 2.67582e-37 2.67582e-37 4.15360e-65 4.15360e-65 5.16449e-98 5.16449e-98 5.31259e-141 5.31259e-141 +1.00000e+00 2.18837e-02 1.73666e-03 1.73666e-03 6.59148e-07 6.59148e-07 4.71837e-19 4.71837e-19 7.67314e-35 7.67314e-35 8.74678e-62 8.74678e-62 8.00527e-94 8.00527e-94 6.06197e-136 6.06197e-136 +1.10000e+00 2.11118e-02 2.50352e-03 2.50352e-03 3.65776e-06 3.65776e-06 1.85068e-17 1.85068e-17 1.76374e-32 1.76374e-32 1.47555e-58 1.47555e-58 9.94026e-90 9.94026e-90 5.54106e-131 5.54106e-131 +1.20000e+00 2.00197e-02 3.17036e-03 3.17036e-03 1.64630e-05 1.64630e-05 5.82895e-16 5.82895e-16 3.25019e-30 3.25019e-30 1.99411e-55 1.99411e-55 9.88767e-86 9.88767e-86 4.05736e-126 4.05736e-126 +1.30000e+00 1.91652e-02 3.53255e-03 3.53255e-03 6.02887e-05 6.02887e-05 1.47520e-14 1.47520e-14 4.80262e-28 4.80262e-28 2.15890e-52 2.15890e-52 7.87888e-82 7.87888e-82 2.37994e-121 2.37994e-121 +1.40000e+00 1.90127e-02 3.48189e-03 3.48189e-03 1.80376e-04 1.80376e-04 3.00236e-13 3.00236e-13 5.69175e-26 5.69175e-26 1.87246e-49 1.87246e-49 5.02934e-78 5.02934e-78 1.11831e-116 1.11831e-116 +1.50000e+00 1.95992e-02 3.08705e-03 3.08705e-03 4.43302e-04 4.43302e-04 4.91905e-12 4.91905e-12 5.41178e-24 5.41178e-24 1.30105e-46 1.30105e-46 2.57178e-74 2.57178e-74 4.20947e-112 4.20947e-112 +1.60000e+00 2.03890e-02 2.57618e-03 2.57618e-03 9.01644e-04 9.01644e-04 6.49662e-11 6.49662e-11 4.12970e-22 4.12970e-22 7.24244e-44 7.24244e-44 1.05351e-70 1.05351e-70 1.26931e-107 1.26931e-107 +1.70000e+00 2.05290e-02 2.22146e-03 2.22146e-03 1.53385e-03 1.53385e-03 6.92826e-10 6.92826e-10 2.53031e-20 2.53031e-20 3.22996e-41 3.22996e-41 3.45717e-67 3.45717e-67 3.06607e-103 3.06607e-103 +1.80000e+00 1.94096e-02 2.18932e-03 2.18932e-03 2.21633e-03 2.21633e-03 5.97919e-09 5.97919e-09 1.24551e-18 1.24551e-18 1.15409e-38 1.15409e-38 9.08840e-64 9.08840e-64 5.93296e-99 5.93296e-99 +1.90000e+00 1.71097e-02 2.45030e-03 2.45030e-03 2.78148e-03 2.78148e-03 4.18750e-08 4.18750e-08 4.92860e-17 4.92860e-17 3.30394e-36 3.30394e-36 1.91400e-60 1.91400e-60 9.19679e-95 9.19679e-95 +2.00000e+00 1.43591e-02 2.81912e-03 2.81912e-03 3.12490e-03 3.12490e-03 2.38836e-07 2.38836e-07 1.56913e-15 1.56913e-15 7.57864e-34 7.57864e-34 3.22913e-57 3.22913e-57 1.14203e-90 1.14203e-90 +2.10000e+00 1.20865e-02 3.10041e-03 3.10041e-03 3.25578e-03 3.25578e-03 1.11435e-06 1.11435e-06 4.02329e-14 4.02329e-14 1.39297e-31 1.39297e-31 4.36442e-54 4.36442e-54 1.13605e-86 1.13605e-86 +2.20000e+00 1.09633e-02 3.21399e-03 3.21399e-03 3.24916e-03 3.24916e-03 4.27726e-06 4.27726e-06 8.31769e-13 8.31769e-13 2.05172e-29 2.05172e-29 4.72574e-51 4.72574e-51 9.05318e-83 9.05318e-83 +2.30000e+00 1.12236e-02 3.19005e-03 3.19005e-03 3.17788e-03 3.17788e-03 1.36022e-05 1.36022e-05 1.38846e-11 1.38846e-11 2.42190e-27 2.42190e-27 4.09943e-48 4.09943e-48 5.77945e-79 5.77945e-79 +2.40000e+00 1.26847e-02 3.06482e-03 3.06482e-03 3.10461e-03 3.10461e-03 3.61631e-05 3.61631e-05 1.87457e-10 1.87457e-10 2.29143e-25 2.29143e-25 2.84903e-45 2.84903e-45 2.95569e-75 2.95569e-75 +2.50000e+00 1.47993e-02 2.81322e-03 2.81322e-03 3.10625e-03 3.10625e-03 8.13202e-05 8.13202e-05 2.05098e-09 2.05098e-09 1.73793e-23 1.73793e-23 1.58637e-42 1.58637e-42 1.21094e-71 1.21094e-71 +2.60000e+00 1.67805e-02 2.39686e-03 2.39686e-03 3.24955e-03 3.24955e-03 1.57036e-04 1.57036e-04 1.82269e-08 1.82269e-08 1.05686e-21 1.05686e-21 7.07715e-40 7.07715e-40 3.97449e-68 3.97449e-68 +2.70000e+00 1.79264e-02 1.85723e-03 1.85723e-03 3.51557e-03 3.51557e-03 2.65495e-04 2.65495e-04 1.31923e-07 1.31923e-07 5.15425e-20 5.15425e-20 2.52977e-37 2.52977e-37 1.04506e-64 1.04506e-64 +2.80000e+00 1.79907e-02 1.33093e-03 1.33093e-03 3.76876e-03 3.76876e-03 4.01966e-04 4.01966e-04 7.80115e-07 7.80115e-07 2.01655e-18 2.01655e-18 7.24591e-35 7.24591e-35 2.20148e-61 2.20148e-61 +2.90000e+00 1.72421e-02 9.65817e-04 9.65817e-04 3.83828e-03 3.83828e-03 5.57429e-04 5.57429e-04 3.78303e-06 3.78303e-06 6.33181e-17 6.33181e-17 1.66313e-32 1.66313e-32 3.71541e-58 3.71541e-58 +3.00000e+00 1.61322e-02 8.30083e-04 8.30083e-04 3.64961e-03 3.64961e-03 7.20742e-04 7.20742e-04 1.51116e-05 1.51116e-05 1.59643e-15 1.59643e-15 3.05929e-30 3.05929e-30 5.02379e-55 5.02379e-55 +3.10000e+00 1.49123e-02 8.92997e-04 8.92997e-04 3.27932e-03 3.27932e-03 8.78263e-04 8.78263e-04 5.00004e-05 5.00004e-05 3.23432e-14 3.23432e-14 4.51043e-28 4.51043e-28 5.44257e-52 5.44257e-52 +3.20000e+00 1.35465e-02 1.06737e-03 1.06737e-03 2.88348e-03 2.88348e-03 1.01433e-03 1.01433e-03 1.37994e-04 1.37994e-04 5.27039e-13 5.27039e-13 5.33063e-26 5.33063e-26 4.72436e-49 4.72436e-49 +3.30000e+00 1.19172e-02 1.26022e-03 1.26022e-03 2.57067e-03 2.57067e-03 1.11335e-03 1.11335e-03 3.20529e-04 3.20529e-04 6.91671e-12 6.91671e-12 5.05096e-24 5.05096e-24 3.28603e-46 3.28603e-46 +3.40000e+00 1.00537e-02 1.40135e-03 1.40135e-03 2.33714e-03 2.33714e-03 1.15940e-03 1.15940e-03 6.33766e-04 6.33766e-04 7.32418e-11 7.32418e-11 3.83791e-22 3.83791e-22 1.83156e-43 1.83156e-43 +3.50000e+00 8.17053e-03 1.45385e-03 1.45385e-03 2.12304e-03 2.12304e-03 1.13607e-03 1.13607e-03 1.08143e-03 1.08143e-03 6.27478e-10 6.27478e-10 2.33911e-20 2.33911e-20 8.18137e-41 8.18137e-41 +3.60000e+00 6.53572e-03 1.41927e-03 1.41927e-03 1.92999e-03 1.92999e-03 1.03519e-03 1.03519e-03 1.61626e-03 1.61626e-03 4.36723e-09 4.36723e-09 1.14389e-18 1.14389e-18 2.92909e-38 2.92909e-38 +3.70000e+00 5.35999e-03 1.33367e-03 1.33367e-03 1.86928e-03 1.86928e-03 8.70233e-04 8.70233e-04 2.14410e-03 2.14410e-03 2.48549e-08 2.48549e-08 4.49016e-17 4.49016e-17 8.40612e-36 8.40612e-36 +3.80000e+00 4.81712e-03 1.24066e-03 1.24066e-03 2.07870e-03 2.07870e-03 6.75861e-04 6.75861e-04 2.54646e-03 2.54646e-03 1.16900e-07 1.16900e-07 1.41547e-15 1.41547e-15 1.93413e-33 1.93413e-33 +3.90000e+00 5.09106e-03 1.15259e-03 1.15259e-03 2.58615e-03 2.58615e-03 4.89391e-04 4.89391e-04 2.71476e-03 2.71476e-03 4.62218e-07 4.62218e-07 3.58560e-14 3.58560e-14 3.56849e-31 3.56849e-31 +4.00000e+00 6.27917e-03 1.04113e-03 1.04113e-03 3.25723e-03 3.25723e-03 3.33325e-04 3.33325e-04 2.59542e-03 2.59542e-03 1.57650e-06 1.57650e-06 7.30420e-13 7.30420e-13 5.28077e-29 5.28077e-29 +4.10000e+00 8.18460e-03 8.74899e-04 8.74899e-04 3.88244e-03 3.88244e-03 2.14609e-04 2.14609e-04 2.22842e-03 2.22842e-03 4.79133e-06 4.79133e-06 1.19766e-11 1.19766e-11 6.26976e-27 6.26976e-27 +4.20000e+00 1.02521e-02 6.63215e-04 6.63215e-04 4.31701e-03 4.31701e-03 1.33479e-04 1.33479e-04 1.74106e-03 1.74106e-03 1.33460e-05 1.33460e-05 1.58248e-10 1.58248e-10 5.97443e-25 5.97443e-25 +4.30000e+00 1.18201e-02 4.56534e-04 4.56534e-04 4.53705e-03 4.53705e-03 8.83076e-05 8.83076e-05 1.28846e-03 1.28846e-03 3.43304e-05 3.43304e-05 1.68730e-09 1.68730e-09 4.57109e-23 4.57109e-23 +4.40000e+00 1.25166e-02 3.07901e-04 3.07901e-04 4.58438e-03 4.58438e-03 7.48076e-05 7.48076e-05 9.85554e-04 9.85554e-04 8.01387e-05 8.01387e-05 1.45425e-08 1.45425e-08 2.80956e-21 2.80956e-21 +4.50000e+00 1.24346e-02 2.39831e-04 2.39831e-04 4.49553e-03 4.49553e-03 8.47877e-05 8.47877e-05 8.78596e-04 8.78596e-04 1.64859e-04 1.64859e-04 1.01531e-07 1.01531e-07 1.38807e-19 1.38807e-19 +4.60000e+00 1.19322e-02 2.40983e-04 2.40983e-04 4.28955e-03 4.28955e-03 1.06907e-04 1.06907e-04 9.55939e-04 9.55939e-04 2.91399e-04 2.91399e-04 5.75738e-07 5.75738e-07 5.51622e-18 5.51622e-18 +4.70000e+00 1.12782e-02 2.80574e-04 2.80574e-04 3.99474e-03 3.99474e-03 1.30423e-04 1.30423e-04 1.16635e-03 1.16635e-03 4.36262e-04 4.36262e-04 2.66058e-06 2.66058e-06 1.76470e-16 1.76470e-16 +4.80000e+00 1.04800e-02 3.23137e-04 3.23137e-04 3.66468e-03 3.66468e-03 1.51930e-04 1.51930e-04 1.42843e-03 1.42843e-03 5.51828e-04 5.51828e-04 1.00645e-05 1.00645e-05 4.54869e-15 4.54869e-15 +4.90000e+00 9.40087e-03 3.40575e-04 3.40575e-04 3.35809e-03 3.35809e-03 1.78878e-04 1.78878e-04 1.64275e-03 1.64275e-03 5.95529e-04 5.95529e-04 3.13600e-05 3.13600e-05 9.45602e-14 9.45602e-14 +5.00000e+00 7.98100e-03 3.21858e-04 3.21858e-04 3.09388e-03 3.09388e-03 2.21316e-04 2.21316e-04 1.72244e-03 1.72244e-03 5.62367e-04 5.62367e-04 8.12272e-05 8.12272e-05 1.58702e-12 1.58702e-12 +5.10000e+00 6.33564e-03 2.75141e-04 2.75141e-04 2.83349e-03 2.83349e-03 2.75830e-04 2.75830e-04 1.63475e-03 1.63475e-03 4.86986e-04 4.86986e-04 1.77338e-04 1.77338e-04 2.15260e-11 2.15260e-11 +5.20000e+00 4.69185e-03 2.20277e-04 2.20277e-04 2.53384e-03 2.53384e-03 3.20101e-04 3.20101e-04 1.42421e-03 1.42421e-03 4.14585e-04 4.14585e-04 3.33162e-04 3.33162e-04 2.36204e-10 2.36204e-10 +5.30000e+00 3.27797e-03 1.79027e-04 1.79027e-04 2.23107e-03 2.23107e-03 3.29667e-04 3.29667e-04 1.19533e-03 1.19533e-03 3.71111e-04 3.71111e-04 5.53645e-04 5.53645e-04 2.09869e-09 2.09869e-09 +5.40000e+00 2.24753e-03 1.70825e-04 1.70825e-04 2.05873e-03 2.05873e-03 3.03413e-04 3.03413e-04 1.06400e-03 1.06400e-03 3.55457e-04 3.55457e-04 8.37552e-04 8.37552e-04 1.51103e-08 1.51103e-08 +5.50000e+00 1.64073e-03 2.12816e-04 2.12816e-04 2.15862e-03 2.15862e-03 2.71480e-04 2.71480e-04 1.10647e-03 1.10647e-03 3.52311e-04 3.52311e-04 1.17414e-03 1.17414e-03 8.82030e-08 8.82030e-08 +5.60000e+00 1.38305e-03 3.15679e-04 3.15679e-04 2.54923e-03 2.54923e-03 2.75242e-04 2.75242e-04 1.32726e-03 1.32726e-03 3.51425e-04 3.51425e-04 1.52290e-03 1.52290e-03 4.17530e-07 4.17530e-07 +5.70000e+00 1.33614e-03 4.70705e-04 4.70705e-04 3.06735e-03 3.06735e-03 3.34875e-04 3.34875e-04 1.65095e-03 1.65095e-03 3.56333e-04 3.56333e-04 1.80197e-03 1.80197e-03 1.60275e-06 1.60275e-06 +5.80000e+00 1.37924e-03 6.38137e-04 6.38137e-04 3.44882e-03 3.44882e-03 4.30290e-04 4.30290e-04 1.94223e-03 1.94223e-03 3.73991e-04 3.73991e-04 1.92617e-03 1.92617e-03 4.98731e-06 4.98731e-06 +5.90000e+00 1.45483e-03 7.55599e-04 7.55599e-04 3.49617e-03 3.49617e-03 5.11150e-04 5.11150e-04 2.06289e-03 2.06289e-03 3.97725e-04 3.97725e-04 1.87370e-03 1.87370e-03 1.25727e-05 1.25727e-05 +6.00000e+00 1.53948e-03 7.70601e-04 7.70601e-04 3.19202e-03 3.19202e-03 5.29865e-04 5.29865e-04 1.94599e-03 1.94599e-03 4.05916e-04 4.05916e-04 1.70002e-03 1.70002e-03 2.56570e-05 2.56570e-05 +6.10000e+00 1.58568e-03 6.73822e-04 6.73822e-04 2.66436e-03 2.66436e-03 4.72139e-04 4.72139e-04 1.62943e-03 1.62943e-03 3.79582e-04 3.79582e-04 1.47514e-03 1.47514e-03 4.23429e-05 4.23429e-05 +6.20000e+00 1.51599e-03 5.04199e-04 5.04199e-04 2.06232e-03 2.06232e-03 3.61528e-04 3.61528e-04 1.21767e-03 1.21767e-03 3.17962e-04 3.17962e-04 1.22482e-03 1.22482e-03 5.64558e-05 5.64558e-05 +6.30000e+00 1.28486e-03 3.22258e-04 3.22258e-04 1.47827e-03 1.47827e-03 2.38643e-04 2.38643e-04 8.14408e-04 8.14408e-04 2.36637e-04 2.36637e-04 9.44342e-04 9.44342e-04 6.07488e-05 6.07488e-05 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/input.toml b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/input.toml new file mode 100644 index 00000000..9cb34532 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/input.toml @@ -0,0 +1,50 @@ +[base] +dimension = 9 +output_dir = "output" + +[solver] +name = "sim-trhepd-rheed-mb_connect" +run_scheme = "subprocess" + +[solver.config] +surface_exec_file = "/home/kinoshita/tool/sim-trhepd-rheed/src/surf.exe" +bulk_output_file = "bulkP.b" +surface_template_file = "template.txt" +cal_number = [1, 2, 4, 6, 8] +#calculated_first_line =5 +#calculated_last_line = 67 +#row_number = 2 + +[solver.post] +normalization = "MS_NORM_SET_WGT" #"TOTAL" for Integration or "MAX" for MAX value +Rfactor_type = "A2" #"A" for Ichimiya's or "B" for Pendry's or "A2" for squared Weight + Ichimiya's +omega = 0.5 +spot_weight = [0.933, 0.026, 0.036, 0.003, 0.002] + +remove_work_dir = false + +[solver.param] +string_list = ["value_01", "value_02", "value_03", "value_04", "value_05", "value_06", "value_07", "value_08", "value_09"] +#degree_max = 6.5 + +[solver.reference] +path = "experiment.txt" +exp_number = [1, 2, 4, 6, 8] +#first =1 +#last = 63 + +[algorithm] +name = "minsearch" +label_list = ["X1", "X2", "X3", "Y3","Z1", "Z2", "Z3", "Z4", "Z5"] + +[algorithm.param] +initial_list = [0.49800, 0.98000, 1.49800, 1.49800, 5.390000, 4.790000, 3.790000, 2.090000, 1.990000] +min_list = [0.00000, 0.50000, 1.00000, 1.00000, 4.400000, 3.800000, 2.800000, 1.100000, 1.000000] +max_list = [1.00000, 1.50000, 2.00000, 2.00000, 6.400000, 5.800000, 4.800000, 3.100000, 3.000000] + +[algorithm.minimize] +fatol = 0.01 +xatol = 0.001 +initial_scale_list = [ 0.0025, 0.0025, 0.0025, 0.0025, 0.01, 0.01, 0.01, 0.01, 0.01 ] +maxiter = 1000 +maxfev = 10000 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/ref.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/ref.txt new file mode 100644 index 00000000..55016479 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/ref.txt @@ -0,0 +1,10 @@ +fx = 9.03877847229974e-09 +X1 = 0.5005020046725166 +X2 = 0.98869323286312 +X3 = 1.5004206807677547 +Y3 = 1.4982051821768732 +Z1 = 5.400768705712512 +Z2 = 4.800786853391697 +Z3 = 3.800378633792033 +Z4 = 2.1001028103351684 +Z5 = 2.0002811485701972 diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/template.txt b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/template.txt new file mode 100644 index 00000000..8469cd87 --- /dev/null +++ b/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/template.txt @@ -0,0 +1,16 @@ +2 ,NELMS, -------- Ge(001)-c4x2 +32,1.2,0.15 ,Ge Z,da1,sap +0.6,0.6,0.6 ,BH(I),BK(I),BZ(I) +32,1.2,0.15 ,Ge Z,da1,sap +0.4,0.4,0.4 ,BH(I),BK(I),BZ(I) +9,4,0,0,2,1.7,-0.5,0.5 ,NSGS,msa,msb,nsa,nsb,dthick,DXS,DYS +8 ,NATM +1, 1.0, value_01, 1.00000, value_05 ,IELM(I),ocr(I),X(I),Y(I),Z(I +1, 1.0, value_02, 1.00000, value_06 +2, 1.0, value_03, value_04, value_07 +2, 1.0, 2.00000, 1.49751, value_08 +2, 1.0, 1.00000, 1.50000, value_09 +2, 1.0, 0.00000, 1.00000, 0.849425 +2, 1.0, 2.00000, 1.00000, 0.809425 +2, 1.0, 1.00997, 1.00000, 0.599425 +1,1 ,(WDOM,I=1,NDOM) From 655ba3b39a174cd9eeb9de7c717e4343f54c60fb Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 13 Sep 2023 12:11:55 +0900 Subject: [PATCH 11/67] Edited about "detail_timer" - Define "self.log_mode" to measure detail_timer if self.log_mode=True. - Add "normalization" section to "detail_timer". - Prepare detail_timer with the "set_detail_timer" function. - TODO: Operate log_mode with toml file. Generate txt of detail_timer. --- .../solver/sim_trhepd_rheed_mb_connect.py | 84 +++++++++++++------ 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index b485edf4..c693d2df 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -55,8 +55,12 @@ def __init__(self, info: py2dmat.Info): break if not os.access(self.path_to_solver, mode=os.X_OK): raise exception.InputError(f"ERROR: solver ({p2solver}) is not found") - self.input = Solver.Input(info) - self.output = Solver.Output(info) + + self.log_mode = False + self.set_detail_timer() + + self.input = Solver.Input(info,self.detail_timer) + self.output = Solver.Output(info,self.detail_timer) self.input.run_scheme = self.run_scheme self.output.run_scheme = self.run_scheme @@ -64,19 +68,22 @@ def __init__(self, info: py2dmat.Info): self.generate_rocking_curve = info.solver.get("generate_rocking_curve", False) self.input.generate_rocking_curve = self.generate_rocking_curve self.output.generate_rocking_curve = self.generate_rocking_curve - - if True: + + def set_detail_timer(self): + # TODO: Operate log_mode with toml file. Generate txt of detail_timer. + if self.log_mode: self.detail_timer = {} self.detail_timer["prepare_Log-directory"] = 0 self.detail_timer["make_surf_input"] = 0 self.detail_timer["launch_STR"] = 0 self.detail_timer["load_STR_result"] = 0 self.detail_timer["convolution"] = 0 + self.detail_timer["normalize_calc_I"] = 0 self.detail_timer["calculate_R-factor"] = 0 self.detail_timer["make_RockingCurve.txt"] = 0 self.detail_timer["delete_Log-directory"] = 0 - self.input.detail_timer = self.detail_timer - self.output.detail_timer = self.detail_timer + else: + self.detail_timer = None def default_run_scheme(self): """ @@ -134,10 +141,16 @@ def launch_so(self): self.output.surf_output = self.output.surf_output[0].decode().splitlines() def run(self, nprocs: int = 1, nthreads: int = 1) -> None: + if self.log_mode : time_sta = time.perf_counter() + if self.run_scheme == "connect_so": self.launch_so() elif self.run_scheme == "subprocess": self._run_by_subprocess([str(self.path_to_solver)]) + + if self.log_mode: + time_end = time.perf_counter() + self.detail_timer["launch_STR"] += time_end - time_sta class Input(object): root_dir: Path @@ -148,11 +161,17 @@ class Input(object): surface_input_file: Path surface_template_file: Path - def __init__(self, info): + def __init__(self, info, d_timer): self.mpicomm = mpi.comm() self.mpisize = mpi.size() self.mpirank = mpi.rank() - + + if d_timer is None: + self.log_mode = False + else: + self.log_mode = True + self.detail_timer = d_timer + self.root_dir = info.base["root_dir"] self.output_dir = info.base["output_dir"] @@ -237,7 +256,7 @@ def load_bulk_output_file(self, filename) : return bulk_f def prepare(self, message: py2dmat.Message): - if self.detail_timer is not None : time_sta = time.perf_counter() + if self.log_mode : time_sta = time.perf_counter() x_list = message.x step = message.step @@ -254,11 +273,11 @@ def prepare(self, message: py2dmat.Message): fitted_value = fitted_value[: len(string_list[index])] fitted_x_list.append(fitted_value) - if self.detail_timer is not None : + if self.log_mode : time_end = time.perf_counter() self.detail_timer["make_surf_input"] += time_end - time_sta - if self.detail_timer is not None : time_sta = time.perf_counter() + if self.log_mode : time_sta = time.perf_counter() if self.generate_rocking_curve: folder_name = self._pre_bulk(step, bulk_output_file, iset) @@ -270,15 +289,15 @@ def prepare(self, message: py2dmat.Message): #make workdir and copy bulk output file folder_name = self._pre_bulk(step, bulk_output_file, iset) - if self.detail_timer is not None : + if self.log_mode : time_end = time.perf_counter() self.detail_timer["prepare_Log-directory"] += time_end - time_sta - if self.detail_timer is not None : time_sta = time.perf_counter() + if self.log_mode : time_sta = time.perf_counter() self._replace(fitted_x_list, folder_name) - if self.detail_timer is not None : + if self.log_mode : time_end = time.perf_counter() self.detail_timer["make_surf_input"] += time_end - time_sta @@ -357,11 +376,17 @@ class Output(object): reference_normalized: List[float] degree_list: List[float] - def __init__(self, info): + def __init__(self, info, d_timer): self.mpicomm = mpi.comm() self.mpisize = mpi.size() self.mpirank = mpi.rank() + if d_timer is None: + self.log_mode = False + else: + self.log_mode = True + self.detail_timer = d_timer + if "dimension" in info.solver: self.dimension = info.solver["dimension"] else: @@ -592,7 +617,7 @@ def get_results(self, work_dir) -> float: os.chdir(cwd) #delete Log-directory - if self.detail_timer is not None : time_sta = time.perf_counter() + if self.log_mode : time_sta = time.perf_counter() if self.run_scheme == "subprocess": if self.remove_work_dir: @@ -600,7 +625,7 @@ def rmtree_error_handler(function, path, excinfo): print(f"WARNING: Failed to remove a working directory, {path}") shutil.rmtree(work_dir, onerror=rmtree_error_handler) - if self.detail_timer is not None : + if self.log_mode : time_end = time.perf_counter() self.detail_timer["delete_Log-directory"] += time_end - time_sta @@ -617,9 +642,10 @@ def _post(self, fitted_x_list): convolution_I_calculated_list, ) = self._calc_I_from_file() - if self.detail_timer is not None : time_sta = time.perf_counter() + if self.log_mode : time_sta = time.perf_counter() + Rfactor = self._calc_Rfactor(all_convolution_I_calculated_list_normalized) - if self.detail_timer is not None : + if self.log_mode : time_end = time.perf_counter() self.detail_timer["calculate_R-factor"] += time_end - time_sta @@ -630,7 +656,7 @@ def _post(self, fitted_x_list): if self.normalization == "MS_NORM": print('NOTICE: The output of rocking curve is not implemented when the following settings are made: self.normalization == "MS_NORM".') else: - if self.detail_timer is not None : time_sta = time.perf_counter() + if self.log_mode : time_sta = time.perf_counter() with open("RockingCurve.txt", "w") as file_RC: # Write headers file_RC.write("#") @@ -676,7 +702,7 @@ def _post(self, fitted_x_list): fmt=fmt_rc ) - if self.detail_timer is not None : + if self.log_mode : time_end = time.perf_counter() self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta @@ -689,7 +715,7 @@ def _g(self, x): return g def _calc_I_from_file(self): - if self.detail_timer is not None : time_sta = time.perf_counter() + if self.log_mode : time_sta = time.perf_counter() surface_output_file = self.surface_output_file calculated_first_line = self.calculated_first_line @@ -709,18 +735,22 @@ def _calc_I_from_file(self): Clines = file_input.readlines() file_input.close() - if self.detail_timer is not None : + if self.log_mode : time_end = time.perf_counter() self.detail_timer["load_STR_result"] += time_end - time_sta - if self.detail_timer is not None : time_sta = time.perf_counter() + if self.log_mode : time_sta = time.perf_counter() verbose_mode = False data_convolution = lib_make_convolution.calc( Clines, self.omega, verbose_mode ) self.all_convolution_I_calculated_list_normalized = [] - + if self.log_mode : + time_end = time.perf_counter() + self.detail_timer["convolution"] += time_end - time_sta + + if self.log_mode : time_sta = time.perf_counter() number = self.cal_number angle_number_convolution = data_convolution.shape[0] self.glancing_angle = data_convolution[:,0] @@ -795,9 +825,9 @@ def _calc_I_from_file(self): for h in convolution_I_calculated_list_normalized: self.all_convolution_I_calculated_list_normalized.append(h) - if self.detail_timer is not None : + if self.log_mode : time_end = time.perf_counter() - self.detail_timer["convolution"] += time_end - time_sta + self.detail_timer["normalize_calc_I"] += time_end - time_sta return ( self.all_convolution_I_calculated_list_normalized, From c2c6255cf8df2630a9f81f16745a6bdcc1822490 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 13 Sep 2023 12:50:36 +0900 Subject: [PATCH 12/67] Added comment of "surf_tempalte_width_for_fortran" and "bulk_out_width_for_fortran". --- src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index c693d2df..8c0121a5 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -183,8 +183,12 @@ def __init__(self, info, d_timer): info_s = info.solver self.run_scheme = info_s["run_scheme"] - self.surf_tempalte_width_for_fortran = 128 - self.bulk_out_width_for_fortran = 1024 + # NOTE: + # surf_tempalte_width_for_fortran: Number of strings per line of template.txt data for surf.so. + # bulk_out_width_for_fortran: Number of strings per line of bulkP.txt data for surf.so. + if self.run_scheme=="connect_so": + self.surf_tempalte_width_for_fortran = 128 + self.bulk_out_width_for_fortran = 1024 info_param = info_s.get("param", {}) v = info_param.setdefault("string_list", ["value_01", "value_02"]) From add625a000bfb0f87aa49e3cc5d3986681e12d65 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 13 Sep 2023 16:35:35 +0900 Subject: [PATCH 13/67] Added comment about "emp_str". --- src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index 8c0121a5..c87aa3af 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -127,6 +127,8 @@ def launch_so(self): n_bulk_file = len(self.input.bulk_file) m_bulk_file = self.input.bulk_out_width_for_fortran + # NOTE: The "20480" is related to the following directive in surf_so.f90. + # character(c_char), intent(inout) :: surf_out(20480) emp_str = ' '*20480 self.output.surf_output = np.array([emp_str.encode()]) self.lib.surf_so( From 4724feb800b857247eebae4293e33865eef17e87 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Thu, 14 Sep 2023 19:12:30 +0900 Subject: [PATCH 14/67] Get "generate_rocking_curve" in "Class Input" and "Class Output". --- src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index c87aa3af..ca8ef8ac 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -61,14 +61,7 @@ def __init__(self, info: py2dmat.Info): self.input = Solver.Input(info,self.detail_timer) self.output = Solver.Output(info,self.detail_timer) - - self.input.run_scheme = self.run_scheme - self.output.run_scheme = self.run_scheme - - self.generate_rocking_curve = info.solver.get("generate_rocking_curve", False) - self.input.generate_rocking_curve = self.generate_rocking_curve - self.output.generate_rocking_curve = self.generate_rocking_curve - + def set_detail_timer(self): # TODO: Operate log_mode with toml file. Generate txt of detail_timer. if self.log_mode: @@ -184,6 +177,7 @@ def __init__(self, info, d_timer): info_s = info.solver self.run_scheme = info_s["run_scheme"] + self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) # NOTE: # surf_tempalte_width_for_fortran: Number of strings per line of template.txt data for surf.so. @@ -400,6 +394,7 @@ def __init__(self, info, d_timer): info_s = info.solver self.run_scheme = info_s["run_scheme"] + self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) # solver.config info_config = info_s.get("config", {}) From 499b10aa04abe8421c524d22fa595b9855b49d9f Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Mon, 18 Sep 2023 18:04:08 +0900 Subject: [PATCH 15/67] Rename the file from RockingCurve.txt to RockingCurve_calculated.txt --- src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index ca8ef8ac..56c986c9 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -658,7 +658,7 @@ def _post(self, fitted_x_list): print('NOTICE: The output of rocking curve is not implemented when the following settings are made: self.normalization == "MS_NORM".') else: if self.log_mode : time_sta = time.perf_counter() - with open("RockingCurve.txt", "w") as file_RC: + with open("RockingCurve_calculated.txt", "w") as file_RC: # Write headers file_RC.write("#") for index in range(dimension): From 976feb1ad091b64dd58493c0b6c093e775f9887f Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 20 Sep 2023 13:28:55 +0900 Subject: [PATCH 16/67] Change in operation to remove headers in computed data files. [before]: Use lib_make_convolution.py to delete headers in the calculated data file and perform the convolution calculation. [after]: Use sim_trhepd_rheed_mb_connect.py to remove the headers of the calculated data file and lib_make_convolution.py to perform the convolution calculation. --- src/py2dmat/solver/lib_make_convolution.py | 87 +------------------ .../solver/sim_trhepd_rheed_mb_connect.py | 39 ++++++++- 2 files changed, 39 insertions(+), 87 deletions(-) diff --git a/src/py2dmat/solver/lib_make_convolution.py b/src/py2dmat/solver/lib_make_convolution.py index 379e6a28..ae05e16a 100644 --- a/src/py2dmat/solver/lib_make_convolution.py +++ b/src/py2dmat/solver/lib_make_convolution.py @@ -1,96 +1,15 @@ import numpy as np import sys -def calc(Clines, omega, verbose_mode): - if verbose_mode: - #print('arg:filename=',args.filename) - print('omega =',omega) +def calc(RC_data_org, RC_data_cnv, number_of_beams, number_of_glancing_angles, omega, verbose_mode): sigma = 0.5 * omega / (np.sqrt(2.0*np.log(2.0))) - #def g(x): - # g = (0.939437 / omega) * np.exp(-2.77259 * (x ** 2.0 / omega ** 2.0)) - # return g def g(x): g = (1.0 / (sigma*np.sqrt(2.0*np.pi))) * np.exp(-0.5 * x ** 2.0 / sigma ** 2.0) return g - # Read the file header - if verbose_mode: - print("debug:lib_make_convolution.py") - print(f"Clines[0:5]=",Clines[0:5]) - #print(line) - - line = Clines[0] - - if line == ' FILE OUTPUT for UNIT3\n': - alpha_lines = 1 - else: - alpha_lines = 0 - - if verbose_mode: print("debug alpha_lines=",alpha_lines) - - number_of_lines = int(len(Clines)) - number_of_header_lines = 4 + alpha_lines - - if verbose_mode: - print("number_of_lines =", number_of_lines) - print("number_of_header_lines =", number_of_header_lines) - - #degree_list = [] - #C_list = [] - - #print("file header :", line) - line = Clines[1 + alpha_lines] - #print("file header :", line) - #sys.exit() - line = line.replace(",", "") - data = line.split() - - number_of_azimuth_angles = int(data[0]) - number_of_glancing_angles = int(data[1]) - number_of_beams = int(data[2]) - - if verbose_mode: - print("number of azimuth angles = ", number_of_azimuth_angles) - print("number of glancing angles = ", number_of_glancing_angles) - print("number of beams = ", number_of_beams) - - # Define the array for the rocking curve data. - # Note the components with (beam-index)=0 are the degree data - RC_data_org = np.zeros((number_of_glancing_angles, number_of_beams+1)) - RC_data_cnv = np.zeros((number_of_glancing_angles, number_of_beams+1)) - - # Read the file header - line = Clines[2+ alpha_lines] - #print("file header :", line, end="") - line = Clines[3+ alpha_lines] - #print("file header :", line, end="") - line = line.replace(",", "") - data = line.split() - #print(data) - - if verbose_mode: - """ - print("beam index (p,q): i p_i q_i") - for beam_index in range(number_of_beams): - print(beam_index, data[beam_index*2], data[beam_index*2+1]) - """ - pass - - for g_angle_index in range(number_of_glancing_angles): - line_index = number_of_header_lines + g_angle_index - line = Clines[ line_index ] - # print("data line: ", line_index, g_angle_index, line) - line = line.replace(",", "") - data = line.split() - # print(data) - RC_data_org[g_angle_index,0]=float(data[0]) - RC_data_cnv[g_angle_index,0]=float(data[0]) - for beam_index in range(number_of_beams): - RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] - angle_interval = RC_data_org[1,0] - RC_data_org[0,0] if verbose_mode: @@ -107,11 +26,7 @@ def g(x): print("beam_index, index, index2, g(RC_data_org[index,0] - RC_data_org[index2,0]) =",beam_index, index, index2, g(RC_data_org[index,0] - RC_data_org[index2,0])) RC_data_cnv[index, beam_index+1]=integral - #np.savetxt("convolution.txt", RC_data_cnv, fmt="%.5e") - if verbose_mode: print("RC_data_cnv =\n",RC_data_cnv) return RC_data_cnv - -#np.savetxt("original.txt", RC_data_org, fmt="%.5e") diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index 56c986c9..33bf6afc 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -736,6 +736,43 @@ def _calc_I_from_file(self): Clines = file_input.readlines() file_input.close() + # Extract STR results (glancing angle and intensity) from Clines. + # Read the file header + line = Clines[0] + + if line == ' FILE OUTPUT for UNIT3\n': + alpha_lines = 1 + else: + alpha_lines = 0 + + number_of_lines = int(len(Clines)) + number_of_header_lines = 4 + alpha_lines + + line = Clines[1 + alpha_lines] + line = line.replace(",", "") + data = line.split() + + number_of_azimuth_angles = int(data[0]) + number_of_glancing_angles = int(data[1]) + number_of_beams = int(data[2]) + + # Define the array for the rocking curve data. + # Note the components with (beam-index)=0 are the degree data + RC_data_org = np.zeros((number_of_glancing_angles, number_of_beams+1)) + RC_data_cnv = np.zeros((number_of_glancing_angles, number_of_beams+1)) + + for g_angle_index in range(number_of_glancing_angles): + line_index = number_of_header_lines + g_angle_index + line = Clines[ line_index ] + # print("data line: ", line_index, g_angle_index, line) + line = line.replace(",", "") + data = line.split() + # print(data) + RC_data_org[g_angle_index,0]=float(data[0]) + RC_data_cnv[g_angle_index,0]=float(data[0]) + for beam_index in range(number_of_beams): + RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] + if self.log_mode : time_end = time.perf_counter() self.detail_timer["load_STR_result"] += time_end - time_sta @@ -743,7 +780,7 @@ def _calc_I_from_file(self): if self.log_mode : time_sta = time.perf_counter() verbose_mode = False data_convolution = lib_make_convolution.calc( - Clines, self.omega, verbose_mode + RC_data_org, RC_data_cnv, number_of_beams, number_of_glancing_angles, self.omega, verbose_mode ) self.all_convolution_I_calculated_list_normalized = [] From 3755365d6a88193e1f36d3ff8f6dff79e7f8f0af Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 20 Sep 2023 16:10:35 +0900 Subject: [PATCH 17/67] delete 'RC_data_cnv' in sim_trhepd_rheed_mb_connect.py --- src/py2dmat/solver/lib_make_convolution.py | 9 +++++++-- src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py | 4 +--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/py2dmat/solver/lib_make_convolution.py b/src/py2dmat/solver/lib_make_convolution.py index ae05e16a..51299029 100644 --- a/src/py2dmat/solver/lib_make_convolution.py +++ b/src/py2dmat/solver/lib_make_convolution.py @@ -1,7 +1,8 @@ import numpy as np import sys +import copy -def calc(RC_data_org, RC_data_cnv, number_of_beams, number_of_glancing_angles, omega, verbose_mode): +def calc(RC_data_org, number_of_beams, number_of_glancing_angles, omega, verbose_mode): sigma = 0.5 * omega / (np.sqrt(2.0*np.log(2.0))) @@ -10,12 +11,16 @@ def g(x): return g + RC_data_cnv = np.zeros((number_of_glancing_angles, number_of_beams+1)) + #copy glancing angle + RC_data_cnv[:,0] = copy.deepcopy(RC_data_org[:,0]) + angle_interval = RC_data_org[1,0] - RC_data_org[0,0] if verbose_mode: print("RC_data_org =\n",RC_data_org) print("RC_data_cnv =\n",RC_data_cnv) - print('angle_ interval=', angle_interval) + print('angle_interval=', angle_interval) for beam_index in range(number_of_beams): for index in range(number_of_glancing_angles): diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index 33bf6afc..65cdcf59 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -759,7 +759,6 @@ def _calc_I_from_file(self): # Define the array for the rocking curve data. # Note the components with (beam-index)=0 are the degree data RC_data_org = np.zeros((number_of_glancing_angles, number_of_beams+1)) - RC_data_cnv = np.zeros((number_of_glancing_angles, number_of_beams+1)) for g_angle_index in range(number_of_glancing_angles): line_index = number_of_header_lines + g_angle_index @@ -769,7 +768,6 @@ def _calc_I_from_file(self): data = line.split() # print(data) RC_data_org[g_angle_index,0]=float(data[0]) - RC_data_cnv[g_angle_index,0]=float(data[0]) for beam_index in range(number_of_beams): RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] @@ -780,7 +778,7 @@ def _calc_I_from_file(self): if self.log_mode : time_sta = time.perf_counter() verbose_mode = False data_convolution = lib_make_convolution.calc( - RC_data_org, RC_data_cnv, number_of_beams, number_of_glancing_angles, self.omega, verbose_mode + RC_data_org, number_of_beams, number_of_glancing_angles, self.omega, verbose_mode ) self.all_convolution_I_calculated_list_normalized = [] From 5e1a9211067fed66e7a549bfec479cdc5a6fbe3f Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Tue, 26 Sep 2023 17:37:14 +0900 Subject: [PATCH 18/67] Modification of the reference data (= experiment data) reading section. - Additional options: "reference_first_line", "reference_last_line". The former specifies the first line to read the reference data, and the latter specifies the last line to read the reference data. - Changed the reading of reference data from the np.loadtxt function to using the open, read, readlines, and split functions. --- .../solver/sim_trhepd_rheed_mb_connect.py | 74 ++++++++++++++----- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index 65cdcf59..be0696a8 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -486,33 +486,34 @@ def __init__(self, info, d_timer): # solver.reference info_ref = info_s.get("reference", {}) - reference_path = info_ref.get("path", "experiment.txt") - - v = info_ref.setdefault("first", 1) + v = info_ref.setdefault("reference_first_line", 1) if not (isinstance(v, int) and v >= 0): raise exception.InputError( "ERROR: reference_first_line should be non-negative integer" ) firstline = v - v = info_ref.setdefault("last", 56) - if not (isinstance(v, int) and v >= firstline): - raise exception.InputError( - "ERROR: reference_last_line < reference_first_line" - ) + # None is dummy value + # If "reference_last_line" is not specified in the toml file, + # the last line of the reference file is used for the R-factor calculation. + v = info_ref.setdefault("reference_last_line", None) + if v is None: + reference_are_read_to_final_line = True + else: + reference_are_read_to_final_line = False + if not (isinstance(v, int) and v >= firstline): + raise exception.InputError( + "ERROR: reference_last_line < reference_first_line" + ) lastline = v - - # Read experiment data - if self.mpirank == 0: - data_e = np.loadtxt(reference_path) - else: - data_e = None - data_experiment = self.mpicomm.bcast(data_e,root=0) - - self.beam_number_experiment = data_experiment.shape[1] + reference_path = info_ref.get("path", "experiment.txt") + data_experiment = self.read_experiment( + reference_path, firstline, lastline, + reference_are_read_to_final_line ) self.angle_number_experiment = data_experiment.shape[0] - + self.beam_number_exp_raw = data_experiment.shape[1] + v = info_ref.get("exp_number", None) if v == None : @@ -525,7 +526,7 @@ def __init__(self, info, d_timer): "ERROR: 'exp_number' must be a list type." ) - if max(v) > self.beam_number_experiment: + if max(v) > self.beam_number_exp_raw : raise exception.InputError( "ERROR: The 'exp_number' setting is wrong." ) @@ -537,7 +538,9 @@ def __init__(self, info, d_timer): ) self.exp_number = v + self.beam_number_experiment = len(self.exp_number) number_ex = self.exp_number + sum_experiment = 0 for i in number_ex: sum_experiment += sum(data_experiment[::,i]) @@ -601,7 +604,38 @@ def __init__(self, info, d_timer): ] for p in self.reference_normalized: self.all_reference_normalized.append(p) - + + def read_experiment(self, ref_path, first, last, read_to_final_line): + # Read experiment data + if self.mpirank == 0: + file_input = open(ref_path, "r") + Elines = file_input.readlines() + + firstline = first + if read_to_final_line : + lastline = len(Elines) + else: + lastline = last + + n_exp_row = lastline-firstline+1 + + # get value from data + for row_index in range(n_exp_row) : + line_index = firstline + row_index - 1 + line = Elines[line_index] + data = line.split() + # first loop + if row_index == 0: + n_exp_column = len(data) + data_e = np.zeros((n_exp_row, n_exp_column)) #init value + + for column_index in range(n_exp_column): + data_e[row_index, column_index] = float(data[column_index]) + else: + data_e = None + data_exp = self.mpicomm.bcast(data_e,root=0) + return data_exp + def prepare(self, fitted_x_list): self.fitted_x_list = fitted_x_list From 168da7dd8ec540ab603d4b15cbc47e668b11a09f Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Thu, 28 Sep 2023 18:54:47 +0900 Subject: [PATCH 19/67] "limitation" is available. - Using the coefficients co_a and co_b, you can make it search only the range that meets the following constraint formula. --- co_a[1,1]*x_[1] + co_a[1,2]*x_[2] + ... + co_a[1,n]*x_[n] + co_b[1] > 0 co_a[2,1]*x_[1] + co_a[2,2]*x_[2] + ... + co_a[2,n]*x_[n] + co_b[2] > 0 ... co_a[m,1]*x_[1] + co_a[m,2]*x_[2] + ... + co_a[m,n]*x_[n] + co_b[m] > 0 --- - co_a and co_b can be defined in option [runner.limitation] in the toml file. - When setting constraint formulas, both co_a and co_b must be set in the toml file. - If neither co_a nor co_b are set in the toml file, the calculation can be performed without constraint formulas. - If the initial_list set in [algorithm.param] does not fit the constraint formulas, an error occurs. - If initial_list is not set in [algorithm.param], then initial coordinates that fit the constraint formulas are created. --- src/py2dmat/_runner.py | 66 +++++++++++++++++++++++++---- src/py2dmat/algorithm/_algorithm.py | 32 +++++++++++--- src/py2dmat/util/limitation.py | 52 +++++++++++++++++++++++ 3 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 src/py2dmat/util/limitation.py diff --git a/src/py2dmat/_runner.py b/src/py2dmat/_runner.py index 62027cfa..7e21e21f 100644 --- a/src/py2dmat/_runner.py +++ b/src/py2dmat/_runner.py @@ -26,6 +26,7 @@ import py2dmat import py2dmat.util.read_matrix import py2dmat.util.mapping +import py2dmat.util.limitation from py2dmat.exception import InputError # type hints @@ -141,6 +142,7 @@ def __init__( solver: py2dmat.solver.SolverBase, info: Optional[py2dmat.Info] = None, mapping=None, + limitation=None, ): """ @@ -178,6 +180,51 @@ def __init__( self.mapping = py2dmat.util.mapping.Affine(A=A, b=b) else: self.mapping = mapping + + self.ndim = info.base["dimension"] + if limitation is None: + info_limitation = info.runner.get("limitation",{}) + co_a: Optional[np.ndarray] = py2dmat.util.read_matrix.read_matrix( + info_limitation.get("co_a", []) + ) + co_b: Optional[np.ndarray] = py2dmat.util.read_matrix.read_matrix( + info_limitation.get("co_b", []) + ) + if co_a is not None: + if co_a.size == 0: + co_a = None + else: + if co_a.ndim != 2: + raise InputError("co_a should be a matrix") + if co_a.shape[1] != self.ndim: + msg ='The number of columns in co_a should be equal to' + msg+='the value of "dimension" in the [base] section' + raise InputError(msg) + n_row_co_a = co_a.shape[0] + if co_b is not None: + if co_b.size == 0: + if co_a is None: + co_b = None + else: # co_a is not None: + msg = "ERROR: co_a is defined but co_b is not." + raise InputError(msg) + elif co_b.ndim == 2: + if co_a is not None: + if co_b.shape[0] == 1 or co_b.shape[1] == 1: + co_b = co_b.reshape(-1) + else: + raise InputError("co_b should be a vector") + if co_b.size != n_row_co_a: + msg ='The number of row in co_a should be equal to' + msg+='the number of size in co_b' + raise InputError(msg) + else: # co_a is None: + msg = "ERROR: co_b is defined but co_a is not." + raise InputError(msg) + + elif co_b.ndim > 2: + raise InputError("co_b should be a vector") + self.limitation = py2dmat.util.limitation.Inequality(co_a, co_b) def prepare(self, proc_dir: Path): self.logger.prepare(proc_dir) @@ -185,14 +232,17 @@ def prepare(self, proc_dir: Path): def submit( self, message: py2dmat.Message, nprocs: int = 1, nthreads: int = 1 ) -> float: - x = self.mapping(message.x) - message_indeed = py2dmat.Message(x, message.step, message.set) - self.solver.prepare(message_indeed) - cwd = os.getcwd() - os.chdir(self.solver.work_dir) - self.solver.run(nprocs, nthreads) - os.chdir(cwd) - result = self.solver.get_results() + if self.limitation.judge(message.x): + x = self.mapping(message.x) + message_indeed = py2dmat.Message(x, message.step, message.set) + self.solver.prepare(message_indeed) + cwd = os.getcwd() + os.chdir(self.solver.work_dir) + self.solver.run(nprocs, nthreads) + os.chdir(cwd) + result = self.solver.get_results() + else: + result = np.inf self.logger.count(message, result) return result diff --git a/src/py2dmat/algorithm/_algorithm.py b/src/py2dmat/algorithm/_algorithm.py index cf503b7c..3467f772 100644 --- a/src/py2dmat/algorithm/_algorithm.py +++ b/src/py2dmat/algorithm/_algorithm.py @@ -26,6 +26,7 @@ import numpy as np import py2dmat +import py2dmat.util.limitation from py2dmat import exception, mpi # for type hints @@ -169,17 +170,38 @@ def _read_param( if initial_list.ndim == 1: initial_list = initial_list.reshape(1, -1) if initial_list.size == 0: - initial_list = min_list + (max_list - min_list) * self.rng.rand( - num_walkers, self.dimension - ) + # Repeat until an "initial_list" is generated + # that satisfies the constraint formula. + loop_count = 0 + while True: + judge_result = [] + initial_list = min_list + (max_list - min_list) * self.rng.rand( + num_walkers, self.dimension + ) + for walker_index in range(num_walkers): + judge = self.runner.limitation.judge( + initial_list[walker_index,:]) + judge_result.append(judge) + if all(judge_result): + break + else: + loop_count += 1 if initial_list.shape[0] != num_walkers: raise exception.InputError( f"ERROR: initial_list.shape[0] != num_walkers ({initial_list.shape[0]} != {num_walkers})" ) if initial_list.shape[1] != self.dimension: raise exception.InputError( - f"ERROR: initial_list.shape[1] != dimension ({initial_list.shape[1]} != {self.dimension})" - ) + f"ERROR: initial_list.shape[1] != dimension ({initial_list.shape[1]} != {self.dimension})" ) + judge_result = [] + for walker_index in range(num_walkers): + judge = self.runner.limitation.judge( + initial_list[walker_index,:]) + judge_result.append(judge) + if not all(judge_result): + raise exception.InputError( + "ERROR: initial_list does not satisfy the constraint formula." + ) return initial_list, min_list, max_list, unit_list def _meshgrid( diff --git a/src/py2dmat/util/limitation.py b/src/py2dmat/util/limitation.py new file mode 100644 index 00000000..0c973f7f --- /dev/null +++ b/src/py2dmat/util/limitation.py @@ -0,0 +1,52 @@ +from abc import ABCMeta, abstractmethod + +import numpy as np + +import py2dmat + +# for type hints +from pathlib import Path +from typing import List, Optional, TYPE_CHECKING, Dict, Tuple + +class LimitationBase(metaclass=ABCMeta): + @abstractmethod + def __init__ (self, a: Optional[np.ndarray] = None, + b: Optional[np.ndarray] = None): + if (a is not None) or (b is not None): + if a is None: + msg = "ERROR: b is defined but a is not." + raise RuntimeError(msg) + if b is None: + msg = "ERROR: a is defined but b is not." + raise RuntimeError(msg) + if (a is None) and (b is None): + self.islimitary = False + else: + self.islimitary = True + self.a = a + self.b = b + self.n_formura = a.shape[0] + self.ndim = a.shape[1] + + @abstractmethod + def judge(self, x: np.ndarray) -> bool: + pass + +class Inequality(LimitationBase): + def __init__ (self, a: Optional[np.ndarray] = None, + b: Optional[np.ndarray] = None): + super().__init__(a, b) + + def judge(self, x: np.ndarray) -> bool: + if self.islimitary : + judge_formula = [] + for formula_index in range(self.n_formura): + value_formula = 0 + for dim_index in range(self.ndim): + value_formula += self.a[formula_index, dim_index]*x[dim_index] + value_formula += self.b[formula_index] + judge_formula.append(value_formula>0) + judge_result = all(judge_formula) + else: + judge_result = True + return judge_result From db51b9328440110f4170955d8efd873f6a3a29c9 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Tue, 3 Oct 2023 19:30:38 +0900 Subject: [PATCH 20/67] Modification of the calculate data reading section. - Added option "calculated_first_line", "calculated_last_line", "calculated_info_line" - "calculated_first_line" specifies the first line to be read from the calculated data file. - "calculated_last_line" specifies the last line to be read from the calculated data file. - "calculated_info_line" specifies the line in the calculated data file where the number of beams and glancing angles are written. - If the number of glancing angles read from the calculated data file does not match the user-specified number of lines to be read from the calculated data file ("calculated_last_line" - "calculated_first_line" + 1), WARNING is output. --- .../solver/sim_trhepd_rheed_mb_connect.py | 180 +++++++++++------- 1 file changed, 107 insertions(+), 73 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index be0696a8..c09feb98 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -396,47 +396,6 @@ def __init__(self, info, d_timer): self.run_scheme = info_s["run_scheme"] self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) - # solver.config - info_config = info_s.get("config", {}) - self.surface_output_file = info_config.get( - "surface_output_file", "surf-bulkP.s" - ) - - v = info_config.get("calculated_first_line", 5) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: calculated_first_line should be non-negative integer" - ) - self.calculated_first_line = v - - v = info_config.get("calculated_last_line", 60) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: calculated_last_line should be non-negative integer" - ) - self.calculated_last_line = v - - v = info_config.get("row_number", 8) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: row_number should be non-negative integer" - ) - self.row_number = v - - v = info_config.get("cal_number",None) - - if v == None : - raise exception.InputError( - "ERROR: You have to set the 'cal_number'." - ) - - if not isinstance(v, list): - raise exception.InputError( - "ERROR: 'cal_number' must be a list type." - ) - - self.cal_number = v - # solver.post info_post = info_s.get("post", {}) v = info_post.get("normalization", "TOTAL") @@ -465,13 +424,8 @@ def __init__(self, info, d_timer): v = info_post.get("spot_weight", None) if v is None: raise exception.InputError('ERROR:If normalization="MS_NORM_SET_WGT", the weight must be set in solver.post.') - if len(v) != len(self.cal_number): - raise exception.InputError( - "len('cal_number') and len('spot_weight') do not match." - ) - self.spot_weight = np.array(v)/sum(v) - + # solver.param info_param = info_s.get("param", {}) v = info_param.setdefault("string_list", ["value_01", "value_02"]) @@ -604,6 +558,79 @@ def __init__(self, info, d_timer): ] for p in self.reference_normalized: self.all_reference_normalized.append(p) + + # solver.config + info_config = info_s.get("config", {}) + self.surface_output_file = info_config.get( + "surface_output_file", "surf-bulkP.s" + ) + + v = info_config.get("calculated_first_line", 5) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: calculated_first_line should be non-negative integer" + ) + self.calculated_first_line = v + + v = info_config.get( + "calculated_last_line", + self.calculated_first_line + self.angle_number_experiment-1 + ) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: calculated_last_line should be non-negative integer" + ) + self.calculated_last_line = v + + # Number of lines in the computation file + # used for R-factor calculations. + self.calculated_nlines = (self.calculated_last_line - + self.calculated_first_line + 1 ) + + if self.angle_number_experiment != self.calculated_nlines : + raise exception.InputError( + "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." + ) + + # Variable indicating whether the warning + # "self.calculated_nlines does not match + # the number of glancing angles in the calculated file" + # is displayed. + self.isWarning_calcnline = False + + v = info_config.get("calculated_info_line", 2) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: calculated_info_line should be non-negative integer" + ) + self.calculated_info_line = v + + v = info_config.get("row_number", 8) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: row_number should be non-negative integer" + ) + self.row_number = v + + v = info_config.get("cal_number",None) + + if v == None : + raise exception.InputError( + "ERROR: You have to set the 'cal_number'." + ) + + if not isinstance(v, list): + raise exception.InputError( + "ERROR: 'cal_number' must be a list type." + ) + + if self.normalization=="MS_NORM_SET_WGT": + if len(self.spot_weight) != len(v): + raise exception.InputError( + "len('cal_number') and len('spot_weight') do not match." + ) + + self.cal_number = v def read_experiment(self, ref_path, first, last, read_to_final_line): # Read experiment data @@ -755,12 +782,14 @@ def _calc_I_from_file(self): surface_output_file = self.surface_output_file calculated_first_line = self.calculated_first_line calculated_last_line = self.calculated_last_line + calculated_info_line = self.calculated_info_line + calculated_nlines = self.calculated_nlines + omega = self.omega row_number = self.row_number degree_max = self.degree_max degree_list = self.degree_list - nlines = calculated_last_line - calculated_first_line + 1 - assert 0 < nlines + assert 0 < calculated_nlines if self.run_scheme == "connect_so": Clines = self.surf_output @@ -769,40 +798,41 @@ def _calc_I_from_file(self): file_input = open(self.surface_output_file, "r") Clines = file_input.readlines() file_input.close() - - # Extract STR results (glancing angle and intensity) from Clines. - # Read the file header - line = Clines[0] - - if line == ' FILE OUTPUT for UNIT3\n': - alpha_lines = 1 - else: - alpha_lines = 0 - - number_of_lines = int(len(Clines)) - number_of_header_lines = 4 + alpha_lines - - line = Clines[1 + alpha_lines] + + # Reads the number of glancing angles and beams + line = Clines[calculated_info_line-1] line = line.replace(",", "") data = line.split() - number_of_azimuth_angles = int(data[0]) - number_of_glancing_angles = int(data[1]) - number_of_beams = int(data[2]) - + calc_number_of_g_angles_org = int(data[1]) + calc_number_of_beams_org = int(data[2]) + + if calc_number_of_g_angles_org != calculated_nlines: + if self.mpirank == 0 and not self.isWarning_calcnline : + msg ="WARNING:\n" + msg+="The number of lines in the calculated file " + msg+="that you have set up does not match " + msg+="the number of glancing angles in the calculated file.\n" + msg+="The number of lines (nline) in the calculated file " + msg+="used for the R-factor calculation " + msg+="is determined by the following values\n" + msg+='nline = "calculated_last_line" - "calculated_first_line" + 1.' + print(msg) + self.isWarning_calcnline = True + calc_number_of_g_angles = calculated_nlines + # Define the array for the rocking curve data. # Note the components with (beam-index)=0 are the degree data - RC_data_org = np.zeros((number_of_glancing_angles, number_of_beams+1)) - - for g_angle_index in range(number_of_glancing_angles): - line_index = number_of_header_lines + g_angle_index + RC_data_org = np.zeros((calc_number_of_g_angles, calc_number_of_beams_org+1)) + for g_angle_index in range(calc_number_of_g_angles): + line_index = (calculated_first_line - 1) + g_angle_index line = Clines[ line_index ] # print("data line: ", line_index, g_angle_index, line) line = line.replace(",", "") data = line.split() # print(data) RC_data_org[g_angle_index,0]=float(data[0]) - for beam_index in range(number_of_beams): + for beam_index in range(calc_number_of_beams_org): RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] if self.log_mode : @@ -812,7 +842,11 @@ def _calc_I_from_file(self): if self.log_mode : time_sta = time.perf_counter() verbose_mode = False data_convolution = lib_make_convolution.calc( - RC_data_org, number_of_beams, number_of_glancing_angles, self.omega, verbose_mode + RC_data_org, + calc_number_of_beams_org, + calc_number_of_g_angles, + omega, + verbose_mode, ) self.all_convolution_I_calculated_list_normalized = [] From 4147260a8032d5dbff010a14ed3037a0bc2bccf5 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 4 Oct 2023 14:01:21 +0900 Subject: [PATCH 21/67] delete row_number --- src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index c09feb98..8f22b7ff 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -367,7 +367,6 @@ class Output(object): Rfactor_type: str calculated_first_line: int calculated_last_line: int - row_number: int degree_max: float degree_list: List[float] @@ -605,15 +604,7 @@ def __init__(self, info, d_timer): ) self.calculated_info_line = v - v = info_config.get("row_number", 8) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: row_number should be non-negative integer" - ) - self.row_number = v - - v = info_config.get("cal_number",None) - + v = info_config.get("cal_number",None) if v == None : raise exception.InputError( "ERROR: You have to set the 'cal_number'." @@ -785,7 +776,6 @@ def _calc_I_from_file(self): calculated_info_line = self.calculated_info_line calculated_nlines = self.calculated_nlines omega = self.omega - row_number = self.row_number degree_max = self.degree_max degree_list = self.degree_list From 2a55492b134e10044905ffda9f7bc0540c0e49e3 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 4 Oct 2023 14:10:50 +0900 Subject: [PATCH 22/67] delete degree_max and degree_list --- src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index 8f22b7ff..556a0ba0 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -367,13 +367,10 @@ class Output(object): Rfactor_type: str calculated_first_line: int calculated_last_line: int - degree_max: float - degree_list: List[float] reference: List[float] reference_norm: float reference_normalized: List[float] - degree_list: List[float] def __init__(self, info, d_timer): self.mpicomm = mpi.comm() @@ -434,9 +431,6 @@ def __init__(self, info, d_timer): ) self.string_list = v - v = info_param.get("degree_max", 6.0) - self.degree_max = v - # solver.reference info_ref = info_s.get("reference", {}) v = info_ref.setdefault("reference_first_line", 1) @@ -498,7 +492,6 @@ def __init__(self, info, d_timer): for i in number_ex: sum_experiment += sum(data_experiment[::,i]) - self.degree_list = (data_experiment[::,0]) self.all_reference_normalized = [] for index, j in enumerate(number_ex): self.reference = (data_experiment[::,j]) @@ -685,7 +678,6 @@ def rmtree_error_handler(function, path, excinfo): return Rfactor def _post(self, fitted_x_list): - degree_list = self.degree_list I_experiment_norm = self.reference_norm I_experiment_list = self.reference @@ -776,8 +768,6 @@ def _calc_I_from_file(self): calculated_info_line = self.calculated_info_line calculated_nlines = self.calculated_nlines omega = self.omega - degree_max = self.degree_max - degree_list = self.degree_list assert 0 < calculated_nlines From fd8fcc5e432d5051aa5198f7c81649c87daa9b55 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 4 Oct 2023 14:16:44 +0900 Subject: [PATCH 23/67] Rename the variable "self.log_mode" to "self.isLogmode". --- .../solver/sim_trhepd_rheed_mb_connect.py | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index 556a0ba0..8c527050 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -56,7 +56,7 @@ def __init__(self, info: py2dmat.Info): if not os.access(self.path_to_solver, mode=os.X_OK): raise exception.InputError(f"ERROR: solver ({p2solver}) is not found") - self.log_mode = False + self.isLogmode = False self.set_detail_timer() self.input = Solver.Input(info,self.detail_timer) @@ -64,7 +64,7 @@ def __init__(self, info: py2dmat.Info): def set_detail_timer(self): # TODO: Operate log_mode with toml file. Generate txt of detail_timer. - if self.log_mode: + if self.isLogmode: self.detail_timer = {} self.detail_timer["prepare_Log-directory"] = 0 self.detail_timer["make_surf_input"] = 0 @@ -136,14 +136,14 @@ def launch_so(self): self.output.surf_output = self.output.surf_output[0].decode().splitlines() def run(self, nprocs: int = 1, nthreads: int = 1) -> None: - if self.log_mode : time_sta = time.perf_counter() + if self.isLogmode : time_sta = time.perf_counter() if self.run_scheme == "connect_so": self.launch_so() elif self.run_scheme == "subprocess": self._run_by_subprocess([str(self.path_to_solver)]) - if self.log_mode: + if self.isLogmode: time_end = time.perf_counter() self.detail_timer["launch_STR"] += time_end - time_sta @@ -162,9 +162,9 @@ def __init__(self, info, d_timer): self.mpirank = mpi.rank() if d_timer is None: - self.log_mode = False + self.isLogmode = False else: - self.log_mode = True + self.isLogmode = True self.detail_timer = d_timer self.root_dir = info.base["root_dir"] @@ -256,7 +256,7 @@ def load_bulk_output_file(self, filename) : return bulk_f def prepare(self, message: py2dmat.Message): - if self.log_mode : time_sta = time.perf_counter() + if self.isLogmode : time_sta = time.perf_counter() x_list = message.x step = message.step @@ -273,11 +273,11 @@ def prepare(self, message: py2dmat.Message): fitted_value = fitted_value[: len(string_list[index])] fitted_x_list.append(fitted_value) - if self.log_mode : + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["make_surf_input"] += time_end - time_sta - if self.log_mode : time_sta = time.perf_counter() + if self.isLogmode : time_sta = time.perf_counter() if self.generate_rocking_curve: folder_name = self._pre_bulk(step, bulk_output_file, iset) @@ -289,15 +289,15 @@ def prepare(self, message: py2dmat.Message): #make workdir and copy bulk output file folder_name = self._pre_bulk(step, bulk_output_file, iset) - if self.log_mode : + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["prepare_Log-directory"] += time_end - time_sta - if self.log_mode : time_sta = time.perf_counter() + if self.isLogmode : time_sta = time.perf_counter() self._replace(fitted_x_list, folder_name) - if self.log_mode : + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["make_surf_input"] += time_end - time_sta @@ -378,9 +378,9 @@ def __init__(self, info, d_timer): self.mpirank = mpi.rank() if d_timer is None: - self.log_mode = False + self.isLogmode = False else: - self.log_mode = True + self.isLogmode = True self.detail_timer = d_timer if "dimension" in info.solver: @@ -663,7 +663,7 @@ def get_results(self, work_dir) -> float: os.chdir(cwd) #delete Log-directory - if self.log_mode : time_sta = time.perf_counter() + if self.isLogmode : time_sta = time.perf_counter() if self.run_scheme == "subprocess": if self.remove_work_dir: @@ -671,7 +671,7 @@ def rmtree_error_handler(function, path, excinfo): print(f"WARNING: Failed to remove a working directory, {path}") shutil.rmtree(work_dir, onerror=rmtree_error_handler) - if self.log_mode : + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["delete_Log-directory"] += time_end - time_sta @@ -687,10 +687,10 @@ def _post(self, fitted_x_list): convolution_I_calculated_list, ) = self._calc_I_from_file() - if self.log_mode : time_sta = time.perf_counter() + if self.isLogmode : time_sta = time.perf_counter() Rfactor = self._calc_Rfactor(all_convolution_I_calculated_list_normalized) - if self.log_mode : + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["calculate_R-factor"] += time_end - time_sta @@ -701,7 +701,7 @@ def _post(self, fitted_x_list): if self.normalization == "MS_NORM": print('NOTICE: The output of rocking curve is not implemented when the following settings are made: self.normalization == "MS_NORM".') else: - if self.log_mode : time_sta = time.perf_counter() + if self.isLogmode : time_sta = time.perf_counter() with open("RockingCurve_calculated.txt", "w") as file_RC: # Write headers file_RC.write("#") @@ -747,7 +747,7 @@ def _post(self, fitted_x_list): fmt=fmt_rc ) - if self.log_mode : + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta @@ -760,7 +760,7 @@ def _g(self, x): return g def _calc_I_from_file(self): - if self.log_mode : time_sta = time.perf_counter() + if self.isLogmode : time_sta = time.perf_counter() surface_output_file = self.surface_output_file calculated_first_line = self.calculated_first_line @@ -815,11 +815,11 @@ def _calc_I_from_file(self): for beam_index in range(calc_number_of_beams_org): RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] - if self.log_mode : + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["load_STR_result"] += time_end - time_sta - if self.log_mode : time_sta = time.perf_counter() + if self.isLogmode : time_sta = time.perf_counter() verbose_mode = False data_convolution = lib_make_convolution.calc( RC_data_org, @@ -830,11 +830,11 @@ def _calc_I_from_file(self): ) self.all_convolution_I_calculated_list_normalized = [] - if self.log_mode : + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["convolution"] += time_end - time_sta - if self.log_mode : time_sta = time.perf_counter() + if self.isLogmode : time_sta = time.perf_counter() number = self.cal_number angle_number_convolution = data_convolution.shape[0] self.glancing_angle = data_convolution[:,0] @@ -909,7 +909,7 @@ def _calc_I_from_file(self): for h in convolution_I_calculated_list_normalized: self.all_convolution_I_calculated_list_normalized.append(h) - if self.log_mode : + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["normalize_calc_I"] += time_end - time_sta From dc462c1336a6f62e115846902650ae9dec24eeab Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 4 Oct 2023 14:59:01 +0900 Subject: [PATCH 24/67] Calculate "angle_interval" in the "for" loop of the convolution calculation. --- src/py2dmat/solver/lib_make_convolution.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/py2dmat/solver/lib_make_convolution.py b/src/py2dmat/solver/lib_make_convolution.py index 51299029..8d591013 100644 --- a/src/py2dmat/solver/lib_make_convolution.py +++ b/src/py2dmat/solver/lib_make_convolution.py @@ -15,8 +15,6 @@ def g(x): #copy glancing angle RC_data_cnv[:,0] = copy.deepcopy(RC_data_org[:,0]) - angle_interval = RC_data_org[1,0] - RC_data_org[0,0] - if verbose_mode: print("RC_data_org =\n",RC_data_org) print("RC_data_cnv =\n",RC_data_cnv) @@ -25,7 +23,12 @@ def g(x): for beam_index in range(number_of_beams): for index in range(number_of_glancing_angles): integral = 0.0 + angle_interval = 0.0 for index2 in range(number_of_glancing_angles): + if index2 == number_of_glancing_angles - 1 : + pass + else : + angle_interval = RC_data_org[index2+1,0] - RC_data_org[index2,0] integral += RC_data_org[index2,beam_index+1] * g(RC_data_org[index,0] - RC_data_org[index2,0]) * angle_interval if verbose_mode: print("beam_index, index, index2, g(RC_data_org[index,0] - RC_data_org[index2,0]) =",beam_index, index, index2, g(RC_data_org[index,0] - RC_data_org[index2,0])) From 8c4a4168d891bc6c936896367116191cc7c72fbc Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 4 Oct 2023 17:33:45 +0900 Subject: [PATCH 25/67] normalization == "MAX" is disabled. If the normalization == "MAX" option is used, an exception.InputError will occur. --- .../solver/sim_trhepd_rheed_mb_connect.py | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index 8c527050..f68f6dff 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -395,8 +395,12 @@ def __init__(self, info, d_timer): # solver.post info_post = info_s.get("post", {}) v = info_post.get("normalization", "TOTAL") - if v not in ["TOTAL", "MAX", "MS_NORM", "MS_NORM_SET_WGT"]: - raise exception.InputError("ERROR: normalization must be MS_NORM, TOTAL or MAX") + if v == "MAX": + raise exception.InputError('ERROR: normalization == "MAX" is not available') + if v not in ["TOTAL", "MS_NORM", "MS_NORM_SET_WGT"]: + msg ="ERROR: normalization must be " + msg+="MS_NORM, MS_NORM_SET_WGT or TOTAL" + raise exception.InputError(msg) self.normalization = v v = info_post.get("Rfactor_type", "A") @@ -543,14 +547,10 @@ def __init__(self, info, d_timer): self.reference_normed[-1,:].tolist() ) - else: # self.normalization == "MAX": - self.reference_norm = max(self.reference) - self.reference_normalized = [ - I_exp / self.reference_norm for I_exp in self.reference - ] - for p in self.reference_normalized: - self.all_reference_normalized.append(p) - + else: + msg ="ERROR: normalization must be " + msg+="MS_NORM, MS_NORM_SET_WGT or TOTAL" + raise exception.InputError(msg) # solver.config info_config = info_s.get("config", {}) self.surface_output_file = info_config.get( @@ -898,13 +898,10 @@ def _calc_I_from_file(self): convolution_I_calculated_list_normalized = convolution_I_calculated_list_normalized_array[-1,:].copy() self.calc_rocking_curve = np.copy(self.convolution_I_calculated_list_normalized_not_spotwgt_array) - else: # self.normalization == "MAX" - print('self.normalization == "MAX" mb対応検討中') - I_calculated_norm = max(convolution_I_calculated_list) - convolution_I_calculated_list_normalized = [ - c / I_calculated_norm for c in convolution_I_calculated_list - ] - self.calc_rocking_curve = np.array([copy.deepcopy(convolution_I_calculated_list_normalized)]) + else: + msg ="ERROR: normalization must be " + msg+="MS_NORM, MS_NORM_SET_WGT or TOTAL" + raise exception.InputError(msg) for h in convolution_I_calculated_list_normalized: self.all_convolution_I_calculated_list_normalized.append(h) From 6b95b24ef922e8335d0c21671533106d87739c07 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Thu, 12 Oct 2023 16:32:50 +0900 Subject: [PATCH 26/67] Changes to R-factor calculation and normalization. - Changed the argument of the function "_calc_Rfactor". - Changed the R-factor code for calculations with "Rfactor_type = A" or "Rfactor_type = A2". The calculated values are exactly the same as before the code change. - Change of the code normalization = "MS_NORM". The self.spot_weight is automatically calculated from the calculated intensity and used in the R-factor calculation. - Some variable names in the code were changed. --- .../solver/sim_trhepd_rheed_mb_connect.py | 329 +++++++++--------- 1 file changed, 172 insertions(+), 157 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index f68f6dff..6912aaf1 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -101,7 +101,8 @@ def get_results(self) -> float: return self.output.get_results(self.work_dir) def load_so(self): - self.lib = np.ctypeslib.load_library("surf.so",os.path.dirname(__file__) ) + self.lib = np.ctypeslib.load_library("surf.so", + os.path.dirname(__file__)) self.lib.surf_so.argtypes = ( ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), @@ -368,9 +369,9 @@ class Output(object): calculated_first_line: int calculated_last_line: int - reference: List[float] - reference_norm: float - reference_normalized: List[float] + I_reference: List[float] + I_reference_norm: float + I_reference_normalized: List[float] def __init__(self, info, d_timer): self.mpicomm = mpi.comm() @@ -420,11 +421,22 @@ def __init__(self, info, d_timer): self.remove_work_dir = info_post.get("remove_work_dir", False) + v = info_post.get("spot_weight", []) if self.normalization=="MS_NORM_SET_WGT": - v = info_post.get("spot_weight", None) - if v is None: - raise exception.InputError('ERROR:If normalization="MS_NORM_SET_WGT", the weight must be set in solver.post.') + if v == [] : + msg ='ERROR:If normalization="MS_NORM_SET_WGT", ' + msg+='"spot_weight" option must be set in solver.post.' + raise exception.InputError(msg) self.spot_weight = np.array(v)/sum(v) + else: + if v != []: + if self.mpirank == 0: + msg ='NOTICE: With the specified "normalization", ' + msg+='the "spot_weight" you specify in the toml file is ignored, ' + msg+='since the spot_weight is automatically calculated within the program.' + print(msg) + if self.normalization== "TOTAL": + self.spot_weight = np.array([1]) # solver.param info_param = info_s.get("param", {}) @@ -485,68 +497,55 @@ def __init__(self, info, d_timer): if self.normalization=="MS_NORM_SET_WGT": if len(v) != len(self.spot_weight): raise exception.InputError( - "len('exp_number') and len('spot_weight') do not match." + "ERROR:len('exp_number') and len('spot_weight') do not match." ) + if self.normalization=="TOTAL" and len(v)!=1: + msg ='When normalization=="TOTAL" is specified, ' + msg+='only one beam data can be specified with ' + msg+='"exp_number" option.' + raise exception.InputError(msg) + self.exp_number = v - self.beam_number_experiment = len(self.exp_number) - number_ex = self.exp_number - sum_experiment = 0 - for i in number_ex: - sum_experiment += sum(data_experiment[::,i]) - - self.all_reference_normalized = [] - for index, j in enumerate(number_ex): - self.reference = (data_experiment[::,j]) - - self.reference_norm = 0.0 + #Normalization of reference data + self.beam_number_experiment = len(self.exp_number) + for loop_index in range(self.beam_number_experiment): + exp_index = self.exp_number[loop_index] + I_reference = data_experiment[:,exp_index] if self.normalization == "TOTAL": - self.reference_norm = sum_experiment - self.reference_normalized = [ - I_exp / self.reference_norm for I_exp in self.reference - ] - for p in self.reference_normalized: - self.all_reference_normalized.append(p) - + I_reference_norm = np.sum(I_reference) + I_reference_normalized = I_reference/I_reference_norm + I_reference_norm_l = np.array([I_reference_norm]) + self.I_reference_normalized_l = np.array([I_reference_normalized]) elif self.normalization == "MS_NORM": - if j == number_ex[0]: #first loop - self.reference_norm_1st = np.array([np.sum(self.reference)]) - self.reference_1st_normed = np.array([self.reference/self.reference_norm_1st[-1]]) + I_reference_norm = np.sum(I_reference) + I_reference_normalized = I_reference/I_reference_norm + if loop_index == 0: #first loop + I_reference_norm_l = np.array([I_reference_norm]) + self.I_reference_normalized_l = np.array([I_reference_normalized]) else : # N-th loop - self.reference_norm_1st = np.block([self.reference_norm_1st, np.sum(self.reference)]) - self.reference_1st_normed = np.block([[self.reference_1st_normed],[self.reference/self.reference_norm_1st[-1]]]) - + I_reference_norm_l = np.block( + [I_reference_norm_l, I_reference_norm] + ) + self.I_reference_normalized_l = np.block( + [[self.I_reference_normalized_l], + [I_reference_normalized]] + ) elif self.normalization == "MS_NORM_SET_WGT": - if index == 0: #first loop - self.reference_norm_l = np.array( - [np.sum(self.reference)] - ) - self.reference_normed_not_sptwgt = np.array( - [self.reference/self.reference_norm_l[-1]] - ) - self.reference_normed = self._multiply_spot_weight( - self.reference_normed_not_sptwgt, - self.spot_weight[index]) + I_reference_norm = np.sum(I_reference) + I_reference_normalized = I_reference/I_reference_norm + if loop_index == 0: #first loop + I_reference_norm_l = np.array([I_reference_norm]) + self.I_reference_normalized_l = np.array([I_reference_normalized]) else : # N-th loop - self.reference_norm_l = np.block( - [self.reference_norm_l, - np.sum(self.reference)] - ) - self.reference_normed_not_sptwgt = np.block( - [[self.reference_normed_not_sptwgt], - [self.reference/self.reference_norm_l[-1]]] - ) - self.reference_normed = np.block( - [[self.reference_normed], - [self._multiply_spot_weight( - self.reference_normed_not_sptwgt[-1,:], - self.spot_weight[index]) ] ] - ) - self.all_reference_normalized.extend( - self.reference_normed[-1,:].tolist() - ) - + I_reference_norm_l = np.block( + [I_reference_norm_l, I_reference_norm] + ) + self.I_reference_normalized_l = np.block( + [[self.I_reference_normalized_l], + [I_reference_normalized]] + ) else: msg ="ERROR: normalization must be " msg+="MS_NORM, MS_NORM_SET_WGT or TOTAL" @@ -613,7 +612,11 @@ def __init__(self, info, d_timer): raise exception.InputError( "len('cal_number') and len('spot_weight') do not match." ) - + if self.normalization=="TOTAL" and len(v)!=1: + msg ='When normalization=="TOTAL" is specified, ' + msg+='only one beam data can be specified with ' + msg+='"cal_number" option.' + raise exception.InputError(msg) self.cal_number = v def read_experiment(self, ref_path, first, last, read_to_final_line): @@ -678,18 +681,20 @@ def rmtree_error_handler(function, path, excinfo): return Rfactor def _post(self, fitted_x_list): - I_experiment_norm = self.reference_norm - I_experiment_list = self.reference - + I_experiment_normalized_l = self.I_reference_normalized_l + ( - all_convolution_I_calculated_list_normalized, - I_calculated_norm, - convolution_I_calculated_list, + conv_number_of_g_angle, + conv_I_calculated_norm_l, + conv_I_calculated_normalized_l ) = self._calc_I_from_file() if self.isLogmode : time_sta = time.perf_counter() - - Rfactor = self._calc_Rfactor(all_convolution_I_calculated_list_normalized) + Rfactor = self._calc_Rfactor( + conv_number_of_g_angle, + conv_I_calculated_normalized_l, + I_experiment_normalized_l, + ) if self.isLogmode : time_end = time.perf_counter() self.detail_timer["calculate_R-factor"] += time_end - time_sta @@ -716,10 +721,9 @@ def _post(self, fitted_x_list): file_RC.write("\n") file_RC.write("#R-factor = {}\n".format(Rfactor)) file_RC.write("#cal_number = {}\n".format(self.cal_number)) - if self.normalization == "MS_NORM_SET_WGT" : - file_RC.write("#spot_weight = {}\n".format(self.spot_weight)) - file_RC.write("#NOTICE : The listed intensities are NOT multiplied by spot_weight.") - file_RC.write("\n") + file_RC.write("#spot_weight = {}\n".format(self.spot_weight)) + file_RC.write("#NOTICE : Intensities are NOT multiplied by spot_weight.") + file_RC.write("\n") file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.") file_RC.write("\n") file_RC.write("#sum( I_(spot) ) = 1") @@ -769,6 +773,8 @@ def _calc_I_from_file(self): calculated_nlines = self.calculated_nlines omega = self.omega + cal_number = self.cal_number + assert 0 < calculated_nlines if self.run_scheme == "connect_so": @@ -828,125 +834,134 @@ def _calc_I_from_file(self): omega, verbose_mode, ) - - self.all_convolution_I_calculated_list_normalized = [] + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["convolution"] += time_end - time_sta if self.isLogmode : time_sta = time.perf_counter() - number = self.cal_number - angle_number_convolution = data_convolution.shape[0] - self.glancing_angle = data_convolution[:,0] + angle_number_convolution = data_convolution.shape[0] if self.angle_number_experiment !=angle_number_convolution: raise exception.InputError( "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." ) - - self.beam_number_convolution = data_convolution.shape[1] - sum_convolution = np.sum(data_convolution[:,number]) - - for i in range(len(number)): - convolution_I_calculated_list = data_convolution[:,number[i]] - + self.glancing_angle = data_convolution[:,0] + + beam_number_reference = len(cal_number) + for loop_index in range(beam_number_reference): + cal_index = cal_number[loop_index] + conv_I_calculated = data_convolution[:,cal_index] if self.normalization == "TOTAL": - I_calculated_norm = sum_convolution - convolution_I_calculated_list_normalized = [ - c / I_calculated_norm for c in convolution_I_calculated_list - ] - self.calc_rocking_curve = np.array([copy.deepcopy(convolution_I_calculated_list_normalized)]) - + conv_I_calculated_norm = np.sum(conv_I_calculated) + conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm + conv_I_calculated_norm_l = np.array( + [conv_I_calculated_norm] + ) + conv_I_calculated_normalized_l = np.array( + [conv_I_calculated_normalized] + ) elif self.normalization == "MS_NORM": - if i == 0: - self.reference_2nd_normed = copy.deepcopy(self.reference_1st_normed) - self.all_reference_normalized = [] - I_calculated_norm = sum_convolution - convolution_I_calculated_list_normalized = [ - c / I_calculated_norm for c in convolution_I_calculated_list - ] - I_calc_norm_sum_spot = sum(convolution_I_calculated_list_normalized) - self.reference_2nd_normed[i,:] *= I_calc_norm_sum_spot - self.all_reference_normalized.extend(self.reference_2nd_normed[i,:].tolist()) - + conv_I_calculated_norm = np.sum(conv_I_calculated) + conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm + if loop_index == 0: #first loop + conv_I_calculated_norm_l = np.array( + [conv_I_calculated_norm] + ) + conv_I_calculated_normalized_l = np.array( + [conv_I_calculated_normalized] + ) + else: # N-th loop + conv_I_calculated_norm_l = np.block( + [conv_I_calculated_norm_l, + conv_I_calculated_norm] + ) + conv_I_calculated_normalized_l = np.block( + [[conv_I_calculated_normalized_l], + [conv_I_calculated_normalized]] + ) + if loop_index == beam_number_reference-1: #first loop + #conv_I_c_norm_l_power2 = conv_I_calculated_norm_l**2 + #self.spot_weight = conv_I_c_norm_l_power2 + #self.spot_weight = (conv_I_c_norm_l_power2 + # / sum(conv_I_calculated_norm_l)**2) + # / sum(conv_I_c_norm_l_power2) ) + self.spot_weight = ( conv_I_calculated_norm_l + / sum(conv_I_calculated_norm_l) )**2 elif self.normalization == "MS_NORM_SET_WGT": - if i == 0: #first loop - I_calculated_norm = np.array( - [np.sum(convolution_I_calculated_list)] - ) - self.convolution_I_calculated_list_normalized_not_spotwgt_array = np.array( - [convolution_I_calculated_list/I_calculated_norm[-1]] - ) - convolution_I_calculated_list_normalized_array = self._multiply_spot_weight( - self.convolution_I_calculated_list_normalized_not_spotwgt_array, - self.spot_weight[i]) + conv_I_calculated_norm = np.sum(conv_I_calculated) + conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm + if loop_index == 0: #first loop + conv_I_calculated_norm_l = np.array( + [conv_I_calculated_norm] + ) + conv_I_calculated_normalized_l = np.array( + [conv_I_calculated_normalized] + ) else: # N-th loop - I_calculated_norm = np.block( - [I_calculated_norm, - np.sum(convolution_I_calculated_list)] - ) - self.convolution_I_calculated_list_normalized_not_spotwgt_array = np.block( - [[self.convolution_I_calculated_list_normalized_not_spotwgt_array], - [convolution_I_calculated_list/I_calculated_norm[-1]]] - ) - convolution_I_calculated_list_normalized_array = np.block( - [[convolution_I_calculated_list_normalized_array], - [ self._multiply_spot_weight( - self.convolution_I_calculated_list_normalized_not_spotwgt_array[-1,:], - self.spot_weight[i]) ] ] - ) - convolution_I_calculated_list_normalized = convolution_I_calculated_list_normalized_array[-1,:].copy() - self.calc_rocking_curve = np.copy(self.convolution_I_calculated_list_normalized_not_spotwgt_array) + conv_I_calculated_norm_l = np.block( + [conv_I_calculated_norm_l, + conv_I_calculated_norm] + ) + conv_I_calculated_normalized_l = np.block( + [[conv_I_calculated_normalized_l], + [conv_I_calculated_normalized]] + ) + + self.calc_rocking_curve = np.copy(conv_I_calculated_normalized_l) else: msg ="ERROR: normalization must be " msg+="MS_NORM, MS_NORM_SET_WGT or TOTAL" raise exception.InputError(msg) - - for h in convolution_I_calculated_list_normalized: - self.all_convolution_I_calculated_list_normalized.append(h) - + self.calc_rocking_curve = conv_I_calculated_normalized_l + if self.isLogmode : time_end = time.perf_counter() self.detail_timer["normalize_calc_I"] += time_end - time_sta - return ( - self.all_convolution_I_calculated_list_normalized, - I_calculated_norm, - convolution_I_calculated_list, - ) - + angle_number_convolution, + conv_I_calculated_norm_l, + conv_I_calculated_normalized_l + ) - def _calc_Rfactor(self, calc_result): - I_experiment_list_normalized = self.all_reference_normalized + def _calc_Rfactor(self, n_g_angle, calc_result, exp_result): + spot_weight = self.spot_weight + n_spot = len(spot_weight) if self.Rfactor_type == "A": R = 0.0 - for I_exp, I_calc in zip(I_experiment_list_normalized, calc_result): - R += (I_exp - I_calc) ** 2 + for spot_index in range(n_spot): + R_spot = 0.0 + for angle_index in range(n_g_angle): + R_spot += (exp_result[spot_index, angle_index] + - calc_result[spot_index, angle_index] )**2 + R_spot = spot_weight[spot_index] * R_spot + R += R_spot R = np.sqrt(R) - elif self.Rfactor_type == "A2": R = 0.0 - for I_exp, I_calc in zip(I_experiment_list_normalized, calc_result): - R += (I_exp - I_calc) ** 2 - + for spot_index in range(n_spot): + R_spot = 0.0 + for angle_index in range(n_g_angle): + R_spot += (exp_result[spot_index, angle_index] + - calc_result[spot_index, angle_index] )**2 + R_spot = spot_weight[spot_index] * R_spot + R += R_spot else: # self.Rfactor_type == "B" + all_exp_result = [] + all_calc_result = [] + for spot_index in range(n_spot): + for angle_index in range(n_g_angle): + all_exp_result.append( + exp_result[spot_index, angle_index]) + all_calc_result.append( + calc_result[spot_index, angle_index]) y1 = 0.0 y2 = 0.0 y3 = 0.0 - for I_exp, I_calc in zip(I_experiment_list_normalized, calc_result): + for I_exp, I_calc in zip(all_exp_result, all_calc_result): y1 += (I_exp - I_calc) ** 2 y2 += I_exp ** 2 y3 += I_calc ** 2 R = y1 / (y2 + y3) return R - - def _multiply_spot_weight(self,I_not_multiplied_spotwgt,s_weight): - if (self.Rfactor_type=="A") or (self.Rfactor_type=="A2") : - I_multiplied = np.sqrt(s_weight)*I_not_multiplied_spotwgt - - else: - raise exception.InputError( - 'ERROR: When normalization="MS_NORM_SET_WGT" is set, only Rfactor_type="A" or Rfactor_type="A2" is valid.' - ) - return I_multiplied From 21d9643b5059fb117208590fdf0844156dec3cb0 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Thu, 12 Oct 2023 18:43:04 +0900 Subject: [PATCH 27/67] Changes related to RockingCurve_calculated.txt. - RockingCurve_calculated.txt can now be generated even if 'normalization = "MS_NORM"' is set. - Minor changes related to variable names. --- .../solver/sim_trhepd_rheed_mb_connect.py | 115 +++++++++--------- 1 file changed, 55 insertions(+), 60 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index 6912aaf1..e8fa1a89 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -676,17 +676,17 @@ def rmtree_error_handler(function, path, excinfo): if self.isLogmode : time_end = time.perf_counter() - self.detail_timer["delete_Log-directory"] += time_end - time_sta - + self.detail_timer["delete_Log-directory"] += time_end - time_sta return Rfactor def _post(self, fitted_x_list): I_experiment_normalized_l = self.I_reference_normalized_l ( + glancing_angle, conv_number_of_g_angle, conv_I_calculated_norm_l, - conv_I_calculated_normalized_l + conv_I_calculated_normalized_l, ) = self._calc_I_from_file() if self.isLogmode : time_sta = time.perf_counter() @@ -698,63 +698,60 @@ def _post(self, fitted_x_list): if self.isLogmode : time_end = time.perf_counter() self.detail_timer["calculate_R-factor"] += time_end - time_sta - + + #generate rocking curve dimension = self.dimension string_list = self.string_list - + cal_number = self.cal_number + spot_weight = self.spot_weight if self.generate_rocking_curve : - if self.normalization == "MS_NORM": - print('NOTICE: The output of rocking curve is not implemented when the following settings are made: self.normalization == "MS_NORM".') - else: - if self.isLogmode : time_sta = time.perf_counter() - with open("RockingCurve_calculated.txt", "w") as file_RC: - # Write headers - file_RC.write("#") - for index in range(dimension): - file_RC.write( - "{} = {} ".format(string_list[index], fitted_x_list[index]) - ) - file_RC.write("\n") - file_RC.write(f"#Rfactor_type = {self.Rfactor_type}") - file_RC.write("\n") - file_RC.write(f"#normalization = {self.normalization}") - file_RC.write("\n") - file_RC.write("#R-factor = {}\n".format(Rfactor)) - file_RC.write("#cal_number = {}\n".format(self.cal_number)) - file_RC.write("#spot_weight = {}\n".format(self.spot_weight)) - file_RC.write("#NOTICE : Intensities are NOT multiplied by spot_weight.") - file_RC.write("\n") - file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.") - file_RC.write("\n") - file_RC.write("#sum( I_(spot) ) = 1") - file_RC.write("\n") - file_RC.write("#") - file_RC.write("\n") - - label_column = ["glancing_angle"] - fmt_rc = '%.5f' - for i in range(len(self.cal_number)): - label_column.append(f"cal_number={self.cal_number[i]}") - fmt_rc += " %.15e" - - for i in range(len(label_column)): - file_RC.write(f"# #{i} {label_column[i]}") - file_RC.write("\n") - - angle_for_rc = np.array([self.glancing_angle]) - np.savetxt( - file_RC, - np.block( - [angle_for_rc.T, - self.calc_rocking_curve.T] - ), - fmt=fmt_rc - ) + if self.isLogmode : time_sta = time.perf_counter() + with open("RockingCurve_calculated.txt", "w") as file_RC: + # Write headers + file_RC.write("#") + for index in range(dimension): + file_RC.write( + "{} = {} ".format(string_list[index], fitted_x_list[index]) + ) + file_RC.write("\n") + file_RC.write(f"#Rfactor_type = {self.Rfactor_type}") + file_RC.write("\n") + file_RC.write(f"#normalization = {self.normalization}") + file_RC.write("\n") + file_RC.write("#R-factor = {}\n".format(Rfactor)) + file_RC.write("#cal_number = {}\n".format(cal_number)) + file_RC.write("#spot_weight = {}\n".format(spot_weight)) + file_RC.write("#NOTICE : Intensities are NOT multiplied by spot_weight.") + file_RC.write("\n") + file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.") + file_RC.write("\n") + file_RC.write("#sum( I_(spot) ) = 1") + file_RC.write("\n") + file_RC.write("#") + file_RC.write("\n") + label_column = ["glancing_angle"] + fmt_rc = '%.5f' + for i in range(len(cal_number)): + label_column.append(f"cal_number={self.cal_number[i]}") + fmt_rc += " %.15e" + + for i in range(len(label_column)): + file_RC.write(f"# #{i} {label_column[i]}") + file_RC.write("\n") + g_angle_for_rc = np.array([glancing_angle]) + np.savetxt( + file_RC, + np.block( + [g_angle_for_rc.T, + conv_I_calculated_normalized_l.T] + ), + fmt=fmt_rc + ) + if self.isLogmode : time_end = time.perf_counter() - self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta - + self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta return Rfactor def _g(self, x): @@ -846,7 +843,7 @@ def _calc_I_from_file(self): raise exception.InputError( "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." ) - self.glancing_angle = data_convolution[:,0] + glancing_angle = data_convolution[:,0] beam_number_reference = len(cal_number) for loop_index in range(beam_number_reference): @@ -906,20 +903,18 @@ def _calc_I_from_file(self): conv_I_calculated_normalized_l = np.block( [[conv_I_calculated_normalized_l], [conv_I_calculated_normalized]] - ) - - self.calc_rocking_curve = np.copy(conv_I_calculated_normalized_l) - + ) else: msg ="ERROR: normalization must be " msg+="MS_NORM, MS_NORM_SET_WGT or TOTAL" raise exception.InputError(msg) - self.calc_rocking_curve = conv_I_calculated_normalized_l if self.isLogmode : time_end = time.perf_counter() self.detail_timer["normalize_calc_I"] += time_end - time_sta + return ( + glancing_angle, angle_number_convolution, conv_I_calculated_norm_l, conv_I_calculated_normalized_l From 8f3a9e0593358ce60d8be23425b3e2f2376d5ccc Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Thu, 12 Oct 2023 21:02:26 +0900 Subject: [PATCH 28/67] Renewal of normalization options - The option "normalization" in [solver,post] can only specify "TOTAL" or "MULTI_SPOT" . - The option "weight_type" of [SOLVER,POST] is newly added. calc" and "manual" can be specified. - With the following settings, the same calculation as the previous code can be performed. -> normalization="MS_NORM" -> normalization="MULTI_SPOT", weight_type="calc" normalization="MS_NORM_SET_WGT" -> normalization="MULTI_SPOT", weight_type="manual" - If normalization="MULTI_SPOT", the value of option "weight_type" is printed in RockingCurve_calculated.txt. --- .../solver/sim_trhepd_rheed_mb_connect.py | 86 ++++++++++++------- 1 file changed, 56 insertions(+), 30 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py index e8fa1a89..a9191227 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py @@ -396,47 +396,70 @@ def __init__(self, info, d_timer): # solver.post info_post = info_s.get("post", {}) v = info_post.get("normalization", "TOTAL") + available_normalization = ["TOTAL", "MULTI_SPOT"] if v == "MAX": raise exception.InputError('ERROR: normalization == "MAX" is not available') - if v not in ["TOTAL", "MS_NORM", "MS_NORM_SET_WGT"]: + if v not in available_normalization: msg ="ERROR: normalization must be " - msg+="MS_NORM, MS_NORM_SET_WGT or TOTAL" + msg+="MULTI_SPOT or TOTAL" raise exception.InputError(msg) self.normalization = v - v = info_post.get("Rfactor_type", "A") - if v not in ["A", "B", "A2"]: - raise exception.InputError("ERROR: Rfactor_type must be A, A2 or B") - if self.normalization=="MS_NORM_SET_WGT": - if (v!="A") and (v!="A2") : - raise exception.InputError( - 'ERROR: When normalization="MS_NORM_SET_WGT" is set, only Rfactor_type="A" or Rfactor_type="A2" is valid.' - ) - self.Rfactor_type = v + v = info_post.get("weight_type", None) + available_weight_type = ["calc", "manual"] + if self.normalization == "MULTI_SPOT": + if v is None : + msg ='ERROR: If normalization = "MULTI_SPOT", ' + msg+='"weight_type" must be set in [solver.post].' + raise exception.InputError(msg) + elif v not in available_weight_type: + msg ="ERROR: weight_type must be " + msg+="calc or manual" + raise exception.InputError(msg) + else: + if v is not None : + if self.mpirank == 0: + msg ='NOTICE: If normalization = "MULTI_SPOT" is not set, ' + msg+='"weight_type" is NOT considered in the calculation.' + print(msg) + self.weight_type = None + self.weight_type = v - v = info_post.get("omega", 0.5) - if v <= 0.0: - raise exception.InputError("ERROR: omega should be positive") - self.omega = v - - self.remove_work_dir = info_post.get("remove_work_dir", False) - v = info_post.get("spot_weight", []) - if self.normalization=="MS_NORM_SET_WGT": + if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": if v == [] : - msg ='ERROR:If normalization="MS_NORM_SET_WGT", ' - msg+='"spot_weight" option must be set in solver.post.' + msg ='ERROR: With normalization="MULTI_SPOT" and ' + msg+='weight_type=="manual", the "spot_weight" option ' + msg+='must be set in [solver.post].' raise exception.InputError(msg) self.spot_weight = np.array(v)/sum(v) else: if v != []: if self.mpirank == 0: - msg ='NOTICE: With the specified "normalization", ' + msg ='NOTICE: With the specified "normalization" option, ' msg+='the "spot_weight" you specify in the toml file is ignored, ' msg+='since the spot_weight is automatically calculated within the program.' print(msg) if self.normalization== "TOTAL": self.spot_weight = np.array([1]) + + v = info_post.get("Rfactor_type", "A") + if v not in ["A", "B", "A2"]: + raise exception.InputError("ERROR: Rfactor_type must be A, A2 or B") + if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + if (v!="A") and (v!="A2") : + msg ='With normalization="MULTI_SPOT" and weight_type=="manual", ' + msg+='only Rfactor_type="A" or Rfactor_type="A2" is valid.' + raise exception.InputError(msg) + self.Rfactor_type = v + + v = info_post.get("omega", 0.5) + if v <= 0.0: + raise exception.InputError("ERROR: omega should be positive") + self.omega = v + + self.remove_work_dir = info_post.get("remove_work_dir", False) + # solver.param info_param = info_s.get("param", {}) @@ -494,7 +517,7 @@ def __init__(self, info, d_timer): "ERROR: The 'exp_number' setting is wrong." ) - if self.normalization=="MS_NORM_SET_WGT": + if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": if len(v) != len(self.spot_weight): raise exception.InputError( "ERROR:len('exp_number') and len('spot_weight') do not match." @@ -518,7 +541,7 @@ def __init__(self, info, d_timer): I_reference_normalized = I_reference/I_reference_norm I_reference_norm_l = np.array([I_reference_norm]) self.I_reference_normalized_l = np.array([I_reference_normalized]) - elif self.normalization == "MS_NORM": + elif self.normalization=="MULTI_SPOT" and self.weight_type=="calc": I_reference_norm = np.sum(I_reference) I_reference_normalized = I_reference/I_reference_norm if loop_index == 0: #first loop @@ -532,7 +555,7 @@ def __init__(self, info, d_timer): [[self.I_reference_normalized_l], [I_reference_normalized]] ) - elif self.normalization == "MS_NORM_SET_WGT": + elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": I_reference_norm = np.sum(I_reference) I_reference_normalized = I_reference/I_reference_norm if loop_index == 0: #first loop @@ -548,7 +571,7 @@ def __init__(self, info, d_timer): ) else: msg ="ERROR: normalization must be " - msg+="MS_NORM, MS_NORM_SET_WGT or TOTAL" + msg+="MULTI_SPOT or TOTAL" raise exception.InputError(msg) # solver.config info_config = info_s.get("config", {}) @@ -607,7 +630,7 @@ def __init__(self, info, d_timer): "ERROR: 'cal_number' must be a list type." ) - if self.normalization=="MS_NORM_SET_WGT": + if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": if len(self.spot_weight) != len(v): raise exception.InputError( "len('cal_number') and len('spot_weight') do not match." @@ -704,6 +727,7 @@ def _post(self, fitted_x_list): string_list = self.string_list cal_number = self.cal_number spot_weight = self.spot_weight + weight_type = self.weight_type if self.generate_rocking_curve : if self.isLogmode : time_sta = time.perf_counter() with open("RockingCurve_calculated.txt", "w") as file_RC: @@ -718,6 +742,8 @@ def _post(self, fitted_x_list): file_RC.write("\n") file_RC.write(f"#normalization = {self.normalization}") file_RC.write("\n") + if weight_type is not None: + file_RC.write(f"#weight_type = {weight_type}\n") file_RC.write("#R-factor = {}\n".format(Rfactor)) file_RC.write("#cal_number = {}\n".format(cal_number)) file_RC.write("#spot_weight = {}\n".format(spot_weight)) @@ -858,7 +884,7 @@ def _calc_I_from_file(self): conv_I_calculated_normalized_l = np.array( [conv_I_calculated_normalized] ) - elif self.normalization == "MS_NORM": + elif self.normalization=="MULTI_SPOT" and self.weight_type=="calc": conv_I_calculated_norm = np.sum(conv_I_calculated) conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm if loop_index == 0: #first loop @@ -885,7 +911,7 @@ def _calc_I_from_file(self): # / sum(conv_I_c_norm_l_power2) ) self.spot_weight = ( conv_I_calculated_norm_l / sum(conv_I_calculated_norm_l) )**2 - elif self.normalization == "MS_NORM_SET_WGT": + elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": conv_I_calculated_norm = np.sum(conv_I_calculated) conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm if loop_index == 0: #first loop @@ -906,7 +932,7 @@ def _calc_I_from_file(self): ) else: msg ="ERROR: normalization must be " - msg+="MS_NORM, MS_NORM_SET_WGT or TOTAL" + msg+="MULTI_SPOT or TOTAL" raise exception.InputError(msg) if self.isLogmode : From d368b932c5694b1850af148c967a6a28b9b31559 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 14 Oct 2023 15:47:45 +0900 Subject: [PATCH 29/67] change solver name "sim-trhepd-rheed-mb_connect" -> "sim-trhepd-rheed" --- src/py2dmat/_main.py | 2 - src/py2dmat/solver/sim_trhepd_rheed.py | 1052 ++++++++++++++++++------ 2 files changed, 783 insertions(+), 271 deletions(-) diff --git a/src/py2dmat/_main.py b/src/py2dmat/_main.py index 60bc35e8..951aa390 100644 --- a/src/py2dmat/_main.py +++ b/src/py2dmat/_main.py @@ -74,8 +74,6 @@ def main(): from .solver.leed import Solver elif solvername == "analytical": from .solver.analytical import Solver - elif solvername == "sim-trhepd-rheed-mb_connect": - from .solver.sim_trhepd_rheed_mb_connect import Solver else: print(f"ERROR: Unknown solver ({solvername})") exit(1) diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index 35cc92b1..a9191227 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -1,71 +1,153 @@ -# 2DMAT -- Data-analysis software of quantum beam diffraction experiments for 2D material structure -# Copyright (C) 2020- The University of Tokyo -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see http://www.gnu.org/licenses/. - from typing import List import itertools import os import os.path import shutil -import subprocess from pathlib import Path +import subprocess +import time +from . import lib_make_convolution import numpy as np import py2dmat -from py2dmat import exception +from py2dmat import exception, mpi + +import ctypes + +from typing import TYPE_CHECKING +import copy class Solver(py2dmat.solver.SolverBase): path_to_solver: Path def __init__(self, info: py2dmat.Info): super().__init__(info) + self.mpicomm = mpi.comm() + self.mpisize = mpi.size() + self.mpirank = mpi.rank() + + self._name = "sim_trhepd_rheed_mb_connect" + + self.run_scheme = info.solver.get("run_scheme",None) + scheme_list = ["subprocess","connect_so"] + scheme_judge = [i == self.run_scheme for i in scheme_list] + + if not any(scheme_judge): + raise exception.InputError( + "ERROR : Input scheme is incorrect." + ) - self._name = "sim_trhepd_rheed" - p2solver = info.solver["config"].get("surface_exec_file", "surf.exe") - if os.path.dirname(p2solver) != "": - # ignore ENV[PATH] - self.path_to_solver = self.root_dir / Path(p2solver).expanduser() + if self.run_scheme == "connect_so": + self.load_so() + + elif self.run_scheme == "subprocess": + #path to surf.exe + p2solver = info.solver["config"].get("surface_exec_file", "surf.exe") + if os.path.dirname(p2solver) != "": + # ignore ENV[PATH] + self.path_to_solver = self.root_dir / Path(p2solver).expanduser() + else: + for P in itertools.chain([self.root_dir], os.environ["PATH"].split(":")): + self.path_to_solver = Path(P) / p2solver + if os.access(self.path_to_solver, mode=os.X_OK): + break + if not os.access(self.path_to_solver, mode=os.X_OK): + raise exception.InputError(f"ERROR: solver ({p2solver}) is not found") + + self.isLogmode = False + self.set_detail_timer() + + self.input = Solver.Input(info,self.detail_timer) + self.output = Solver.Output(info,self.detail_timer) + + def set_detail_timer(self): + # TODO: Operate log_mode with toml file. Generate txt of detail_timer. + if self.isLogmode: + self.detail_timer = {} + self.detail_timer["prepare_Log-directory"] = 0 + self.detail_timer["make_surf_input"] = 0 + self.detail_timer["launch_STR"] = 0 + self.detail_timer["load_STR_result"] = 0 + self.detail_timer["convolution"] = 0 + self.detail_timer["normalize_calc_I"] = 0 + self.detail_timer["calculate_R-factor"] = 0 + self.detail_timer["make_RockingCurve.txt"] = 0 + self.detail_timer["delete_Log-directory"] = 0 else: - for P in itertools.chain([self.root_dir], os.environ["PATH"].split(":")): - self.path_to_solver = Path(P) / p2solver - if os.access(self.path_to_solver, mode=os.X_OK): - break - if not os.access(self.path_to_solver, mode=os.X_OK): - raise exception.InputError(f"ERROR: solver ({p2solver}) is not found") - info_config = info.solver.get("config", {}) - - self.input = Solver.Input(info) - self.output = Solver.Output(info) - self.result = None + self.detail_timer = None + + def default_run_scheme(self): + """ + Return + ------- + str + run_scheme. + """ + return self.run_scheme + + def command(self) -> List[str]: + """Command to invoke solver""" + return [str(self.path_to_solver)] def prepare(self, message: py2dmat.Message) -> None: fitted_x_list, subdir = self.input.prepare(message) self.work_dir = self.proc_dir / Path(subdir) - self.output.prepare(fitted_x_list) - self.result = None - def run(self, nprocs: int = 1, nthreads: int = 1) -> None: - self._run_by_subprocess([str(self.path_to_solver)]) + self.output.prepare(fitted_x_list) def get_results(self) -> float: - if self.result is None: - self.result = self.output.get_results(self.work_dir) - return self.result - + return self.output.get_results(self.work_dir) + + def load_so(self): + self.lib = np.ctypeslib.load_library("surf.so", + os.path.dirname(__file__)) + self.lib.surf_so.argtypes = ( + ctypes.POINTER(ctypes.c_int), + ctypes.POINTER(ctypes.c_int), + np.ctypeslib.ndpointer(), + ctypes.POINTER(ctypes.c_int), + ctypes.POINTER(ctypes.c_int), + np.ctypeslib.ndpointer(), + np.ctypeslib.ndpointer() + ) + self.lib.surf_so.restype = ctypes.c_void_p + + def launch_so(self): + + n_template_file = len(self.input.template_file) + m_template_file = self.input.surf_tempalte_width_for_fortran + n_bulk_file = len(self.input.bulk_file) + m_bulk_file = self.input.bulk_out_width_for_fortran + + # NOTE: The "20480" is related to the following directive in surf_so.f90. + # character(c_char), intent(inout) :: surf_out(20480) + emp_str = ' '*20480 + self.output.surf_output = np.array([emp_str.encode()]) + self.lib.surf_so( + ctypes.byref(ctypes.c_int(n_template_file)), + ctypes.byref(ctypes.c_int(m_template_file)), + self.input.template_file, + ctypes.byref(ctypes.c_int(n_bulk_file)), + ctypes.byref(ctypes.c_int(m_bulk_file)), + self.input.bulk_file, + self.output.surf_output + ) + self.output.surf_output = self.output.surf_output[0].decode().splitlines() + + def run(self, nprocs: int = 1, nthreads: int = 1) -> None: + if self.isLogmode : time_sta = time.perf_counter() + + if self.run_scheme == "connect_so": + self.launch_so() + elif self.run_scheme == "subprocess": + self._run_by_subprocess([str(self.path_to_solver)]) + + if self.isLogmode: + time_end = time.perf_counter() + self.detail_timer["launch_STR"] += time_end - time_sta + class Input(object): root_dir: Path output_dir: Path @@ -75,7 +157,17 @@ class Input(object): surface_input_file: Path surface_template_file: Path - def __init__(self, info): + def __init__(self, info, d_timer): + self.mpicomm = mpi.comm() + self.mpisize = mpi.size() + self.mpirank = mpi.rank() + + if d_timer is None: + self.isLogmode = False + else: + self.isLogmode = True + self.detail_timer = d_timer + self.root_dir = info.base["root_dir"] self.output_dir = info.base["output_dir"] @@ -85,7 +177,16 @@ def __init__(self, info): self.dimension = info.base["dimension"] info_s = info.solver - + self.run_scheme = info_s["run_scheme"] + self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) + + # NOTE: + # surf_tempalte_width_for_fortran: Number of strings per line of template.txt data for surf.so. + # bulk_out_width_for_fortran: Number of strings per line of bulkP.txt data for surf.so. + if self.run_scheme=="connect_so": + self.surf_tempalte_width_for_fortran = 128 + self.bulk_out_width_for_fortran = 1024 + info_param = info_s.get("param", {}) v = info_param.setdefault("string_list", ["value_01", "value_02"]) if len(v) != self.dimension: @@ -106,22 +207,62 @@ def __init__(self, info): raise exception.InputError( f"ERROR: surface_template_file ({self.surface_template_file}) does not exist" ) + + if self.mpirank == 0: + self._check_template() + temp_origin = self.load_surface_template_file(filename) + else: + temp_origin = None + self.template_file_origin = self.mpicomm.bcast(temp_origin,root=0) + + if self.run_scheme == "connect_so": + filename = info_config.get("bulk_output_file", "bulkP.txt") + filename = Path(filename).expanduser().resolve() + self.bulk_output_file = self.root_dir / filename + if not self.bulk_output_file.exists(): + raise exception.InputError( + f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" + ) + + if self.mpirank == 0: + bulk_f = self.load_bulk_output_file(filename) + else: + bulk_f = None + self.bulk_file = self.mpicomm.bcast(bulk_f,root=0) - self._check_template() + else: + filename = info_config.get("bulk_output_file", "bulkP.b") + filename = Path(filename).expanduser().resolve() + self.bulk_output_file = self.root_dir / filename + if not self.bulk_output_file.exists(): + raise exception.InputError( + f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" + ) - filename = info_config.get("bulk_output_file", "bulkP.b") - filename = Path(filename).expanduser().resolve() - self.bulk_output_file = self.root_dir / filename - if not self.bulk_output_file.exists(): - raise exception.InputError( - f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" - ) + def load_surface_template_file(self, filename): + template_file = [] + with open(self.surface_template_file) as f: + for line in f: + template_file.append(line) + return template_file + + def load_bulk_output_file(self, filename) : + bulk_file = [] + with open(self.bulk_output_file) as f: + for line in f: + line = line.replace("\t", " ").replace("\n", " ") + line = line.encode().ljust(self.bulk_out_width_for_fortran) + bulk_file.append(line) + bulk_f = np.array(bulk_file) + return bulk_f def prepare(self, message: py2dmat.Message): + if self.isLogmode : time_sta = time.perf_counter() + x_list = message.x step = message.step iset = message.set - + dimension = self.dimension string_list = self.string_list bulk_output_file = self.bulk_output_file @@ -132,25 +273,74 @@ def prepare(self, message: py2dmat.Message): fitted_value += format(x_list[index], ".8f") fitted_value = fitted_value[: len(string_list[index])] fitted_x_list.append(fitted_value) - for index in range(dimension): - print(string_list[index], "=", fitted_x_list[index]) - folder_name = self._pre_bulk(step, bulk_output_file, iset) + + if self.isLogmode : + time_end = time.perf_counter() + self.detail_timer["make_surf_input"] += time_end - time_sta + + if self.isLogmode : time_sta = time.perf_counter() + + if self.generate_rocking_curve: + folder_name = self._pre_bulk(step, bulk_output_file, iset) + else: + if self.run_scheme == "connect_so": + folder_name = "." + + elif self.run_scheme == "subprocess": + #make workdir and copy bulk output file + folder_name = self._pre_bulk(step, bulk_output_file, iset) + + if self.isLogmode : + time_end = time.perf_counter() + self.detail_timer["prepare_Log-directory"] += time_end - time_sta + + if self.isLogmode : time_sta = time.perf_counter() + self._replace(fitted_x_list, folder_name) + + if self.isLogmode : + time_end = time.perf_counter() + self.detail_timer["make_surf_input"] += time_end - time_sta + return fitted_x_list, folder_name + def _pre_bulk(self, Log_number, bulk_output_file, iset): + folder_name = "Log{:08d}_{:08d}".format(Log_number, iset) + os.makedirs(folder_name, exist_ok=True) + if self.run_scheme == "connect_so": + pass + else: #self.run_scheme == "subprocess": + shutil.copy( + bulk_output_file, os.path.join(folder_name, bulk_output_file.name) + ) + return folder_name + def _replace(self, fitted_x_list, folder_name): - with open(self.surface_template_file, "r") as file_input, open( - os.path.join(folder_name, self.surface_input_file), "w" - ) as file_output: - for line in file_input: - for index in range(self.dimension): - if line.find(self.string_list[index]) != -1: - line = line.replace( + template_file = [] + if self.run_scheme == "subprocess": + file_output = open(os.path.join(folder_name, self.surface_input_file), "w") + for line in self.template_file_origin: + for index in range(self.dimension): + if line.find(self.string_list[index]) != -1: + line = line.replace( self.string_list[index], - fitted_x_list[index], + fitted_x_list[index] ) + + if self.run_scheme == "connect_so": + line = line.replace("\t", " ").replace("\n", " ") + line = line.encode().ljust(self.surf_tempalte_width_for_fortran) + template_file.append(line) + + elif self.run_scheme == "subprocess": file_output.write(line) + + if self.run_scheme == "connect_so": + self.template_file = np.array(template_file) + elif self.run_scheme == "subprocess": + file_output.close() + def _check_template(self) -> None: found = [False] * self.dimension with open(self.surface_template_file, "r") as file_input: @@ -166,14 +356,6 @@ def _check_template(self) -> None: msg += label raise exception.InputError(msg) - def _pre_bulk(self, Log_number, bulk_output_file, iset): - folder_name = "Log{:08d}_{:08d}".format(Log_number, iset) - os.makedirs(folder_name, exist_ok=True) - shutil.copy( - bulk_output_file, os.path.join(folder_name, bulk_output_file.name) - ) - return folder_name - class Output(object): """ Output manager. @@ -186,70 +368,99 @@ class Output(object): Rfactor_type: str calculated_first_line: int calculated_last_line: int - row_number: int - degree_max: float - degree_list: List[float] - reference: List[float] - reference_norm: float - reference_normalized: List[float] - degree_list: List[float] + I_reference: List[float] + I_reference_norm: float + I_reference_normalized: List[float] + + def __init__(self, info, d_timer): + self.mpicomm = mpi.comm() + self.mpisize = mpi.size() + self.mpirank = mpi.rank() + + if d_timer is None: + self.isLogmode = False + else: + self.isLogmode = True + self.detail_timer = d_timer - def __init__(self, info): if "dimension" in info.solver: self.dimension = info.solver["dimension"] else: self.dimension = info.base["dimension"] info_s = info.solver - - # solver.config - info_config = info_s.get("config", {}) - self.surface_output_file = info_config.get( - "surface_output_file", "surf-bulkP.s" - ) - - v = info_config.get("calculated_first_line", 5) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: calculated_first_line should be non-negative integer" - ) - self.calculated_first_line = v - - v = info_config.get("calculated_last_line", 60) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: calculated_last_line should be non-negative integer" - ) - self.calculated_last_line = v - - v = info_config.get("row_number", 8) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: row_number should be non-negative integer" - ) - self.row_number = v + self.run_scheme = info_s["run_scheme"] + self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) # solver.post info_post = info_s.get("post", {}) - v = info_post.get("normalization", "TOTAL") - if v not in ["TOTAL", "MAX"]: - raise exception.InputError("ERROR: normalization must be TOTAL or MAX") + available_normalization = ["TOTAL", "MULTI_SPOT"] + if v == "MAX": + raise exception.InputError('ERROR: normalization == "MAX" is not available') + if v not in available_normalization: + msg ="ERROR: normalization must be " + msg+="MULTI_SPOT or TOTAL" + raise exception.InputError(msg) self.normalization = v + v = info_post.get("weight_type", None) + available_weight_type = ["calc", "manual"] + if self.normalization == "MULTI_SPOT": + if v is None : + msg ='ERROR: If normalization = "MULTI_SPOT", ' + msg+='"weight_type" must be set in [solver.post].' + raise exception.InputError(msg) + elif v not in available_weight_type: + msg ="ERROR: weight_type must be " + msg+="calc or manual" + raise exception.InputError(msg) + else: + if v is not None : + if self.mpirank == 0: + msg ='NOTICE: If normalization = "MULTI_SPOT" is not set, ' + msg+='"weight_type" is NOT considered in the calculation.' + print(msg) + self.weight_type = None + self.weight_type = v + + v = info_post.get("spot_weight", []) + if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + if v == [] : + msg ='ERROR: With normalization="MULTI_SPOT" and ' + msg+='weight_type=="manual", the "spot_weight" option ' + msg+='must be set in [solver.post].' + raise exception.InputError(msg) + self.spot_weight = np.array(v)/sum(v) + else: + if v != []: + if self.mpirank == 0: + msg ='NOTICE: With the specified "normalization" option, ' + msg+='the "spot_weight" you specify in the toml file is ignored, ' + msg+='since the spot_weight is automatically calculated within the program.' + print(msg) + if self.normalization== "TOTAL": + self.spot_weight = np.array([1]) + v = info_post.get("Rfactor_type", "A") - if v not in ["A", "B"]: - raise exception.InputError("ERROR: Rfactor_type must be A or B") + if v not in ["A", "B", "A2"]: + raise exception.InputError("ERROR: Rfactor_type must be A, A2 or B") + if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + if (v!="A") and (v!="A2") : + msg ='With normalization="MULTI_SPOT" and weight_type=="manual", ' + msg+='only Rfactor_type="A" or Rfactor_type="A2" is valid.' + raise exception.InputError(msg) self.Rfactor_type = v v = info_post.get("omega", 0.5) if v <= 0.0: raise exception.InputError("ERROR: omega should be positive") self.omega = v - + self.remove_work_dir = info_post.get("remove_work_dir", False) - + + # solver.param info_param = info_s.get("param", {}) v = info_param.setdefault("string_list", ["value_01", "value_02"]) @@ -259,49 +470,208 @@ def __init__(self, info): ) self.string_list = v - v = info_param.get("degree_max", 6.0) - self.degree_max = v - # solver.reference info_ref = info_s.get("reference", {}) - reference_path = info_ref.get("path", "experiment.txt") - - v = info_ref.setdefault("first", 1) + v = info_ref.setdefault("reference_first_line", 1) if not (isinstance(v, int) and v >= 0): raise exception.InputError( "ERROR: reference_first_line should be non-negative integer" ) firstline = v - v = info_ref.setdefault("last", 56) - if not (isinstance(v, int) and v >= firstline): + # None is dummy value + # If "reference_last_line" is not specified in the toml file, + # the last line of the reference file is used for the R-factor calculation. + v = info_ref.setdefault("reference_last_line", None) + if v is None: + reference_are_read_to_final_line = True + else: + reference_are_read_to_final_line = False + if not (isinstance(v, int) and v >= firstline): + raise exception.InputError( + "ERROR: reference_last_line < reference_first_line" + ) + lastline = v + + reference_path = info_ref.get("path", "experiment.txt") + data_experiment = self.read_experiment( + reference_path, firstline, lastline, + reference_are_read_to_final_line ) + self.angle_number_experiment = data_experiment.shape[0] + self.beam_number_exp_raw = data_experiment.shape[1] + + v = info_ref.get("exp_number", None) + + if v == None : raise exception.InputError( - "ERROR: reference_last_line < reference_first_line" + "ERROR: You have to set the 'exp_number'." ) - lastline = v - # Read experiment-data - nline = lastline - firstline + 1 - self.degree_list = [] - self.reference = [] - with open(reference_path, "r") as fp: - for _ in range(firstline - 1): - fp.readline() - for _ in range(nline): - line = fp.readline() - words = line.split() - self.degree_list.append(float(words[0])) - self.reference.append(float(words[1])) - - self.reference_norm = 0.0 - if self.normalization == "TOTAL": - self.reference_norm = sum(self.reference) - else: # self.normalization == "MAX": - self.reference_norm = max(self.reference) - - self.reference_normalized = [ - I_exp / self.reference_norm for I_exp in self.reference - ] + if not isinstance(v, list): + raise exception.InputError( + "ERROR: 'exp_number' must be a list type." + ) + + if max(v) > self.beam_number_exp_raw : + raise exception.InputError( + "ERROR: The 'exp_number' setting is wrong." + ) + + if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + if len(v) != len(self.spot_weight): + raise exception.InputError( + "ERROR:len('exp_number') and len('spot_weight') do not match." + ) + + if self.normalization=="TOTAL" and len(v)!=1: + msg ='When normalization=="TOTAL" is specified, ' + msg+='only one beam data can be specified with ' + msg+='"exp_number" option.' + raise exception.InputError(msg) + + self.exp_number = v + + #Normalization of reference data + self.beam_number_experiment = len(self.exp_number) + for loop_index in range(self.beam_number_experiment): + exp_index = self.exp_number[loop_index] + I_reference = data_experiment[:,exp_index] + if self.normalization == "TOTAL": + I_reference_norm = np.sum(I_reference) + I_reference_normalized = I_reference/I_reference_norm + I_reference_norm_l = np.array([I_reference_norm]) + self.I_reference_normalized_l = np.array([I_reference_normalized]) + elif self.normalization=="MULTI_SPOT" and self.weight_type=="calc": + I_reference_norm = np.sum(I_reference) + I_reference_normalized = I_reference/I_reference_norm + if loop_index == 0: #first loop + I_reference_norm_l = np.array([I_reference_norm]) + self.I_reference_normalized_l = np.array([I_reference_normalized]) + else : # N-th loop + I_reference_norm_l = np.block( + [I_reference_norm_l, I_reference_norm] + ) + self.I_reference_normalized_l = np.block( + [[self.I_reference_normalized_l], + [I_reference_normalized]] + ) + elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + I_reference_norm = np.sum(I_reference) + I_reference_normalized = I_reference/I_reference_norm + if loop_index == 0: #first loop + I_reference_norm_l = np.array([I_reference_norm]) + self.I_reference_normalized_l = np.array([I_reference_normalized]) + else : # N-th loop + I_reference_norm_l = np.block( + [I_reference_norm_l, I_reference_norm] + ) + self.I_reference_normalized_l = np.block( + [[self.I_reference_normalized_l], + [I_reference_normalized]] + ) + else: + msg ="ERROR: normalization must be " + msg+="MULTI_SPOT or TOTAL" + raise exception.InputError(msg) + # solver.config + info_config = info_s.get("config", {}) + self.surface_output_file = info_config.get( + "surface_output_file", "surf-bulkP.s" + ) + + v = info_config.get("calculated_first_line", 5) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: calculated_first_line should be non-negative integer" + ) + self.calculated_first_line = v + + v = info_config.get( + "calculated_last_line", + self.calculated_first_line + self.angle_number_experiment-1 + ) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: calculated_last_line should be non-negative integer" + ) + self.calculated_last_line = v + + # Number of lines in the computation file + # used for R-factor calculations. + self.calculated_nlines = (self.calculated_last_line - + self.calculated_first_line + 1 ) + + if self.angle_number_experiment != self.calculated_nlines : + raise exception.InputError( + "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." + ) + + # Variable indicating whether the warning + # "self.calculated_nlines does not match + # the number of glancing angles in the calculated file" + # is displayed. + self.isWarning_calcnline = False + + v = info_config.get("calculated_info_line", 2) + if not (isinstance(v, int) and v >= 0): + raise exception.InputError( + "ERROR: calculated_info_line should be non-negative integer" + ) + self.calculated_info_line = v + + v = info_config.get("cal_number",None) + if v == None : + raise exception.InputError( + "ERROR: You have to set the 'cal_number'." + ) + + if not isinstance(v, list): + raise exception.InputError( + "ERROR: 'cal_number' must be a list type." + ) + + if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + if len(self.spot_weight) != len(v): + raise exception.InputError( + "len('cal_number') and len('spot_weight') do not match." + ) + if self.normalization=="TOTAL" and len(v)!=1: + msg ='When normalization=="TOTAL" is specified, ' + msg+='only one beam data can be specified with ' + msg+='"cal_number" option.' + raise exception.InputError(msg) + self.cal_number = v + + def read_experiment(self, ref_path, first, last, read_to_final_line): + # Read experiment data + if self.mpirank == 0: + file_input = open(ref_path, "r") + Elines = file_input.readlines() + + firstline = first + if read_to_final_line : + lastline = len(Elines) + else: + lastline = last + + n_exp_row = lastline-firstline+1 + + # get value from data + for row_index in range(n_exp_row) : + line_index = firstline + row_index - 1 + line = Elines[line_index] + data = line.split() + # first loop + if row_index == 0: + n_exp_column = len(data) + data_e = np.zeros((n_exp_row, n_exp_column)) #init value + + for column_index in range(n_exp_column): + data_e[row_index, column_index] = float(data[column_index]) + else: + data_e = None + data_exp = self.mpicomm.bcast(data_e,root=0) + return data_exp def prepare(self, fitted_x_list): self.fitted_x_list = fitted_x_list @@ -309,84 +679,105 @@ def prepare(self, fitted_x_list): def get_results(self, work_dir) -> float: """ Get Rfactor obtained by the solver program. - Returns ------- - """ - - cwd = os.getcwd() + """ # Calculate Rfactor and Output numerical results + cwd = os.getcwd() os.chdir(work_dir) Rfactor = self._post(self.fitted_x_list) os.chdir(cwd) - if self.remove_work_dir: - def rmtree_error_handler(function, path, excinfo): - print(f"WARNING: Failed to remove a working directory, {path}") - - shutil.rmtree(work_dir, onerror=rmtree_error_handler) + #delete Log-directory + if self.isLogmode : time_sta = time.perf_counter() + + if self.run_scheme == "subprocess": + if self.remove_work_dir: + def rmtree_error_handler(function, path, excinfo): + print(f"WARNING: Failed to remove a working directory, {path}") + shutil.rmtree(work_dir, onerror=rmtree_error_handler) + + if self.isLogmode : + time_end = time.perf_counter() + self.detail_timer["delete_Log-directory"] += time_end - time_sta return Rfactor def _post(self, fitted_x_list): - degree_list = self.degree_list - I_experiment_norm = self.reference_norm - I_experiment_list = self.reference - + I_experiment_normalized_l = self.I_reference_normalized_l + ( - convolution_I_calculated_list_normalized, - I_calculated_norm, - I_calculated_list, - convolution_I_calculated_list, + glancing_angle, + conv_number_of_g_angle, + conv_I_calculated_norm_l, + conv_I_calculated_normalized_l, ) = self._calc_I_from_file() - - Rfactor = self._calc_Rfactor(convolution_I_calculated_list_normalized) - - print("R-factor =", Rfactor) - + + if self.isLogmode : time_sta = time.perf_counter() + Rfactor = self._calc_Rfactor( + conv_number_of_g_angle, + conv_I_calculated_normalized_l, + I_experiment_normalized_l, + ) + if self.isLogmode : + time_end = time.perf_counter() + self.detail_timer["calculate_R-factor"] += time_end - time_sta + + #generate rocking curve dimension = self.dimension string_list = self.string_list - - with open("RockingCurve.txt", "w") as file_RC: - I_experiment_list_normalized = self.reference_normalized - # Write headers - file_RC.write("#") - for index in range(dimension): - file_RC.write( - "{} = {} ".format(string_list[index], fitted_x_list[index]) - ) - file_RC.write("\n") - file_RC.write("#R-factor = {}\n".format(Rfactor)) - if self.normalization == "TOTAL": - file_RC.write("#I_calculated_total={}\n".format(I_calculated_norm)) - file_RC.write("#I_experiment_total={}\n".format(I_experiment_norm)) - else: # self.normalization == "MAX" - file_RC.write("#I_calculated_max={}\n".format(I_calculated_norm)) - file_RC.write("#I_experiment_max={}\n".format(I_experiment_norm)) - file_RC.write("#") - for xname in ( - "degree", - "convolution_I_calculated", - "I_experiment", - "convolution_I_calculated(normalized)", - "I_experiment(normalized)", - "I_calculated", - ): - file_RC.write(xname) - file_RC.write(" ") - file_RC.write("\n") - - # Write rocking curve - for index in range(len(degree_list)): - file_RC.write( - "{} {} {} {} {} {}\n".format( - degree_list[index], - convolution_I_calculated_list[index], - I_experiment_list[index], - convolution_I_calculated_list_normalized[index], - I_experiment_list_normalized[index], - I_calculated_list[index], + cal_number = self.cal_number + spot_weight = self.spot_weight + weight_type = self.weight_type + if self.generate_rocking_curve : + if self.isLogmode : time_sta = time.perf_counter() + with open("RockingCurve_calculated.txt", "w") as file_RC: + # Write headers + file_RC.write("#") + for index in range(dimension): + file_RC.write( + "{} = {} ".format(string_list[index], fitted_x_list[index]) ) - ) + file_RC.write("\n") + file_RC.write(f"#Rfactor_type = {self.Rfactor_type}") + file_RC.write("\n") + file_RC.write(f"#normalization = {self.normalization}") + file_RC.write("\n") + if weight_type is not None: + file_RC.write(f"#weight_type = {weight_type}\n") + file_RC.write("#R-factor = {}\n".format(Rfactor)) + file_RC.write("#cal_number = {}\n".format(cal_number)) + file_RC.write("#spot_weight = {}\n".format(spot_weight)) + file_RC.write("#NOTICE : Intensities are NOT multiplied by spot_weight.") + file_RC.write("\n") + file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.") + file_RC.write("\n") + file_RC.write("#sum( I_(spot) ) = 1") + file_RC.write("\n") + file_RC.write("#") + file_RC.write("\n") + + label_column = ["glancing_angle"] + fmt_rc = '%.5f' + for i in range(len(cal_number)): + label_column.append(f"cal_number={self.cal_number[i]}") + fmt_rc += " %.15e" + + for i in range(len(label_column)): + file_RC.write(f"# #{i} {label_column[i]}") + file_RC.write("\n") + g_angle_for_rc = np.array([glancing_angle]) + np.savetxt( + file_RC, + np.block( + [g_angle_for_rc.T, + conv_I_calculated_normalized_l.T] + ), + fmt=fmt_rc + ) + + if self.isLogmode : + time_end = time.perf_counter() + self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta return Rfactor def _g(self, x): @@ -396,77 +787,200 @@ def _g(self, x): return g def _calc_I_from_file(self): + if self.isLogmode : time_sta = time.perf_counter() + surface_output_file = self.surface_output_file calculated_first_line = self.calculated_first_line calculated_last_line = self.calculated_last_line - row_number = self.row_number - degree_max = self.degree_max - degree_list = self.degree_list - - nlines = calculated_last_line - calculated_first_line + 1 - # TODO: handling error - assert 0 < nlines - - # TODO: nlines == len(degree_list) ? - # assert nlines == len(degree_list) - - I_calculated_list = [] - with open(surface_output_file, "r") as file_result: - for _ in range(calculated_first_line - 1): - file_result.readline() - for _ in range(nlines): - line = file_result.readline() - words = line.replace(",", "").split() - I_calculated_list.append(float(words[row_number - 1])) - # TODO: degree_calc == degree_exp should be checked for every line? - degree_last = round(float(words[0]), 1) - if degree_last != degree_max: - print( - "WARNING : degree in lastline = {}, but {} expected".format( - degree_last, degree_max - ) - ) - - ##### convolution ##### - convolution_I_calculated_list = [] - for index in range(len(I_calculated_list)): - integral = 0.0 - degree_org = degree_list[index] - for index2 in range(len(I_calculated_list)): - integral += ( - I_calculated_list[index2] - * self._g(degree_org - degree_list[index2]) - * 0.1 - ) - convolution_I_calculated_list.append(integral) - - if self.normalization == "TOTAL": - I_calculated_norm = sum(convolution_I_calculated_list) - else: # self.normalization == "MAX" - I_calculated_norm = max(convolution_I_calculated_list) - convolution_I_calculated_list_normalized = [ - c / I_calculated_norm for c in convolution_I_calculated_list - ] + calculated_info_line = self.calculated_info_line + calculated_nlines = self.calculated_nlines + omega = self.omega + + cal_number = self.cal_number + + assert 0 < calculated_nlines + + if self.run_scheme == "connect_so": + Clines = self.surf_output + + elif self.run_scheme == "subprocess": + file_input = open(self.surface_output_file, "r") + Clines = file_input.readlines() + file_input.close() + + # Reads the number of glancing angles and beams + line = Clines[calculated_info_line-1] + line = line.replace(",", "") + data = line.split() + + calc_number_of_g_angles_org = int(data[1]) + calc_number_of_beams_org = int(data[2]) + + if calc_number_of_g_angles_org != calculated_nlines: + if self.mpirank == 0 and not self.isWarning_calcnline : + msg ="WARNING:\n" + msg+="The number of lines in the calculated file " + msg+="that you have set up does not match " + msg+="the number of glancing angles in the calculated file.\n" + msg+="The number of lines (nline) in the calculated file " + msg+="used for the R-factor calculation " + msg+="is determined by the following values\n" + msg+='nline = "calculated_last_line" - "calculated_first_line" + 1.' + print(msg) + self.isWarning_calcnline = True + calc_number_of_g_angles = calculated_nlines + + # Define the array for the rocking curve data. + # Note the components with (beam-index)=0 are the degree data + RC_data_org = np.zeros((calc_number_of_g_angles, calc_number_of_beams_org+1)) + for g_angle_index in range(calc_number_of_g_angles): + line_index = (calculated_first_line - 1) + g_angle_index + line = Clines[ line_index ] + # print("data line: ", line_index, g_angle_index, line) + line = line.replace(",", "") + data = line.split() + # print(data) + RC_data_org[g_angle_index,0]=float(data[0]) + for beam_index in range(calc_number_of_beams_org): + RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] + + if self.isLogmode : + time_end = time.perf_counter() + self.detail_timer["load_STR_result"] += time_end - time_sta + + if self.isLogmode : time_sta = time.perf_counter() + verbose_mode = False + data_convolution = lib_make_convolution.calc( + RC_data_org, + calc_number_of_beams_org, + calc_number_of_g_angles, + omega, + verbose_mode, + ) + + if self.isLogmode : + time_end = time.perf_counter() + self.detail_timer["convolution"] += time_end - time_sta + + if self.isLogmode : time_sta = time.perf_counter() + + angle_number_convolution = data_convolution.shape[0] + if self.angle_number_experiment !=angle_number_convolution: + raise exception.InputError( + "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." + ) + glancing_angle = data_convolution[:,0] + + beam_number_reference = len(cal_number) + for loop_index in range(beam_number_reference): + cal_index = cal_number[loop_index] + conv_I_calculated = data_convolution[:,cal_index] + if self.normalization == "TOTAL": + conv_I_calculated_norm = np.sum(conv_I_calculated) + conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm + conv_I_calculated_norm_l = np.array( + [conv_I_calculated_norm] + ) + conv_I_calculated_normalized_l = np.array( + [conv_I_calculated_normalized] + ) + elif self.normalization=="MULTI_SPOT" and self.weight_type=="calc": + conv_I_calculated_norm = np.sum(conv_I_calculated) + conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm + if loop_index == 0: #first loop + conv_I_calculated_norm_l = np.array( + [conv_I_calculated_norm] + ) + conv_I_calculated_normalized_l = np.array( + [conv_I_calculated_normalized] + ) + else: # N-th loop + conv_I_calculated_norm_l = np.block( + [conv_I_calculated_norm_l, + conv_I_calculated_norm] + ) + conv_I_calculated_normalized_l = np.block( + [[conv_I_calculated_normalized_l], + [conv_I_calculated_normalized]] + ) + if loop_index == beam_number_reference-1: #first loop + #conv_I_c_norm_l_power2 = conv_I_calculated_norm_l**2 + #self.spot_weight = conv_I_c_norm_l_power2 + #self.spot_weight = (conv_I_c_norm_l_power2 + # / sum(conv_I_calculated_norm_l)**2) + # / sum(conv_I_c_norm_l_power2) ) + self.spot_weight = ( conv_I_calculated_norm_l + / sum(conv_I_calculated_norm_l) )**2 + elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + conv_I_calculated_norm = np.sum(conv_I_calculated) + conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm + if loop_index == 0: #first loop + conv_I_calculated_norm_l = np.array( + [conv_I_calculated_norm] + ) + conv_I_calculated_normalized_l = np.array( + [conv_I_calculated_normalized] + ) + else: # N-th loop + conv_I_calculated_norm_l = np.block( + [conv_I_calculated_norm_l, + conv_I_calculated_norm] + ) + conv_I_calculated_normalized_l = np.block( + [[conv_I_calculated_normalized_l], + [conv_I_calculated_normalized]] + ) + else: + msg ="ERROR: normalization must be " + msg+="MULTI_SPOT or TOTAL" + raise exception.InputError(msg) + + if self.isLogmode : + time_end = time.perf_counter() + self.detail_timer["normalize_calc_I"] += time_end - time_sta + return ( - convolution_I_calculated_list_normalized, - I_calculated_norm, - I_calculated_list, - convolution_I_calculated_list, - ) - - def _calc_Rfactor(self, calc_result): - I_experiment_list_normalized = self.reference_normalized + glancing_angle, + angle_number_convolution, + conv_I_calculated_norm_l, + conv_I_calculated_normalized_l + ) + + def _calc_Rfactor(self, n_g_angle, calc_result, exp_result): + spot_weight = self.spot_weight + n_spot = len(spot_weight) if self.Rfactor_type == "A": R = 0.0 - for I_exp, I_calc in zip(I_experiment_list_normalized, calc_result): - R += (I_exp - I_calc) ** 2 + for spot_index in range(n_spot): + R_spot = 0.0 + for angle_index in range(n_g_angle): + R_spot += (exp_result[spot_index, angle_index] + - calc_result[spot_index, angle_index] )**2 + R_spot = spot_weight[spot_index] * R_spot + R += R_spot R = np.sqrt(R) + elif self.Rfactor_type == "A2": + R = 0.0 + for spot_index in range(n_spot): + R_spot = 0.0 + for angle_index in range(n_g_angle): + R_spot += (exp_result[spot_index, angle_index] + - calc_result[spot_index, angle_index] )**2 + R_spot = spot_weight[spot_index] * R_spot + R += R_spot else: # self.Rfactor_type == "B" - # Pendry's R-factor + all_exp_result = [] + all_calc_result = [] + for spot_index in range(n_spot): + for angle_index in range(n_g_angle): + all_exp_result.append( + exp_result[spot_index, angle_index]) + all_calc_result.append( + calc_result[spot_index, angle_index]) y1 = 0.0 y2 = 0.0 y3 = 0.0 - for I_exp, I_calc in zip(I_experiment_list_normalized, calc_result): + for I_exp, I_calc in zip(all_exp_result, all_calc_result): y1 += (I_exp - I_calc) ** 2 y2 += I_exp ** 2 y3 += I_calc ** 2 From 1f9159860bb55a67197952569ca539754dca39e6 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 14 Oct 2023 15:54:27 +0900 Subject: [PATCH 30/67] delete sim_trhepd_rheed_mb_connect.py --- .../solver/sim_trhepd_rheed_mb_connect.py | 988 ------------------ 1 file changed, 988 deletions(-) delete mode 100644 src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py deleted file mode 100644 index a9191227..00000000 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ /dev/null @@ -1,988 +0,0 @@ -from typing import List -import itertools -import os -import os.path -import shutil -from pathlib import Path -import subprocess -import time -from . import lib_make_convolution - -import numpy as np - -import py2dmat -from py2dmat import exception, mpi - -import ctypes - -from typing import TYPE_CHECKING - -import copy - -class Solver(py2dmat.solver.SolverBase): - path_to_solver: Path - - def __init__(self, info: py2dmat.Info): - super().__init__(info) - self.mpicomm = mpi.comm() - self.mpisize = mpi.size() - self.mpirank = mpi.rank() - - self._name = "sim_trhepd_rheed_mb_connect" - - self.run_scheme = info.solver.get("run_scheme",None) - scheme_list = ["subprocess","connect_so"] - scheme_judge = [i == self.run_scheme for i in scheme_list] - - if not any(scheme_judge): - raise exception.InputError( - "ERROR : Input scheme is incorrect." - ) - - if self.run_scheme == "connect_so": - self.load_so() - - elif self.run_scheme == "subprocess": - #path to surf.exe - p2solver = info.solver["config"].get("surface_exec_file", "surf.exe") - if os.path.dirname(p2solver) != "": - # ignore ENV[PATH] - self.path_to_solver = self.root_dir / Path(p2solver).expanduser() - else: - for P in itertools.chain([self.root_dir], os.environ["PATH"].split(":")): - self.path_to_solver = Path(P) / p2solver - if os.access(self.path_to_solver, mode=os.X_OK): - break - if not os.access(self.path_to_solver, mode=os.X_OK): - raise exception.InputError(f"ERROR: solver ({p2solver}) is not found") - - self.isLogmode = False - self.set_detail_timer() - - self.input = Solver.Input(info,self.detail_timer) - self.output = Solver.Output(info,self.detail_timer) - - def set_detail_timer(self): - # TODO: Operate log_mode with toml file. Generate txt of detail_timer. - if self.isLogmode: - self.detail_timer = {} - self.detail_timer["prepare_Log-directory"] = 0 - self.detail_timer["make_surf_input"] = 0 - self.detail_timer["launch_STR"] = 0 - self.detail_timer["load_STR_result"] = 0 - self.detail_timer["convolution"] = 0 - self.detail_timer["normalize_calc_I"] = 0 - self.detail_timer["calculate_R-factor"] = 0 - self.detail_timer["make_RockingCurve.txt"] = 0 - self.detail_timer["delete_Log-directory"] = 0 - else: - self.detail_timer = None - - def default_run_scheme(self): - """ - Return - ------- - str - run_scheme. - """ - return self.run_scheme - - def command(self) -> List[str]: - """Command to invoke solver""" - return [str(self.path_to_solver)] - - def prepare(self, message: py2dmat.Message) -> None: - fitted_x_list, subdir = self.input.prepare(message) - self.work_dir = self.proc_dir / Path(subdir) - - self.output.prepare(fitted_x_list) - - def get_results(self) -> float: - return self.output.get_results(self.work_dir) - - def load_so(self): - self.lib = np.ctypeslib.load_library("surf.so", - os.path.dirname(__file__)) - self.lib.surf_so.argtypes = ( - ctypes.POINTER(ctypes.c_int), - ctypes.POINTER(ctypes.c_int), - np.ctypeslib.ndpointer(), - ctypes.POINTER(ctypes.c_int), - ctypes.POINTER(ctypes.c_int), - np.ctypeslib.ndpointer(), - np.ctypeslib.ndpointer() - ) - self.lib.surf_so.restype = ctypes.c_void_p - - def launch_so(self): - - n_template_file = len(self.input.template_file) - m_template_file = self.input.surf_tempalte_width_for_fortran - n_bulk_file = len(self.input.bulk_file) - m_bulk_file = self.input.bulk_out_width_for_fortran - - # NOTE: The "20480" is related to the following directive in surf_so.f90. - # character(c_char), intent(inout) :: surf_out(20480) - emp_str = ' '*20480 - self.output.surf_output = np.array([emp_str.encode()]) - self.lib.surf_so( - ctypes.byref(ctypes.c_int(n_template_file)), - ctypes.byref(ctypes.c_int(m_template_file)), - self.input.template_file, - ctypes.byref(ctypes.c_int(n_bulk_file)), - ctypes.byref(ctypes.c_int(m_bulk_file)), - self.input.bulk_file, - self.output.surf_output - ) - self.output.surf_output = self.output.surf_output[0].decode().splitlines() - - def run(self, nprocs: int = 1, nthreads: int = 1) -> None: - if self.isLogmode : time_sta = time.perf_counter() - - if self.run_scheme == "connect_so": - self.launch_so() - elif self.run_scheme == "subprocess": - self._run_by_subprocess([str(self.path_to_solver)]) - - if self.isLogmode: - time_end = time.perf_counter() - self.detail_timer["launch_STR"] += time_end - time_sta - - class Input(object): - root_dir: Path - output_dir: Path - dimension: int - string_list: List[str] - bulk_output_file: Path - surface_input_file: Path - surface_template_file: Path - - def __init__(self, info, d_timer): - self.mpicomm = mpi.comm() - self.mpisize = mpi.size() - self.mpirank = mpi.rank() - - if d_timer is None: - self.isLogmode = False - else: - self.isLogmode = True - self.detail_timer = d_timer - - self.root_dir = info.base["root_dir"] - self.output_dir = info.base["output_dir"] - - if "dimension" in info.solver: - self.dimension = info.solver["dimension"] - else: - self.dimension = info.base["dimension"] - - info_s = info.solver - self.run_scheme = info_s["run_scheme"] - self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) - - # NOTE: - # surf_tempalte_width_for_fortran: Number of strings per line of template.txt data for surf.so. - # bulk_out_width_for_fortran: Number of strings per line of bulkP.txt data for surf.so. - if self.run_scheme=="connect_so": - self.surf_tempalte_width_for_fortran = 128 - self.bulk_out_width_for_fortran = 1024 - - info_param = info_s.get("param", {}) - v = info_param.setdefault("string_list", ["value_01", "value_02"]) - if len(v) != self.dimension: - raise exception.InputError( - f"ERROR: len(string_list) != dimension ({len(v)} != {self.dimension})" - ) - self.string_list = v - - info_config = info_s.get("config", {}) - self.surface_input_file = Path( - info_config.get("surface_input_file", "surf.txt") - ) - - filename = info_config.get("surface_template_file", "template.txt") - filename = Path(filename).expanduser().resolve() - self.surface_template_file = self.root_dir / filename - if not self.surface_template_file.exists(): - raise exception.InputError( - f"ERROR: surface_template_file ({self.surface_template_file}) does not exist" - ) - - if self.mpirank == 0: - self._check_template() - temp_origin = self.load_surface_template_file(filename) - else: - temp_origin = None - self.template_file_origin = self.mpicomm.bcast(temp_origin,root=0) - - if self.run_scheme == "connect_so": - filename = info_config.get("bulk_output_file", "bulkP.txt") - filename = Path(filename).expanduser().resolve() - self.bulk_output_file = self.root_dir / filename - if not self.bulk_output_file.exists(): - raise exception.InputError( - f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" - ) - - if self.mpirank == 0: - bulk_f = self.load_bulk_output_file(filename) - else: - bulk_f = None - self.bulk_file = self.mpicomm.bcast(bulk_f,root=0) - - else: - filename = info_config.get("bulk_output_file", "bulkP.b") - filename = Path(filename).expanduser().resolve() - self.bulk_output_file = self.root_dir / filename - if not self.bulk_output_file.exists(): - raise exception.InputError( - f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" - ) - - def load_surface_template_file(self, filename): - template_file = [] - with open(self.surface_template_file) as f: - for line in f: - template_file.append(line) - return template_file - - def load_bulk_output_file(self, filename) : - bulk_file = [] - with open(self.bulk_output_file) as f: - for line in f: - line = line.replace("\t", " ").replace("\n", " ") - line = line.encode().ljust(self.bulk_out_width_for_fortran) - bulk_file.append(line) - bulk_f = np.array(bulk_file) - return bulk_f - - def prepare(self, message: py2dmat.Message): - if self.isLogmode : time_sta = time.perf_counter() - - x_list = message.x - step = message.step - iset = message.set - - dimension = self.dimension - string_list = self.string_list - bulk_output_file = self.bulk_output_file - solver_input_file = self.surface_input_file - fitted_x_list = [] - for index in range(dimension): - fitted_value = " " if x_list[index] >= 0 else "" - fitted_value += format(x_list[index], ".8f") - fitted_value = fitted_value[: len(string_list[index])] - fitted_x_list.append(fitted_value) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["make_surf_input"] += time_end - time_sta - - if self.isLogmode : time_sta = time.perf_counter() - - if self.generate_rocking_curve: - folder_name = self._pre_bulk(step, bulk_output_file, iset) - else: - if self.run_scheme == "connect_so": - folder_name = "." - - elif self.run_scheme == "subprocess": - #make workdir and copy bulk output file - folder_name = self._pre_bulk(step, bulk_output_file, iset) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["prepare_Log-directory"] += time_end - time_sta - - if self.isLogmode : time_sta = time.perf_counter() - - self._replace(fitted_x_list, folder_name) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["make_surf_input"] += time_end - time_sta - - return fitted_x_list, folder_name - - def _pre_bulk(self, Log_number, bulk_output_file, iset): - folder_name = "Log{:08d}_{:08d}".format(Log_number, iset) - os.makedirs(folder_name, exist_ok=True) - if self.run_scheme == "connect_so": - pass - else: #self.run_scheme == "subprocess": - shutil.copy( - bulk_output_file, os.path.join(folder_name, bulk_output_file.name) - ) - return folder_name - - def _replace(self, fitted_x_list, folder_name): - template_file = [] - if self.run_scheme == "subprocess": - file_output = open(os.path.join(folder_name, self.surface_input_file), "w") - for line in self.template_file_origin: - for index in range(self.dimension): - if line.find(self.string_list[index]) != -1: - line = line.replace( - self.string_list[index], - fitted_x_list[index] - ) - - if self.run_scheme == "connect_so": - line = line.replace("\t", " ").replace("\n", " ") - line = line.encode().ljust(self.surf_tempalte_width_for_fortran) - template_file.append(line) - - elif self.run_scheme == "subprocess": - file_output.write(line) - - - if self.run_scheme == "connect_so": - self.template_file = np.array(template_file) - elif self.run_scheme == "subprocess": - file_output.close() - - def _check_template(self) -> None: - found = [False] * self.dimension - with open(self.surface_template_file, "r") as file_input: - for line in file_input: - for index, placeholder in enumerate(self.string_list): - if line.find(placeholder) != -1: - found[index] = True - if not np.all(found): - msg = "ERROR: the following labels do not appear in the template file:" - for label, f in zip(self.string_list, found): - if not f: - msg += "\n" - msg += label - raise exception.InputError(msg) - - class Output(object): - """ - Output manager. - """ - - dimension: int - string_list: List[str] - surface_output_file: str - normalization: str - Rfactor_type: str - calculated_first_line: int - calculated_last_line: int - - I_reference: List[float] - I_reference_norm: float - I_reference_normalized: List[float] - - def __init__(self, info, d_timer): - self.mpicomm = mpi.comm() - self.mpisize = mpi.size() - self.mpirank = mpi.rank() - - if d_timer is None: - self.isLogmode = False - else: - self.isLogmode = True - self.detail_timer = d_timer - - if "dimension" in info.solver: - self.dimension = info.solver["dimension"] - else: - self.dimension = info.base["dimension"] - - info_s = info.solver - self.run_scheme = info_s["run_scheme"] - self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) - - # solver.post - info_post = info_s.get("post", {}) - v = info_post.get("normalization", "TOTAL") - available_normalization = ["TOTAL", "MULTI_SPOT"] - if v == "MAX": - raise exception.InputError('ERROR: normalization == "MAX" is not available') - if v not in available_normalization: - msg ="ERROR: normalization must be " - msg+="MULTI_SPOT or TOTAL" - raise exception.InputError(msg) - self.normalization = v - - v = info_post.get("weight_type", None) - available_weight_type = ["calc", "manual"] - if self.normalization == "MULTI_SPOT": - if v is None : - msg ='ERROR: If normalization = "MULTI_SPOT", ' - msg+='"weight_type" must be set in [solver.post].' - raise exception.InputError(msg) - elif v not in available_weight_type: - msg ="ERROR: weight_type must be " - msg+="calc or manual" - raise exception.InputError(msg) - else: - if v is not None : - if self.mpirank == 0: - msg ='NOTICE: If normalization = "MULTI_SPOT" is not set, ' - msg+='"weight_type" is NOT considered in the calculation.' - print(msg) - self.weight_type = None - self.weight_type = v - - v = info_post.get("spot_weight", []) - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - if v == [] : - msg ='ERROR: With normalization="MULTI_SPOT" and ' - msg+='weight_type=="manual", the "spot_weight" option ' - msg+='must be set in [solver.post].' - raise exception.InputError(msg) - self.spot_weight = np.array(v)/sum(v) - else: - if v != []: - if self.mpirank == 0: - msg ='NOTICE: With the specified "normalization" option, ' - msg+='the "spot_weight" you specify in the toml file is ignored, ' - msg+='since the spot_weight is automatically calculated within the program.' - print(msg) - if self.normalization== "TOTAL": - self.spot_weight = np.array([1]) - - v = info_post.get("Rfactor_type", "A") - if v not in ["A", "B", "A2"]: - raise exception.InputError("ERROR: Rfactor_type must be A, A2 or B") - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - if (v!="A") and (v!="A2") : - msg ='With normalization="MULTI_SPOT" and weight_type=="manual", ' - msg+='only Rfactor_type="A" or Rfactor_type="A2" is valid.' - raise exception.InputError(msg) - self.Rfactor_type = v - - v = info_post.get("omega", 0.5) - if v <= 0.0: - raise exception.InputError("ERROR: omega should be positive") - self.omega = v - - self.remove_work_dir = info_post.get("remove_work_dir", False) - - - # solver.param - info_param = info_s.get("param", {}) - v = info_param.setdefault("string_list", ["value_01", "value_02"]) - if len(v) != self.dimension: - raise exception.InputError( - f"ERROR: len(string_list) != dimension ({len(v)} != {self.dimension})" - ) - self.string_list = v - - # solver.reference - info_ref = info_s.get("reference", {}) - v = info_ref.setdefault("reference_first_line", 1) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: reference_first_line should be non-negative integer" - ) - firstline = v - - # None is dummy value - # If "reference_last_line" is not specified in the toml file, - # the last line of the reference file is used for the R-factor calculation. - v = info_ref.setdefault("reference_last_line", None) - if v is None: - reference_are_read_to_final_line = True - else: - reference_are_read_to_final_line = False - if not (isinstance(v, int) and v >= firstline): - raise exception.InputError( - "ERROR: reference_last_line < reference_first_line" - ) - lastline = v - - reference_path = info_ref.get("path", "experiment.txt") - data_experiment = self.read_experiment( - reference_path, firstline, lastline, - reference_are_read_to_final_line ) - self.angle_number_experiment = data_experiment.shape[0] - self.beam_number_exp_raw = data_experiment.shape[1] - - v = info_ref.get("exp_number", None) - - if v == None : - raise exception.InputError( - "ERROR: You have to set the 'exp_number'." - ) - - if not isinstance(v, list): - raise exception.InputError( - "ERROR: 'exp_number' must be a list type." - ) - - if max(v) > self.beam_number_exp_raw : - raise exception.InputError( - "ERROR: The 'exp_number' setting is wrong." - ) - - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - if len(v) != len(self.spot_weight): - raise exception.InputError( - "ERROR:len('exp_number') and len('spot_weight') do not match." - ) - - if self.normalization=="TOTAL" and len(v)!=1: - msg ='When normalization=="TOTAL" is specified, ' - msg+='only one beam data can be specified with ' - msg+='"exp_number" option.' - raise exception.InputError(msg) - - self.exp_number = v - - #Normalization of reference data - self.beam_number_experiment = len(self.exp_number) - for loop_index in range(self.beam_number_experiment): - exp_index = self.exp_number[loop_index] - I_reference = data_experiment[:,exp_index] - if self.normalization == "TOTAL": - I_reference_norm = np.sum(I_reference) - I_reference_normalized = I_reference/I_reference_norm - I_reference_norm_l = np.array([I_reference_norm]) - self.I_reference_normalized_l = np.array([I_reference_normalized]) - elif self.normalization=="MULTI_SPOT" and self.weight_type=="calc": - I_reference_norm = np.sum(I_reference) - I_reference_normalized = I_reference/I_reference_norm - if loop_index == 0: #first loop - I_reference_norm_l = np.array([I_reference_norm]) - self.I_reference_normalized_l = np.array([I_reference_normalized]) - else : # N-th loop - I_reference_norm_l = np.block( - [I_reference_norm_l, I_reference_norm] - ) - self.I_reference_normalized_l = np.block( - [[self.I_reference_normalized_l], - [I_reference_normalized]] - ) - elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - I_reference_norm = np.sum(I_reference) - I_reference_normalized = I_reference/I_reference_norm - if loop_index == 0: #first loop - I_reference_norm_l = np.array([I_reference_norm]) - self.I_reference_normalized_l = np.array([I_reference_normalized]) - else : # N-th loop - I_reference_norm_l = np.block( - [I_reference_norm_l, I_reference_norm] - ) - self.I_reference_normalized_l = np.block( - [[self.I_reference_normalized_l], - [I_reference_normalized]] - ) - else: - msg ="ERROR: normalization must be " - msg+="MULTI_SPOT or TOTAL" - raise exception.InputError(msg) - # solver.config - info_config = info_s.get("config", {}) - self.surface_output_file = info_config.get( - "surface_output_file", "surf-bulkP.s" - ) - - v = info_config.get("calculated_first_line", 5) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: calculated_first_line should be non-negative integer" - ) - self.calculated_first_line = v - - v = info_config.get( - "calculated_last_line", - self.calculated_first_line + self.angle_number_experiment-1 - ) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: calculated_last_line should be non-negative integer" - ) - self.calculated_last_line = v - - # Number of lines in the computation file - # used for R-factor calculations. - self.calculated_nlines = (self.calculated_last_line - - self.calculated_first_line + 1 ) - - if self.angle_number_experiment != self.calculated_nlines : - raise exception.InputError( - "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." - ) - - # Variable indicating whether the warning - # "self.calculated_nlines does not match - # the number of glancing angles in the calculated file" - # is displayed. - self.isWarning_calcnline = False - - v = info_config.get("calculated_info_line", 2) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: calculated_info_line should be non-negative integer" - ) - self.calculated_info_line = v - - v = info_config.get("cal_number",None) - if v == None : - raise exception.InputError( - "ERROR: You have to set the 'cal_number'." - ) - - if not isinstance(v, list): - raise exception.InputError( - "ERROR: 'cal_number' must be a list type." - ) - - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - if len(self.spot_weight) != len(v): - raise exception.InputError( - "len('cal_number') and len('spot_weight') do not match." - ) - if self.normalization=="TOTAL" and len(v)!=1: - msg ='When normalization=="TOTAL" is specified, ' - msg+='only one beam data can be specified with ' - msg+='"cal_number" option.' - raise exception.InputError(msg) - self.cal_number = v - - def read_experiment(self, ref_path, first, last, read_to_final_line): - # Read experiment data - if self.mpirank == 0: - file_input = open(ref_path, "r") - Elines = file_input.readlines() - - firstline = first - if read_to_final_line : - lastline = len(Elines) - else: - lastline = last - - n_exp_row = lastline-firstline+1 - - # get value from data - for row_index in range(n_exp_row) : - line_index = firstline + row_index - 1 - line = Elines[line_index] - data = line.split() - # first loop - if row_index == 0: - n_exp_column = len(data) - data_e = np.zeros((n_exp_row, n_exp_column)) #init value - - for column_index in range(n_exp_column): - data_e[row_index, column_index] = float(data[column_index]) - else: - data_e = None - data_exp = self.mpicomm.bcast(data_e,root=0) - return data_exp - - def prepare(self, fitted_x_list): - self.fitted_x_list = fitted_x_list - - def get_results(self, work_dir) -> float: - """ - Get Rfactor obtained by the solver program. - Returns - ------- - """ - # Calculate Rfactor and Output numerical results - cwd = os.getcwd() - os.chdir(work_dir) - Rfactor = self._post(self.fitted_x_list) - os.chdir(cwd) - - #delete Log-directory - if self.isLogmode : time_sta = time.perf_counter() - - if self.run_scheme == "subprocess": - if self.remove_work_dir: - def rmtree_error_handler(function, path, excinfo): - print(f"WARNING: Failed to remove a working directory, {path}") - shutil.rmtree(work_dir, onerror=rmtree_error_handler) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["delete_Log-directory"] += time_end - time_sta - return Rfactor - - def _post(self, fitted_x_list): - I_experiment_normalized_l = self.I_reference_normalized_l - - ( - glancing_angle, - conv_number_of_g_angle, - conv_I_calculated_norm_l, - conv_I_calculated_normalized_l, - ) = self._calc_I_from_file() - - if self.isLogmode : time_sta = time.perf_counter() - Rfactor = self._calc_Rfactor( - conv_number_of_g_angle, - conv_I_calculated_normalized_l, - I_experiment_normalized_l, - ) - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["calculate_R-factor"] += time_end - time_sta - - #generate rocking curve - dimension = self.dimension - string_list = self.string_list - cal_number = self.cal_number - spot_weight = self.spot_weight - weight_type = self.weight_type - if self.generate_rocking_curve : - if self.isLogmode : time_sta = time.perf_counter() - with open("RockingCurve_calculated.txt", "w") as file_RC: - # Write headers - file_RC.write("#") - for index in range(dimension): - file_RC.write( - "{} = {} ".format(string_list[index], fitted_x_list[index]) - ) - file_RC.write("\n") - file_RC.write(f"#Rfactor_type = {self.Rfactor_type}") - file_RC.write("\n") - file_RC.write(f"#normalization = {self.normalization}") - file_RC.write("\n") - if weight_type is not None: - file_RC.write(f"#weight_type = {weight_type}\n") - file_RC.write("#R-factor = {}\n".format(Rfactor)) - file_RC.write("#cal_number = {}\n".format(cal_number)) - file_RC.write("#spot_weight = {}\n".format(spot_weight)) - file_RC.write("#NOTICE : Intensities are NOT multiplied by spot_weight.") - file_RC.write("\n") - file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.") - file_RC.write("\n") - file_RC.write("#sum( I_(spot) ) = 1") - file_RC.write("\n") - file_RC.write("#") - file_RC.write("\n") - - label_column = ["glancing_angle"] - fmt_rc = '%.5f' - for i in range(len(cal_number)): - label_column.append(f"cal_number={self.cal_number[i]}") - fmt_rc += " %.15e" - - for i in range(len(label_column)): - file_RC.write(f"# #{i} {label_column[i]}") - file_RC.write("\n") - g_angle_for_rc = np.array([glancing_angle]) - np.savetxt( - file_RC, - np.block( - [g_angle_for_rc.T, - conv_I_calculated_normalized_l.T] - ), - fmt=fmt_rc - ) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta - return Rfactor - - def _g(self, x): - g = (0.939437 / self.omega) * np.exp( - -2.77259 * (x ** 2.0 / self.omega ** 2.0) - ) - return g - - def _calc_I_from_file(self): - if self.isLogmode : time_sta = time.perf_counter() - - surface_output_file = self.surface_output_file - calculated_first_line = self.calculated_first_line - calculated_last_line = self.calculated_last_line - calculated_info_line = self.calculated_info_line - calculated_nlines = self.calculated_nlines - omega = self.omega - - cal_number = self.cal_number - - assert 0 < calculated_nlines - - if self.run_scheme == "connect_so": - Clines = self.surf_output - - elif self.run_scheme == "subprocess": - file_input = open(self.surface_output_file, "r") - Clines = file_input.readlines() - file_input.close() - - # Reads the number of glancing angles and beams - line = Clines[calculated_info_line-1] - line = line.replace(",", "") - data = line.split() - - calc_number_of_g_angles_org = int(data[1]) - calc_number_of_beams_org = int(data[2]) - - if calc_number_of_g_angles_org != calculated_nlines: - if self.mpirank == 0 and not self.isWarning_calcnline : - msg ="WARNING:\n" - msg+="The number of lines in the calculated file " - msg+="that you have set up does not match " - msg+="the number of glancing angles in the calculated file.\n" - msg+="The number of lines (nline) in the calculated file " - msg+="used for the R-factor calculation " - msg+="is determined by the following values\n" - msg+='nline = "calculated_last_line" - "calculated_first_line" + 1.' - print(msg) - self.isWarning_calcnline = True - calc_number_of_g_angles = calculated_nlines - - # Define the array for the rocking curve data. - # Note the components with (beam-index)=0 are the degree data - RC_data_org = np.zeros((calc_number_of_g_angles, calc_number_of_beams_org+1)) - for g_angle_index in range(calc_number_of_g_angles): - line_index = (calculated_first_line - 1) + g_angle_index - line = Clines[ line_index ] - # print("data line: ", line_index, g_angle_index, line) - line = line.replace(",", "") - data = line.split() - # print(data) - RC_data_org[g_angle_index,0]=float(data[0]) - for beam_index in range(calc_number_of_beams_org): - RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["load_STR_result"] += time_end - time_sta - - if self.isLogmode : time_sta = time.perf_counter() - verbose_mode = False - data_convolution = lib_make_convolution.calc( - RC_data_org, - calc_number_of_beams_org, - calc_number_of_g_angles, - omega, - verbose_mode, - ) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["convolution"] += time_end - time_sta - - if self.isLogmode : time_sta = time.perf_counter() - - angle_number_convolution = data_convolution.shape[0] - if self.angle_number_experiment !=angle_number_convolution: - raise exception.InputError( - "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." - ) - glancing_angle = data_convolution[:,0] - - beam_number_reference = len(cal_number) - for loop_index in range(beam_number_reference): - cal_index = cal_number[loop_index] - conv_I_calculated = data_convolution[:,cal_index] - if self.normalization == "TOTAL": - conv_I_calculated_norm = np.sum(conv_I_calculated) - conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm - conv_I_calculated_norm_l = np.array( - [conv_I_calculated_norm] - ) - conv_I_calculated_normalized_l = np.array( - [conv_I_calculated_normalized] - ) - elif self.normalization=="MULTI_SPOT" and self.weight_type=="calc": - conv_I_calculated_norm = np.sum(conv_I_calculated) - conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm - if loop_index == 0: #first loop - conv_I_calculated_norm_l = np.array( - [conv_I_calculated_norm] - ) - conv_I_calculated_normalized_l = np.array( - [conv_I_calculated_normalized] - ) - else: # N-th loop - conv_I_calculated_norm_l = np.block( - [conv_I_calculated_norm_l, - conv_I_calculated_norm] - ) - conv_I_calculated_normalized_l = np.block( - [[conv_I_calculated_normalized_l], - [conv_I_calculated_normalized]] - ) - if loop_index == beam_number_reference-1: #first loop - #conv_I_c_norm_l_power2 = conv_I_calculated_norm_l**2 - #self.spot_weight = conv_I_c_norm_l_power2 - #self.spot_weight = (conv_I_c_norm_l_power2 - # / sum(conv_I_calculated_norm_l)**2) - # / sum(conv_I_c_norm_l_power2) ) - self.spot_weight = ( conv_I_calculated_norm_l - / sum(conv_I_calculated_norm_l) )**2 - elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - conv_I_calculated_norm = np.sum(conv_I_calculated) - conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm - if loop_index == 0: #first loop - conv_I_calculated_norm_l = np.array( - [conv_I_calculated_norm] - ) - conv_I_calculated_normalized_l = np.array( - [conv_I_calculated_normalized] - ) - else: # N-th loop - conv_I_calculated_norm_l = np.block( - [conv_I_calculated_norm_l, - conv_I_calculated_norm] - ) - conv_I_calculated_normalized_l = np.block( - [[conv_I_calculated_normalized_l], - [conv_I_calculated_normalized]] - ) - else: - msg ="ERROR: normalization must be " - msg+="MULTI_SPOT or TOTAL" - raise exception.InputError(msg) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["normalize_calc_I"] += time_end - time_sta - - return ( - glancing_angle, - angle_number_convolution, - conv_I_calculated_norm_l, - conv_I_calculated_normalized_l - ) - - def _calc_Rfactor(self, n_g_angle, calc_result, exp_result): - spot_weight = self.spot_weight - n_spot = len(spot_weight) - if self.Rfactor_type == "A": - R = 0.0 - for spot_index in range(n_spot): - R_spot = 0.0 - for angle_index in range(n_g_angle): - R_spot += (exp_result[spot_index, angle_index] - - calc_result[spot_index, angle_index] )**2 - R_spot = spot_weight[spot_index] * R_spot - R += R_spot - R = np.sqrt(R) - elif self.Rfactor_type == "A2": - R = 0.0 - for spot_index in range(n_spot): - R_spot = 0.0 - for angle_index in range(n_g_angle): - R_spot += (exp_result[spot_index, angle_index] - - calc_result[spot_index, angle_index] )**2 - R_spot = spot_weight[spot_index] * R_spot - R += R_spot - else: # self.Rfactor_type == "B" - all_exp_result = [] - all_calc_result = [] - for spot_index in range(n_spot): - for angle_index in range(n_g_angle): - all_exp_result.append( - exp_result[spot_index, angle_index]) - all_calc_result.append( - calc_result[spot_index, angle_index]) - y1 = 0.0 - y2 = 0.0 - y3 = 0.0 - for I_exp, I_calc in zip(all_exp_result, all_calc_result): - y1 += (I_exp - I_calc) ** 2 - y2 += I_exp ** 2 - y3 += I_calc ** 2 - R = y1 / (y2 + y3) - return R From 3d85410cdec74d8fb2ac005e40993ada03ca9675 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 14 Oct 2023 18:40:40 +0900 Subject: [PATCH 31/67] delete sim_trhepd_rheed_mb_connect.py sim_trhepd_rheed_mb_connect.py has already been copied to sim_trhepd_rheed.py in the previous commit(d368b93). --- .../solver/sim_trhepd_rheed_mb_connect.py | 988 ------------------ 1 file changed, 988 deletions(-) delete mode 100644 src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py diff --git a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py b/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py deleted file mode 100644 index a9191227..00000000 --- a/src/py2dmat/solver/sim_trhepd_rheed_mb_connect.py +++ /dev/null @@ -1,988 +0,0 @@ -from typing import List -import itertools -import os -import os.path -import shutil -from pathlib import Path -import subprocess -import time -from . import lib_make_convolution - -import numpy as np - -import py2dmat -from py2dmat import exception, mpi - -import ctypes - -from typing import TYPE_CHECKING - -import copy - -class Solver(py2dmat.solver.SolverBase): - path_to_solver: Path - - def __init__(self, info: py2dmat.Info): - super().__init__(info) - self.mpicomm = mpi.comm() - self.mpisize = mpi.size() - self.mpirank = mpi.rank() - - self._name = "sim_trhepd_rheed_mb_connect" - - self.run_scheme = info.solver.get("run_scheme",None) - scheme_list = ["subprocess","connect_so"] - scheme_judge = [i == self.run_scheme for i in scheme_list] - - if not any(scheme_judge): - raise exception.InputError( - "ERROR : Input scheme is incorrect." - ) - - if self.run_scheme == "connect_so": - self.load_so() - - elif self.run_scheme == "subprocess": - #path to surf.exe - p2solver = info.solver["config"].get("surface_exec_file", "surf.exe") - if os.path.dirname(p2solver) != "": - # ignore ENV[PATH] - self.path_to_solver = self.root_dir / Path(p2solver).expanduser() - else: - for P in itertools.chain([self.root_dir], os.environ["PATH"].split(":")): - self.path_to_solver = Path(P) / p2solver - if os.access(self.path_to_solver, mode=os.X_OK): - break - if not os.access(self.path_to_solver, mode=os.X_OK): - raise exception.InputError(f"ERROR: solver ({p2solver}) is not found") - - self.isLogmode = False - self.set_detail_timer() - - self.input = Solver.Input(info,self.detail_timer) - self.output = Solver.Output(info,self.detail_timer) - - def set_detail_timer(self): - # TODO: Operate log_mode with toml file. Generate txt of detail_timer. - if self.isLogmode: - self.detail_timer = {} - self.detail_timer["prepare_Log-directory"] = 0 - self.detail_timer["make_surf_input"] = 0 - self.detail_timer["launch_STR"] = 0 - self.detail_timer["load_STR_result"] = 0 - self.detail_timer["convolution"] = 0 - self.detail_timer["normalize_calc_I"] = 0 - self.detail_timer["calculate_R-factor"] = 0 - self.detail_timer["make_RockingCurve.txt"] = 0 - self.detail_timer["delete_Log-directory"] = 0 - else: - self.detail_timer = None - - def default_run_scheme(self): - """ - Return - ------- - str - run_scheme. - """ - return self.run_scheme - - def command(self) -> List[str]: - """Command to invoke solver""" - return [str(self.path_to_solver)] - - def prepare(self, message: py2dmat.Message) -> None: - fitted_x_list, subdir = self.input.prepare(message) - self.work_dir = self.proc_dir / Path(subdir) - - self.output.prepare(fitted_x_list) - - def get_results(self) -> float: - return self.output.get_results(self.work_dir) - - def load_so(self): - self.lib = np.ctypeslib.load_library("surf.so", - os.path.dirname(__file__)) - self.lib.surf_so.argtypes = ( - ctypes.POINTER(ctypes.c_int), - ctypes.POINTER(ctypes.c_int), - np.ctypeslib.ndpointer(), - ctypes.POINTER(ctypes.c_int), - ctypes.POINTER(ctypes.c_int), - np.ctypeslib.ndpointer(), - np.ctypeslib.ndpointer() - ) - self.lib.surf_so.restype = ctypes.c_void_p - - def launch_so(self): - - n_template_file = len(self.input.template_file) - m_template_file = self.input.surf_tempalte_width_for_fortran - n_bulk_file = len(self.input.bulk_file) - m_bulk_file = self.input.bulk_out_width_for_fortran - - # NOTE: The "20480" is related to the following directive in surf_so.f90. - # character(c_char), intent(inout) :: surf_out(20480) - emp_str = ' '*20480 - self.output.surf_output = np.array([emp_str.encode()]) - self.lib.surf_so( - ctypes.byref(ctypes.c_int(n_template_file)), - ctypes.byref(ctypes.c_int(m_template_file)), - self.input.template_file, - ctypes.byref(ctypes.c_int(n_bulk_file)), - ctypes.byref(ctypes.c_int(m_bulk_file)), - self.input.bulk_file, - self.output.surf_output - ) - self.output.surf_output = self.output.surf_output[0].decode().splitlines() - - def run(self, nprocs: int = 1, nthreads: int = 1) -> None: - if self.isLogmode : time_sta = time.perf_counter() - - if self.run_scheme == "connect_so": - self.launch_so() - elif self.run_scheme == "subprocess": - self._run_by_subprocess([str(self.path_to_solver)]) - - if self.isLogmode: - time_end = time.perf_counter() - self.detail_timer["launch_STR"] += time_end - time_sta - - class Input(object): - root_dir: Path - output_dir: Path - dimension: int - string_list: List[str] - bulk_output_file: Path - surface_input_file: Path - surface_template_file: Path - - def __init__(self, info, d_timer): - self.mpicomm = mpi.comm() - self.mpisize = mpi.size() - self.mpirank = mpi.rank() - - if d_timer is None: - self.isLogmode = False - else: - self.isLogmode = True - self.detail_timer = d_timer - - self.root_dir = info.base["root_dir"] - self.output_dir = info.base["output_dir"] - - if "dimension" in info.solver: - self.dimension = info.solver["dimension"] - else: - self.dimension = info.base["dimension"] - - info_s = info.solver - self.run_scheme = info_s["run_scheme"] - self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) - - # NOTE: - # surf_tempalte_width_for_fortran: Number of strings per line of template.txt data for surf.so. - # bulk_out_width_for_fortran: Number of strings per line of bulkP.txt data for surf.so. - if self.run_scheme=="connect_so": - self.surf_tempalte_width_for_fortran = 128 - self.bulk_out_width_for_fortran = 1024 - - info_param = info_s.get("param", {}) - v = info_param.setdefault("string_list", ["value_01", "value_02"]) - if len(v) != self.dimension: - raise exception.InputError( - f"ERROR: len(string_list) != dimension ({len(v)} != {self.dimension})" - ) - self.string_list = v - - info_config = info_s.get("config", {}) - self.surface_input_file = Path( - info_config.get("surface_input_file", "surf.txt") - ) - - filename = info_config.get("surface_template_file", "template.txt") - filename = Path(filename).expanduser().resolve() - self.surface_template_file = self.root_dir / filename - if not self.surface_template_file.exists(): - raise exception.InputError( - f"ERROR: surface_template_file ({self.surface_template_file}) does not exist" - ) - - if self.mpirank == 0: - self._check_template() - temp_origin = self.load_surface_template_file(filename) - else: - temp_origin = None - self.template_file_origin = self.mpicomm.bcast(temp_origin,root=0) - - if self.run_scheme == "connect_so": - filename = info_config.get("bulk_output_file", "bulkP.txt") - filename = Path(filename).expanduser().resolve() - self.bulk_output_file = self.root_dir / filename - if not self.bulk_output_file.exists(): - raise exception.InputError( - f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" - ) - - if self.mpirank == 0: - bulk_f = self.load_bulk_output_file(filename) - else: - bulk_f = None - self.bulk_file = self.mpicomm.bcast(bulk_f,root=0) - - else: - filename = info_config.get("bulk_output_file", "bulkP.b") - filename = Path(filename).expanduser().resolve() - self.bulk_output_file = self.root_dir / filename - if not self.bulk_output_file.exists(): - raise exception.InputError( - f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" - ) - - def load_surface_template_file(self, filename): - template_file = [] - with open(self.surface_template_file) as f: - for line in f: - template_file.append(line) - return template_file - - def load_bulk_output_file(self, filename) : - bulk_file = [] - with open(self.bulk_output_file) as f: - for line in f: - line = line.replace("\t", " ").replace("\n", " ") - line = line.encode().ljust(self.bulk_out_width_for_fortran) - bulk_file.append(line) - bulk_f = np.array(bulk_file) - return bulk_f - - def prepare(self, message: py2dmat.Message): - if self.isLogmode : time_sta = time.perf_counter() - - x_list = message.x - step = message.step - iset = message.set - - dimension = self.dimension - string_list = self.string_list - bulk_output_file = self.bulk_output_file - solver_input_file = self.surface_input_file - fitted_x_list = [] - for index in range(dimension): - fitted_value = " " if x_list[index] >= 0 else "" - fitted_value += format(x_list[index], ".8f") - fitted_value = fitted_value[: len(string_list[index])] - fitted_x_list.append(fitted_value) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["make_surf_input"] += time_end - time_sta - - if self.isLogmode : time_sta = time.perf_counter() - - if self.generate_rocking_curve: - folder_name = self._pre_bulk(step, bulk_output_file, iset) - else: - if self.run_scheme == "connect_so": - folder_name = "." - - elif self.run_scheme == "subprocess": - #make workdir and copy bulk output file - folder_name = self._pre_bulk(step, bulk_output_file, iset) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["prepare_Log-directory"] += time_end - time_sta - - if self.isLogmode : time_sta = time.perf_counter() - - self._replace(fitted_x_list, folder_name) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["make_surf_input"] += time_end - time_sta - - return fitted_x_list, folder_name - - def _pre_bulk(self, Log_number, bulk_output_file, iset): - folder_name = "Log{:08d}_{:08d}".format(Log_number, iset) - os.makedirs(folder_name, exist_ok=True) - if self.run_scheme == "connect_so": - pass - else: #self.run_scheme == "subprocess": - shutil.copy( - bulk_output_file, os.path.join(folder_name, bulk_output_file.name) - ) - return folder_name - - def _replace(self, fitted_x_list, folder_name): - template_file = [] - if self.run_scheme == "subprocess": - file_output = open(os.path.join(folder_name, self.surface_input_file), "w") - for line in self.template_file_origin: - for index in range(self.dimension): - if line.find(self.string_list[index]) != -1: - line = line.replace( - self.string_list[index], - fitted_x_list[index] - ) - - if self.run_scheme == "connect_so": - line = line.replace("\t", " ").replace("\n", " ") - line = line.encode().ljust(self.surf_tempalte_width_for_fortran) - template_file.append(line) - - elif self.run_scheme == "subprocess": - file_output.write(line) - - - if self.run_scheme == "connect_so": - self.template_file = np.array(template_file) - elif self.run_scheme == "subprocess": - file_output.close() - - def _check_template(self) -> None: - found = [False] * self.dimension - with open(self.surface_template_file, "r") as file_input: - for line in file_input: - for index, placeholder in enumerate(self.string_list): - if line.find(placeholder) != -1: - found[index] = True - if not np.all(found): - msg = "ERROR: the following labels do not appear in the template file:" - for label, f in zip(self.string_list, found): - if not f: - msg += "\n" - msg += label - raise exception.InputError(msg) - - class Output(object): - """ - Output manager. - """ - - dimension: int - string_list: List[str] - surface_output_file: str - normalization: str - Rfactor_type: str - calculated_first_line: int - calculated_last_line: int - - I_reference: List[float] - I_reference_norm: float - I_reference_normalized: List[float] - - def __init__(self, info, d_timer): - self.mpicomm = mpi.comm() - self.mpisize = mpi.size() - self.mpirank = mpi.rank() - - if d_timer is None: - self.isLogmode = False - else: - self.isLogmode = True - self.detail_timer = d_timer - - if "dimension" in info.solver: - self.dimension = info.solver["dimension"] - else: - self.dimension = info.base["dimension"] - - info_s = info.solver - self.run_scheme = info_s["run_scheme"] - self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) - - # solver.post - info_post = info_s.get("post", {}) - v = info_post.get("normalization", "TOTAL") - available_normalization = ["TOTAL", "MULTI_SPOT"] - if v == "MAX": - raise exception.InputError('ERROR: normalization == "MAX" is not available') - if v not in available_normalization: - msg ="ERROR: normalization must be " - msg+="MULTI_SPOT or TOTAL" - raise exception.InputError(msg) - self.normalization = v - - v = info_post.get("weight_type", None) - available_weight_type = ["calc", "manual"] - if self.normalization == "MULTI_SPOT": - if v is None : - msg ='ERROR: If normalization = "MULTI_SPOT", ' - msg+='"weight_type" must be set in [solver.post].' - raise exception.InputError(msg) - elif v not in available_weight_type: - msg ="ERROR: weight_type must be " - msg+="calc or manual" - raise exception.InputError(msg) - else: - if v is not None : - if self.mpirank == 0: - msg ='NOTICE: If normalization = "MULTI_SPOT" is not set, ' - msg+='"weight_type" is NOT considered in the calculation.' - print(msg) - self.weight_type = None - self.weight_type = v - - v = info_post.get("spot_weight", []) - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - if v == [] : - msg ='ERROR: With normalization="MULTI_SPOT" and ' - msg+='weight_type=="manual", the "spot_weight" option ' - msg+='must be set in [solver.post].' - raise exception.InputError(msg) - self.spot_weight = np.array(v)/sum(v) - else: - if v != []: - if self.mpirank == 0: - msg ='NOTICE: With the specified "normalization" option, ' - msg+='the "spot_weight" you specify in the toml file is ignored, ' - msg+='since the spot_weight is automatically calculated within the program.' - print(msg) - if self.normalization== "TOTAL": - self.spot_weight = np.array([1]) - - v = info_post.get("Rfactor_type", "A") - if v not in ["A", "B", "A2"]: - raise exception.InputError("ERROR: Rfactor_type must be A, A2 or B") - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - if (v!="A") and (v!="A2") : - msg ='With normalization="MULTI_SPOT" and weight_type=="manual", ' - msg+='only Rfactor_type="A" or Rfactor_type="A2" is valid.' - raise exception.InputError(msg) - self.Rfactor_type = v - - v = info_post.get("omega", 0.5) - if v <= 0.0: - raise exception.InputError("ERROR: omega should be positive") - self.omega = v - - self.remove_work_dir = info_post.get("remove_work_dir", False) - - - # solver.param - info_param = info_s.get("param", {}) - v = info_param.setdefault("string_list", ["value_01", "value_02"]) - if len(v) != self.dimension: - raise exception.InputError( - f"ERROR: len(string_list) != dimension ({len(v)} != {self.dimension})" - ) - self.string_list = v - - # solver.reference - info_ref = info_s.get("reference", {}) - v = info_ref.setdefault("reference_first_line", 1) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: reference_first_line should be non-negative integer" - ) - firstline = v - - # None is dummy value - # If "reference_last_line" is not specified in the toml file, - # the last line of the reference file is used for the R-factor calculation. - v = info_ref.setdefault("reference_last_line", None) - if v is None: - reference_are_read_to_final_line = True - else: - reference_are_read_to_final_line = False - if not (isinstance(v, int) and v >= firstline): - raise exception.InputError( - "ERROR: reference_last_line < reference_first_line" - ) - lastline = v - - reference_path = info_ref.get("path", "experiment.txt") - data_experiment = self.read_experiment( - reference_path, firstline, lastline, - reference_are_read_to_final_line ) - self.angle_number_experiment = data_experiment.shape[0] - self.beam_number_exp_raw = data_experiment.shape[1] - - v = info_ref.get("exp_number", None) - - if v == None : - raise exception.InputError( - "ERROR: You have to set the 'exp_number'." - ) - - if not isinstance(v, list): - raise exception.InputError( - "ERROR: 'exp_number' must be a list type." - ) - - if max(v) > self.beam_number_exp_raw : - raise exception.InputError( - "ERROR: The 'exp_number' setting is wrong." - ) - - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - if len(v) != len(self.spot_weight): - raise exception.InputError( - "ERROR:len('exp_number') and len('spot_weight') do not match." - ) - - if self.normalization=="TOTAL" and len(v)!=1: - msg ='When normalization=="TOTAL" is specified, ' - msg+='only one beam data can be specified with ' - msg+='"exp_number" option.' - raise exception.InputError(msg) - - self.exp_number = v - - #Normalization of reference data - self.beam_number_experiment = len(self.exp_number) - for loop_index in range(self.beam_number_experiment): - exp_index = self.exp_number[loop_index] - I_reference = data_experiment[:,exp_index] - if self.normalization == "TOTAL": - I_reference_norm = np.sum(I_reference) - I_reference_normalized = I_reference/I_reference_norm - I_reference_norm_l = np.array([I_reference_norm]) - self.I_reference_normalized_l = np.array([I_reference_normalized]) - elif self.normalization=="MULTI_SPOT" and self.weight_type=="calc": - I_reference_norm = np.sum(I_reference) - I_reference_normalized = I_reference/I_reference_norm - if loop_index == 0: #first loop - I_reference_norm_l = np.array([I_reference_norm]) - self.I_reference_normalized_l = np.array([I_reference_normalized]) - else : # N-th loop - I_reference_norm_l = np.block( - [I_reference_norm_l, I_reference_norm] - ) - self.I_reference_normalized_l = np.block( - [[self.I_reference_normalized_l], - [I_reference_normalized]] - ) - elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - I_reference_norm = np.sum(I_reference) - I_reference_normalized = I_reference/I_reference_norm - if loop_index == 0: #first loop - I_reference_norm_l = np.array([I_reference_norm]) - self.I_reference_normalized_l = np.array([I_reference_normalized]) - else : # N-th loop - I_reference_norm_l = np.block( - [I_reference_norm_l, I_reference_norm] - ) - self.I_reference_normalized_l = np.block( - [[self.I_reference_normalized_l], - [I_reference_normalized]] - ) - else: - msg ="ERROR: normalization must be " - msg+="MULTI_SPOT or TOTAL" - raise exception.InputError(msg) - # solver.config - info_config = info_s.get("config", {}) - self.surface_output_file = info_config.get( - "surface_output_file", "surf-bulkP.s" - ) - - v = info_config.get("calculated_first_line", 5) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: calculated_first_line should be non-negative integer" - ) - self.calculated_first_line = v - - v = info_config.get( - "calculated_last_line", - self.calculated_first_line + self.angle_number_experiment-1 - ) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: calculated_last_line should be non-negative integer" - ) - self.calculated_last_line = v - - # Number of lines in the computation file - # used for R-factor calculations. - self.calculated_nlines = (self.calculated_last_line - - self.calculated_first_line + 1 ) - - if self.angle_number_experiment != self.calculated_nlines : - raise exception.InputError( - "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." - ) - - # Variable indicating whether the warning - # "self.calculated_nlines does not match - # the number of glancing angles in the calculated file" - # is displayed. - self.isWarning_calcnline = False - - v = info_config.get("calculated_info_line", 2) - if not (isinstance(v, int) and v >= 0): - raise exception.InputError( - "ERROR: calculated_info_line should be non-negative integer" - ) - self.calculated_info_line = v - - v = info_config.get("cal_number",None) - if v == None : - raise exception.InputError( - "ERROR: You have to set the 'cal_number'." - ) - - if not isinstance(v, list): - raise exception.InputError( - "ERROR: 'cal_number' must be a list type." - ) - - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - if len(self.spot_weight) != len(v): - raise exception.InputError( - "len('cal_number') and len('spot_weight') do not match." - ) - if self.normalization=="TOTAL" and len(v)!=1: - msg ='When normalization=="TOTAL" is specified, ' - msg+='only one beam data can be specified with ' - msg+='"cal_number" option.' - raise exception.InputError(msg) - self.cal_number = v - - def read_experiment(self, ref_path, first, last, read_to_final_line): - # Read experiment data - if self.mpirank == 0: - file_input = open(ref_path, "r") - Elines = file_input.readlines() - - firstline = first - if read_to_final_line : - lastline = len(Elines) - else: - lastline = last - - n_exp_row = lastline-firstline+1 - - # get value from data - for row_index in range(n_exp_row) : - line_index = firstline + row_index - 1 - line = Elines[line_index] - data = line.split() - # first loop - if row_index == 0: - n_exp_column = len(data) - data_e = np.zeros((n_exp_row, n_exp_column)) #init value - - for column_index in range(n_exp_column): - data_e[row_index, column_index] = float(data[column_index]) - else: - data_e = None - data_exp = self.mpicomm.bcast(data_e,root=0) - return data_exp - - def prepare(self, fitted_x_list): - self.fitted_x_list = fitted_x_list - - def get_results(self, work_dir) -> float: - """ - Get Rfactor obtained by the solver program. - Returns - ------- - """ - # Calculate Rfactor and Output numerical results - cwd = os.getcwd() - os.chdir(work_dir) - Rfactor = self._post(self.fitted_x_list) - os.chdir(cwd) - - #delete Log-directory - if self.isLogmode : time_sta = time.perf_counter() - - if self.run_scheme == "subprocess": - if self.remove_work_dir: - def rmtree_error_handler(function, path, excinfo): - print(f"WARNING: Failed to remove a working directory, {path}") - shutil.rmtree(work_dir, onerror=rmtree_error_handler) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["delete_Log-directory"] += time_end - time_sta - return Rfactor - - def _post(self, fitted_x_list): - I_experiment_normalized_l = self.I_reference_normalized_l - - ( - glancing_angle, - conv_number_of_g_angle, - conv_I_calculated_norm_l, - conv_I_calculated_normalized_l, - ) = self._calc_I_from_file() - - if self.isLogmode : time_sta = time.perf_counter() - Rfactor = self._calc_Rfactor( - conv_number_of_g_angle, - conv_I_calculated_normalized_l, - I_experiment_normalized_l, - ) - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["calculate_R-factor"] += time_end - time_sta - - #generate rocking curve - dimension = self.dimension - string_list = self.string_list - cal_number = self.cal_number - spot_weight = self.spot_weight - weight_type = self.weight_type - if self.generate_rocking_curve : - if self.isLogmode : time_sta = time.perf_counter() - with open("RockingCurve_calculated.txt", "w") as file_RC: - # Write headers - file_RC.write("#") - for index in range(dimension): - file_RC.write( - "{} = {} ".format(string_list[index], fitted_x_list[index]) - ) - file_RC.write("\n") - file_RC.write(f"#Rfactor_type = {self.Rfactor_type}") - file_RC.write("\n") - file_RC.write(f"#normalization = {self.normalization}") - file_RC.write("\n") - if weight_type is not None: - file_RC.write(f"#weight_type = {weight_type}\n") - file_RC.write("#R-factor = {}\n".format(Rfactor)) - file_RC.write("#cal_number = {}\n".format(cal_number)) - file_RC.write("#spot_weight = {}\n".format(spot_weight)) - file_RC.write("#NOTICE : Intensities are NOT multiplied by spot_weight.") - file_RC.write("\n") - file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.") - file_RC.write("\n") - file_RC.write("#sum( I_(spot) ) = 1") - file_RC.write("\n") - file_RC.write("#") - file_RC.write("\n") - - label_column = ["glancing_angle"] - fmt_rc = '%.5f' - for i in range(len(cal_number)): - label_column.append(f"cal_number={self.cal_number[i]}") - fmt_rc += " %.15e" - - for i in range(len(label_column)): - file_RC.write(f"# #{i} {label_column[i]}") - file_RC.write("\n") - g_angle_for_rc = np.array([glancing_angle]) - np.savetxt( - file_RC, - np.block( - [g_angle_for_rc.T, - conv_I_calculated_normalized_l.T] - ), - fmt=fmt_rc - ) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta - return Rfactor - - def _g(self, x): - g = (0.939437 / self.omega) * np.exp( - -2.77259 * (x ** 2.0 / self.omega ** 2.0) - ) - return g - - def _calc_I_from_file(self): - if self.isLogmode : time_sta = time.perf_counter() - - surface_output_file = self.surface_output_file - calculated_first_line = self.calculated_first_line - calculated_last_line = self.calculated_last_line - calculated_info_line = self.calculated_info_line - calculated_nlines = self.calculated_nlines - omega = self.omega - - cal_number = self.cal_number - - assert 0 < calculated_nlines - - if self.run_scheme == "connect_so": - Clines = self.surf_output - - elif self.run_scheme == "subprocess": - file_input = open(self.surface_output_file, "r") - Clines = file_input.readlines() - file_input.close() - - # Reads the number of glancing angles and beams - line = Clines[calculated_info_line-1] - line = line.replace(",", "") - data = line.split() - - calc_number_of_g_angles_org = int(data[1]) - calc_number_of_beams_org = int(data[2]) - - if calc_number_of_g_angles_org != calculated_nlines: - if self.mpirank == 0 and not self.isWarning_calcnline : - msg ="WARNING:\n" - msg+="The number of lines in the calculated file " - msg+="that you have set up does not match " - msg+="the number of glancing angles in the calculated file.\n" - msg+="The number of lines (nline) in the calculated file " - msg+="used for the R-factor calculation " - msg+="is determined by the following values\n" - msg+='nline = "calculated_last_line" - "calculated_first_line" + 1.' - print(msg) - self.isWarning_calcnline = True - calc_number_of_g_angles = calculated_nlines - - # Define the array for the rocking curve data. - # Note the components with (beam-index)=0 are the degree data - RC_data_org = np.zeros((calc_number_of_g_angles, calc_number_of_beams_org+1)) - for g_angle_index in range(calc_number_of_g_angles): - line_index = (calculated_first_line - 1) + g_angle_index - line = Clines[ line_index ] - # print("data line: ", line_index, g_angle_index, line) - line = line.replace(",", "") - data = line.split() - # print(data) - RC_data_org[g_angle_index,0]=float(data[0]) - for beam_index in range(calc_number_of_beams_org): - RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["load_STR_result"] += time_end - time_sta - - if self.isLogmode : time_sta = time.perf_counter() - verbose_mode = False - data_convolution = lib_make_convolution.calc( - RC_data_org, - calc_number_of_beams_org, - calc_number_of_g_angles, - omega, - verbose_mode, - ) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["convolution"] += time_end - time_sta - - if self.isLogmode : time_sta = time.perf_counter() - - angle_number_convolution = data_convolution.shape[0] - if self.angle_number_experiment !=angle_number_convolution: - raise exception.InputError( - "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." - ) - glancing_angle = data_convolution[:,0] - - beam_number_reference = len(cal_number) - for loop_index in range(beam_number_reference): - cal_index = cal_number[loop_index] - conv_I_calculated = data_convolution[:,cal_index] - if self.normalization == "TOTAL": - conv_I_calculated_norm = np.sum(conv_I_calculated) - conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm - conv_I_calculated_norm_l = np.array( - [conv_I_calculated_norm] - ) - conv_I_calculated_normalized_l = np.array( - [conv_I_calculated_normalized] - ) - elif self.normalization=="MULTI_SPOT" and self.weight_type=="calc": - conv_I_calculated_norm = np.sum(conv_I_calculated) - conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm - if loop_index == 0: #first loop - conv_I_calculated_norm_l = np.array( - [conv_I_calculated_norm] - ) - conv_I_calculated_normalized_l = np.array( - [conv_I_calculated_normalized] - ) - else: # N-th loop - conv_I_calculated_norm_l = np.block( - [conv_I_calculated_norm_l, - conv_I_calculated_norm] - ) - conv_I_calculated_normalized_l = np.block( - [[conv_I_calculated_normalized_l], - [conv_I_calculated_normalized]] - ) - if loop_index == beam_number_reference-1: #first loop - #conv_I_c_norm_l_power2 = conv_I_calculated_norm_l**2 - #self.spot_weight = conv_I_c_norm_l_power2 - #self.spot_weight = (conv_I_c_norm_l_power2 - # / sum(conv_I_calculated_norm_l)**2) - # / sum(conv_I_c_norm_l_power2) ) - self.spot_weight = ( conv_I_calculated_norm_l - / sum(conv_I_calculated_norm_l) )**2 - elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": - conv_I_calculated_norm = np.sum(conv_I_calculated) - conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm - if loop_index == 0: #first loop - conv_I_calculated_norm_l = np.array( - [conv_I_calculated_norm] - ) - conv_I_calculated_normalized_l = np.array( - [conv_I_calculated_normalized] - ) - else: # N-th loop - conv_I_calculated_norm_l = np.block( - [conv_I_calculated_norm_l, - conv_I_calculated_norm] - ) - conv_I_calculated_normalized_l = np.block( - [[conv_I_calculated_normalized_l], - [conv_I_calculated_normalized]] - ) - else: - msg ="ERROR: normalization must be " - msg+="MULTI_SPOT or TOTAL" - raise exception.InputError(msg) - - if self.isLogmode : - time_end = time.perf_counter() - self.detail_timer["normalize_calc_I"] += time_end - time_sta - - return ( - glancing_angle, - angle_number_convolution, - conv_I_calculated_norm_l, - conv_I_calculated_normalized_l - ) - - def _calc_Rfactor(self, n_g_angle, calc_result, exp_result): - spot_weight = self.spot_weight - n_spot = len(spot_weight) - if self.Rfactor_type == "A": - R = 0.0 - for spot_index in range(n_spot): - R_spot = 0.0 - for angle_index in range(n_g_angle): - R_spot += (exp_result[spot_index, angle_index] - - calc_result[spot_index, angle_index] )**2 - R_spot = spot_weight[spot_index] * R_spot - R += R_spot - R = np.sqrt(R) - elif self.Rfactor_type == "A2": - R = 0.0 - for spot_index in range(n_spot): - R_spot = 0.0 - for angle_index in range(n_g_angle): - R_spot += (exp_result[spot_index, angle_index] - - calc_result[spot_index, angle_index] )**2 - R_spot = spot_weight[spot_index] * R_spot - R += R_spot - else: # self.Rfactor_type == "B" - all_exp_result = [] - all_calc_result = [] - for spot_index in range(n_spot): - for angle_index in range(n_g_angle): - all_exp_result.append( - exp_result[spot_index, angle_index]) - all_calc_result.append( - calc_result[spot_index, angle_index]) - y1 = 0.0 - y2 = 0.0 - y3 = 0.0 - for I_exp, I_calc in zip(all_exp_result, all_calc_result): - y1 += (I_exp - I_calc) ** 2 - y2 += I_exp ** 2 - y3 += I_calc ** 2 - R = y1 / (y2 + y3) - return R From 4e7c96669fd879ef17e4e3446ff899d743d6a9ba Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 14 Oct 2023 19:35:59 +0900 Subject: [PATCH 32/67] Edited about self.Rfactor_type="B". -Edited error statement. --- src/py2dmat/solver/sim_trhepd_rheed.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index a9191227..f7cbd3f6 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -446,9 +446,9 @@ def __init__(self, info, d_timer): v = info_post.get("Rfactor_type", "A") if v not in ["A", "B", "A2"]: raise exception.InputError("ERROR: Rfactor_type must be A, A2 or B") - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + if self.normalization=="MULTI_SPOT": if (v!="A") and (v!="A2") : - msg ='With normalization="MULTI_SPOT" and weight_type=="manual", ' + msg ='With normalization="MULTI_SPOT", ' msg+='only Rfactor_type="A" or Rfactor_type="A2" is valid.' raise exception.InputError(msg) self.Rfactor_type = v From 771511e118f2a351e4b6d088d4859b002b7a8bb8 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 14 Oct 2023 19:53:55 +0900 Subject: [PATCH 33/67] Minor changes to RockingCurve_calculated.txt --- src/py2dmat/solver/sim_trhepd_rheed.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index f7cbd3f6..45252a30 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -728,6 +728,8 @@ def _post(self, fitted_x_list): cal_number = self.cal_number spot_weight = self.spot_weight weight_type = self.weight_type + Rfactor_type = self.Rfactor_type + normalization = self.normalization if self.generate_rocking_curve : if self.isLogmode : time_sta = time.perf_counter() with open("RockingCurve_calculated.txt", "w") as file_RC: @@ -738,23 +740,17 @@ def _post(self, fitted_x_list): "{} = {} ".format(string_list[index], fitted_x_list[index]) ) file_RC.write("\n") - file_RC.write(f"#Rfactor_type = {self.Rfactor_type}") - file_RC.write("\n") - file_RC.write(f"#normalization = {self.normalization}") - file_RC.write("\n") + file_RC.write("#Rfactor_type = {}\n".format(Rfactor_type)) + file_RC.write("#normalization = {}\n".format(normalization)) if weight_type is not None: - file_RC.write(f"#weight_type = {weight_type}\n") - file_RC.write("#R-factor = {}\n".format(Rfactor)) + file_RC.write("#weight_type = {}\n".format(weight_type)) + file_RC.write("#fx(x) = {}\n".format(Rfactor)) file_RC.write("#cal_number = {}\n".format(cal_number)) file_RC.write("#spot_weight = {}\n".format(spot_weight)) - file_RC.write("#NOTICE : Intensities are NOT multiplied by spot_weight.") - file_RC.write("\n") - file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.") - file_RC.write("\n") - file_RC.write("#sum( I_(spot) ) = 1") - file_RC.write("\n") - file_RC.write("#") - file_RC.write("\n") + file_RC.write("#NOTICE : Intensities are NOT multiplied by spot_weight.\n") + file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.\n") + file_RC.write("#sum( I_(spot) ) = 1\n") + file_RC.write("#\n") label_column = ["glancing_angle"] fmt_rc = '%.5f' From 85f47ad2ddaa316ed594cf19398c9b78f4e70ce2 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 14 Oct 2023 19:57:34 +0900 Subject: [PATCH 34/67] Delete unused function "_g" --- src/py2dmat/solver/sim_trhepd_rheed.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index 45252a30..b8b9f4e3 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -776,12 +776,6 @@ def _post(self, fitted_x_list): self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta return Rfactor - def _g(self, x): - g = (0.939437 / self.omega) * np.exp( - -2.77259 * (x ** 2.0 / self.omega ** 2.0) - ) - return g - def _calc_I_from_file(self): if self.isLogmode : time_sta = time.perf_counter() From f65713c9146fbfe5dd8076d82f59bb95040a1ec1 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 14 Oct 2023 20:01:06 +0900 Subject: [PATCH 35/67] Removed redundant comments. --- src/py2dmat/solver/sim_trhepd_rheed.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index b8b9f4e3..92e0fd42 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -826,10 +826,8 @@ def _calc_I_from_file(self): for g_angle_index in range(calc_number_of_g_angles): line_index = (calculated_first_line - 1) + g_angle_index line = Clines[ line_index ] - # print("data line: ", line_index, g_angle_index, line) line = line.replace(",", "") data = line.split() - # print(data) RC_data_org[g_angle_index,0]=float(data[0]) for beam_index in range(calc_number_of_beams_org): RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] @@ -894,11 +892,6 @@ def _calc_I_from_file(self): [conv_I_calculated_normalized]] ) if loop_index == beam_number_reference-1: #first loop - #conv_I_c_norm_l_power2 = conv_I_calculated_norm_l**2 - #self.spot_weight = conv_I_c_norm_l_power2 - #self.spot_weight = (conv_I_c_norm_l_power2 - # / sum(conv_I_calculated_norm_l)**2) - # / sum(conv_I_c_norm_l_power2) ) self.spot_weight = ( conv_I_calculated_norm_l / sum(conv_I_calculated_norm_l) )**2 elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": From b59a90306e158f4d624b14ba7b61eef80515f595 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 18 Oct 2023 01:27:34 +0900 Subject: [PATCH 36/67] Change of limitation on montecarlo - Changed the method of generating "initial_list" for execution with [runner.limitation] set. - Changed the constraint formula to include the judgment in the variable "in_range". --- src/py2dmat/algorithm/_algorithm.py | 30 +++++++++++++++++------------ src/py2dmat/algorithm/montecarlo.py | 18 +++++++++++++---- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/py2dmat/algorithm/_algorithm.py b/src/py2dmat/algorithm/_algorithm.py index 3467f772..ab2b95dd 100644 --- a/src/py2dmat/algorithm/_algorithm.py +++ b/src/py2dmat/algorithm/_algorithm.py @@ -170,22 +170,28 @@ def _read_param( if initial_list.ndim == 1: initial_list = initial_list.reshape(1, -1) if initial_list.size == 0: - # Repeat until an "initial_list" is generated - # that satisfies the constraint formula. + initial_list = min_list + (max_list - min_list) * self.rng.rand( + num_walkers, self.dimension + ) + # Repeat until an "initial_list" is generated + # that satisfies the constraint expression. + # If "co_a" and "co_b" are not set in [runner.limitation], + # all(isOK_judge) = true and do not repeat. loop_count = 0 + isOK_judge = np.full(num_walkers, False) while True: - judge_result = [] - initial_list = min_list + (max_list - min_list) * self.rng.rand( - num_walkers, self.dimension - ) - for walker_index in range(num_walkers): - judge = self.runner.limitation.judge( - initial_list[walker_index,:]) - judge_result.append(judge) - if all(judge_result): + for index in np.where(~isOK_judge)[0]: + isOK_judge[index] = self.runner.limitation.judge( + initial_list[index,:] + ) + if np.all(isOK_judge): break else: - loop_count += 1 + initial_list[~isOK_judge] = ( + min_list + (max_list - min_list) * self.rng.rand( + np.count_nonzero(~isOK_judge), self.dimension + ) ) + loop_count += 1 if initial_list.shape[0] != num_walkers: raise exception.InputError( f"ERROR: initial_list.shape[0] != num_walkers ({initial_list.shape[0]} != {num_walkers})" diff --git a/src/py2dmat/algorithm/montecarlo.py b/src/py2dmat/algorithm/montecarlo.py index 1e4cae1c..fd3cb3a2 100644 --- a/src/py2dmat/algorithm/montecarlo.py +++ b/src/py2dmat/algorithm/montecarlo.py @@ -302,7 +302,17 @@ def local_update( x_old = copy.copy(self.x) if self.iscontinuous: self.x = self.propose(x_old) - in_range = ((self.xmin <= self.x) & (self.x <= self.xmax)).all(axis=1) + #judgement of "in_range" + in_range_xmin = self.xmin <= self.x + in_range_xmax = self.x <= self.xmax + in_range_limitation = np.full(self.nwalkers, False) + for index_walker in range(self.nwalkers): + in_range_limitation[index_walker] = self.runner.limitation.judge( + self.x[index_walker] + ) + + in_range = (in_range_xmin & in_range_xmax).all(axis=1) \ + &in_range_limitation else: i_old = copy.copy(self.inode) self.inode = self.propose(self.inode) @@ -313,7 +323,7 @@ def local_update( fx_old = self.fx.copy() self._evaluate(in_range) self._write_result(file_trial, extra_info_to_write=extra_info_to_write) - + fdiff = self.fx - fx_old # Ignore an overflow warning in np.exp(x) for x >~ 710 @@ -322,9 +332,9 @@ def local_update( # old_setting = np.seterr(over="ignore") old_setting = np.seterr(all="ignore") probs = np.exp(-beta * fdiff) - # probs[np.isnan(probs)] = 0.0 + #probs[np.isnan(probs)] = 0.0 np.seterr(**old_setting) - + if not self.iscontinuous: probs *= self.ncandidates[i_old] / self.ncandidates[self.inode] tocheck = in_range & (probs < 1.0) From 1d268cf6742d33aae858a31fff91e73e471267aa Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 18 Oct 2023 02:51:25 +0900 Subject: [PATCH 37/67] Change of limitation on minsearch. - If the constraint formula is not satisfied, out_of_range = true. --- src/py2dmat/algorithm/min_search.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/py2dmat/algorithm/min_search.py b/src/py2dmat/algorithm/min_search.py index 5b6f2c07..46495472 100644 --- a/src/py2dmat/algorithm/min_search.py +++ b/src/py2dmat/algorithm/min_search.py @@ -91,6 +91,14 @@ def _f_calc(x_list: np.ndarray, extra_data: bool = False) -> float: ) ) out_of_range = True + + if not self.runner.limitation.judge(x_list): + msg ="Warning: " + msg+="Variables do not satisfy the constraint formula.\n" + for index in range(dimension): + msg+="{} = {}\n".format(label_list[index],x_list[index]) + print(msg,end="") + out_of_range = True for index in range(dimension): x_list[index] /= unit_list[index] From 96d27085cfa88574fa84124c239ae9c94c60c679 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Mon, 30 Oct 2023 20:07:11 +0900 Subject: [PATCH 38/67] Add limitation section --- doc/ja/source/input.rst | 95 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/doc/ja/source/input.rst b/doc/ja/source/input.rst index d8606232..8402c5ef 100644 --- a/doc/ja/source/input.rst +++ b/doc/ja/source/input.rst @@ -118,10 +118,11 @@ py2dmat は入力ファイルの形式に `TOML `_ を採 [``runner``] セクション ************************ ``Algorithm`` と ``Solver`` を橋渡しする要素である ``Runner`` の設定を記述します。 -サブセクションとして ``mapping`` と ``log`` を持ちます。 +サブセクションとして ``mapping`` 、 ``limitation`` 、 ``log`` を持ちます。 + [``mapping``] セクション -************************ +************************************************ ``Algorithm`` で探索している :math:`N` 次元のパラメータ :math:`x` から ``Solver`` で使う :math:`M` 次元のパラメータ :math:`y` への写像を定義します。 :math:`N \ne M` となる場合には、 ``solver`` セクションにも ``dimension`` パラメータを指定してください。 @@ -166,8 +167,96 @@ py2dmat は入力ファイルの形式に `TOML `_ を採 を表します。 +[``limitation``] セクション +************************************************ + +``Algorithm`` で探索している :math:`N` 次元のパラメータ :math:`x` に、制約条件を課すことが出来ます。 +``Algorithm`` ごとに定義する探索範囲(例:``exchange`` の ``min_list`` や ``max_list`` ) に加えて課すことが出来ます。 +現在は :math:`M` 行 :math:`N` 列の行列Aと :math:`M` 次元の縦ベクトルbから定義される :math:`Ax+b>0` の制約式が利用可能です。具体的に + +.. math:: + + A_{1,1} x_{1} + A_{1,2} x_{2} + &...& + A_{1,N} x_{N} + b_{1} > 0 \\ + A_{2,1} x_{1} + A_{2,2} x_{2} + &...& + A_{2,N} x_{N} + b_{2} > 0 \\ + &...& \\ + A_{M,1} x_{1} + A_{M,2} x_{2} + &...& + A_{M,N} x_{N} + b_{M} > 0 \\ + +という制約をかけることが出来ます。 +ここで :math:`M` は制約式の個数(任意)となります。 + +- ``co_a`` + + 形式: リストのリスト、あるいは文字列 (default: []) + + 説明: 制約式の行列 :math:`A` を設定します。 + + 行数は制約式数 :math:`M` 列数は探索変数の数 :math:`N` である必要があります。 + + ``co_b`` を同時に定義する必要があります。 + +- ``co_b`` + + 形式: リストのリスト、あるいは文字列 (default: []) + + 説明: 制約式の縦ベクトル :math:`b` を設定します。 + + 次元数が制約式数 :math:`M` の縦ベクトルを設定する必要があります。 + + ``co_a`` を同時に定義する必要があります。 + +行列の指定方法について、[``mapping``] セクションと同様で、例えば、 :: + + A = [[1,1], [0,1]] + +と :: + + A = """ + 1 1 + 0 1 + """ + +はともに + +.. math:: + + A = \left( + \begin{matrix} + 1 & 1 \\ + 0 & 1 + \end{matrix} + \right) + +を表します。また、 :: + + co_b = [[0], [-1]] + +と :: + + co_b = """0 -1""" + +と :: + + co_b = """ + 0 + -1 + """ + +はともに + +.. math:: + + b = \left( + \begin{matrix} + 0 \\ + -1 + \end{matrix} + \right) + +を表します。 +``co_a`` と ``co_b`` のどちらも定義しない場合、制約式を課さずに探索します。 + [``log``] セクション -************************ +************************************************ solver 呼び出しのlogging に関する設定です。 From a7019bbef70749f6e640686aeb5c3757ecad4324 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Mon, 30 Oct 2023 21:02:57 +0900 Subject: [PATCH 39/67] bug fix --- doc/ja/source/input.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/ja/source/input.rst b/doc/ja/source/input.rst index 8402c5ef..ea2bf59d 100644 --- a/doc/ja/source/input.rst +++ b/doc/ja/source/input.rst @@ -176,10 +176,10 @@ py2dmat は入力ファイルの形式に `TOML `_ を採 .. math:: - A_{1,1} x_{1} + A_{1,2} x_{2} + &...& + A_{1,N} x_{N} + b_{1} > 0 \\ - A_{2,1} x_{1} + A_{2,2} x_{2} + &...& + A_{2,N} x_{N} + b_{2} > 0 \\ - &...& \\ - A_{M,1} x_{1} + A_{M,2} x_{2} + &...& + A_{M,N} x_{N} + b_{M} > 0 \\ + A_{1,1} x_{1} + A_{1,2} x_{2} + &... + A_{1,N} x_{N} + b_{1} > 0\\ + A_{2,1} x_{1} + A_{2,2} x_{2} + &... + A_{2,N} x_{N} + b_{2} > 0\\ + &...\\ + A_{M,1} x_{1} + A_{M,2} x_{2} + &... + A_{M,N} x_{N} + b_{M} > 0 という制約をかけることが出来ます。 ここで :math:`M` は制約式の個数(任意)となります。 From 605f16bbeeb2fc720373fc733cc1459b8c20f5eb Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Tue, 31 Oct 2023 19:45:22 +0900 Subject: [PATCH 40/67] Added sample of limitaiton --- sample/analytical/limitation/best_result.txt | 7 + sample/analytical/limitation/do.sh | 3 + .../limitation/hist2d_limitation_sample.py | 210 ++++++++++++++++++ sample/analytical/limitation/input.toml | 27 +++ 4 files changed, 247 insertions(+) create mode 100644 sample/analytical/limitation/best_result.txt create mode 100644 sample/analytical/limitation/do.sh create mode 100644 sample/analytical/limitation/hist2d_limitation_sample.py create mode 100644 sample/analytical/limitation/input.toml diff --git a/sample/analytical/limitation/best_result.txt b/sample/analytical/limitation/best_result.txt new file mode 100644 index 00000000..63b22eae --- /dev/null +++ b/sample/analytical/limitation/best_result.txt @@ -0,0 +1,7 @@ +nprocs = 10 +rank = 2 +step = 4523 +walker = 0 +fx = 0.00010188398524402734 +x1 = 3.584944906595298 +x2 = -1.8506985826548874 diff --git a/sample/analytical/limitation/do.sh b/sample/analytical/limitation/do.sh new file mode 100644 index 00000000..ffbb81e6 --- /dev/null +++ b/sample/analytical/limitation/do.sh @@ -0,0 +1,3 @@ +mpiexec -np 10 --oversubscribe python3 ../../../src/py2dmat_main.py input.toml + +python3 hist2d_limitation_sample.py -p 10 -i input.toml -b 0.1 diff --git a/sample/analytical/limitation/hist2d_limitation_sample.py b/sample/analytical/limitation/hist2d_limitation_sample.py new file mode 100644 index 00000000..d847c792 --- /dev/null +++ b/sample/analytical/limitation/hist2d_limitation_sample.py @@ -0,0 +1,210 @@ +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.colors as clr +import toml as tm +import sys +import datetime +import os +import math as m +import collections as cl +import argparse +import decimal + +def read_toml(): + #input.tomlを取得 + dict_toml= tm.load(inputfile) + + #変数の範囲の最大値・最小値とTがlogスケールかを取得 + x1_min,x2_min= dict_toml['algorithm']['param']['min_list'] + x1_max,x2_max= dict_toml['algorithm']['param']['max_list'] + T_min= dict_toml['algorithm']['exchange']['Tmin'] + T_max= dict_toml['algorithm']['exchange']['Tmax'] + Tlog= True #dict_toml['algorithm']['exchange']['Tlogspace'] + #Tlogはブーリアン型 + + #結果を出力したディレクトリ名を取得 + output_dicname= dict_toml['base']['output_dir'] + + #探索回数を取得 + numsteps= int(dict_toml['algorithm']['exchange']['numsteps']) + numsteps_exchange= int(dict_toml['algorithm']['exchange']['numsteps_exchange']) + + name_for_simulate = '' + return x1_min, x2_min, x1_max, x2_max, T_max, T_min, Tlog, output_dicname, numsteps, numsteps_exchange, name_for_simulate + + +def read_result(): + + #各ディレクトリから得た値を格納する変数 + x1= [] + x2= [] + fx= [] + T= [] + step= range(1,numsteps+1,1) + + #各探索プロセッサにおけるfxの最大値・最小値を格納する変数 + fx_max_list= [] + fx_min_list= [] + + #以下よりファイルの読み込み + i= 0 + while i <= number_of_replica-1 : + print('{0}/{1} ファイル読み込み開始'.format(i+1,number_of_replica)) + #リストの中にi番目のディレクトリの値を格納するリストを作成 + x1.append([]) + x2.append([]) + fx.append([]) + T.append([]) + + #ファイルを開き、改行区切りのリストにする。 + f=open('{0}/{1}/result.txt'.format(output_dicname,i)) + frs= f.read().splitlines() + f.close() + + #繰り返し処理で値を抽出、float型へ変換 + #jが1からスタートなのはresult.txtの1行目には結果の値が入っていないため + j= 1 + while j< len(frs): + sp= frs[j].split() + x1[i].append(float(sp[-2])) + x2[i].append(float(sp[-1])) + fx[i].append(float(sp[-3])) + T[i].append(float(sp[-4])) + j+= 1 + + #i番目のresult.txtにおけるfxの最大値・最小値を格納 + fx_max_list.append(max(fx[i])) + fx_min_list.append(min(fx[i])) + i+= 1 + + print('読み込み完了') + + #読み込みができてるかの確認 + #print(x1[0][0:5],'\n\n',x1[1][0:5],'\n\n',x1[2][0:5],'\n\n',x1[3][0:5]) + return x1, x2, fx, T, step, max(fx_max_list), min(fx_min_list) + + +def sort_T(): + sorted_x1= [] + sorted_x2= [] + sorted_fx= [] + replica_num= [] + #original_x1= cp.deepcopy(x1) + #original_x2= cp.deepcopy(x2) + #original_fx= cp.deepcopy(fx) + + Tvalue= make_Tvalue_list() + + i= 0 + while i < len(Tvalue): + sorted_x1.append([]) + sorted_x2.append([]) + sorted_fx.append([]) + replica_num.append([]) + i+= 1 + + i = int(numsteps*burn_in) + while i < numsteps: + j= 0 + while j < number_of_replica: + k= 0 + while k < len(Tvalue): + if Tvalue[k] == T[j][i]: + sorted_x1[k].append(x1[j][i]) + sorted_x2[k].append(x2[j][i]) + sorted_fx[k].append(fx[j][i]) + replica_num[k].append(j) + k+= 1 + j+= 1 + i+= 1 + + sorted_T= True + return sorted_x1, sorted_x2, sorted_fx, replica_num, Tvalue, sorted_T + + +def make_Tvalue_list(): + Tvalue= [] + i= 0 + while i < number_of_replica : + Tvalue.extend(list(cl.Counter(T[i]).keys())) + i+= 1 + Tvalue= list(cl.Counter(Tvalue).keys()) + return Tvalue + +def soloplot(): + #繰り返し処理でプロット・図の保存 + print('グラフ描画開始') + min_l = [] + max_l = [] + + l= 0 + while l< number_of_replica: + fig = plt.figure(figsize= (8,8)) + ax = fig.add_subplot() + + num_of_sample = len(sorted_x1[l][:]) + weight_l = np.ones(num_of_sample)/num_of_sample + + hst2d = ax.hist2d( + sorted_x1[l][:], sorted_x2[l][:], + norm= clr.LogNorm(vmin=10**-4, vmax=10**-1), + range=[ [x1_min,x1_max] , [x2_min,x2_max] ], + cmap= 'Reds', weights=weight_l , bins=100) + + sum_allspace = np.sum(hst2d[0]) + max_in_one_space = hst2d[0].max() + min_in_one_space = hst2d[0][np.nonzero(hst2d[0])].min() + min_l.append(min_in_one_space) + max_l.append(max_in_one_space) + + cb = fig.colorbar(hst2d[3]) + + temp_for_title = decimal.Decimal(Tvalue[l]).quantize( + decimal.Decimal('0.001'), rounding=decimal.ROUND_HALF_UP + ) + figtitlestr = f'τ = {temp_for_title}' + + ax.set_title(figtitlestr) + + line_x1 = np.arange(x1_min,x1_max+1,1) + line_x2_1 = line_x1 + line_x2_2 = -line_x1 + 1 + ax.plot(line_x1,line_x2_1,c="black",alpha=0.3,lw=0.5) + ax.plot(line_x1,line_x2_2,c="black",alpha=0.3,lw=0.5) + #''' + ax.set_xlabel("x1") + ax.set_ylabel("x2") + ax.set_xlim(x1_min,x1_max) + ax.set_ylim(x2_min,x2_max) + ax.set_aspect('equal') + #軸サイズ設定と図の保存 + fig.savefig(f'{dirname}/{l}_T_{temp_for_title}_burn_in_{burn_in}.png',dpi=300) + l+= 1 + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-p','--mpiprocess',help='MPI process') + parser.add_argument('-i','--inputfile',help='input toml file') + parser.add_argument('-b','--burn_in',help='burn-in ratio') + args = parser.parse_args() + + number_of_replica = int(args.mpiprocess) + inputfile = args.inputfile + burn_in = float(args.burn_in) + + x1_min, x2_min, x1_max, x2_max, T_max, T_min, Tlog, output_dicname, numsteps, numsteps_exchange, name_for_simulate= read_toml() + + #result.txtから読み取り + x1, x2, fx, T, step, fx_max, fx_min = read_result() + + #グラフタイトル・ファイル名用に実行した時間の年日時間分を取得 + time= datetime.date.today().strftime("%Y%m%d") + + sorted_x1, sorted_x2, sorted_fx, replica_num, Tvalue, sorted_T= sort_T() + + dirname= '{0}_histogram'.format(time) + if os.path.exists(dirname) == False: + os.makedirs(dirname) + + soloplot() diff --git a/sample/analytical/limitation/input.toml b/sample/analytical/limitation/input.toml new file mode 100644 index 00000000..90d9e835 --- /dev/null +++ b/sample/analytical/limitation/input.toml @@ -0,0 +1,27 @@ +[base] +dimension = 2 +output_dir = "output" + +[algorithm] +name = "exchange" +seed = 12345 + +[algorithm.param] +max_list = [6.0, 6.0] +min_list = [-6.0, -6.0] +unit_list = [0.3, 0.3] + +[algorithm.exchange] +Tmin = 1.0 +Tmax = 100000.0 +numsteps = 10000 +numsteps_exchange = 100 + +[solver] +name = "analytical" +function_name = "himmelblau" + +[runner] +[runner.limitation] +co_a = [[1, -1],[1, 1]] +co_b = [[0, -1]] From 656c2e87b2f245ad97e9d8db6d5cf48e0d72be5d Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Tue, 31 Oct 2023 20:07:01 +0900 Subject: [PATCH 41/67] Rename best_result.txt -> ref.txt (in sample/analytical/limitation) --- sample/analytical/limitation/{best_result.txt => ref.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename sample/analytical/limitation/{best_result.txt => ref.txt} (100%) diff --git a/sample/analytical/limitation/best_result.txt b/sample/analytical/limitation/ref.txt similarity index 100% rename from sample/analytical/limitation/best_result.txt rename to sample/analytical/limitation/ref.txt From d8373e7e5968c3fa064f71af18aa1739fa7ff755 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Tue, 31 Oct 2023 20:09:05 +0900 Subject: [PATCH 42/67] fix input.toml --- sample/analytical/limitation/input.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample/analytical/limitation/input.toml b/sample/analytical/limitation/input.toml index 90d9e835..05e4163a 100644 --- a/sample/analytical/limitation/input.toml +++ b/sample/analytical/limitation/input.toml @@ -24,4 +24,4 @@ function_name = "himmelblau" [runner] [runner.limitation] co_a = [[1, -1],[1, 1]] -co_b = [[0, -1]] +co_b = [[0], [-1]] From 980e7a305b27ab1d9e3432b53d1b3de0f497feed Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 1 Nov 2023 17:38:11 +0900 Subject: [PATCH 43/67] Add file --- sample/analytical/limitation/do.sh | 12 +++++++++++- .../limitation/hist2d_limitation_sample.py | 8 ++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/sample/analytical/limitation/do.sh b/sample/analytical/limitation/do.sh index ffbb81e6..8de55d57 100644 --- a/sample/analytical/limitation/do.sh +++ b/sample/analytical/limitation/do.sh @@ -1,3 +1,13 @@ +#!/bin/bash mpiexec -np 10 --oversubscribe python3 ../../../src/py2dmat_main.py input.toml -python3 hist2d_limitation_sample.py -p 10 -i input.toml -b 0.1 +echo diff output/best_result.txt ref.txt +res=0 +diff output/best_result.txt ref.txt || res=$? +if [ $res -eq 0 ]; then + echo TEST PASS + true +else + echo TEST FAILED: best_result.txt and ref.txt differ + false +fi diff --git a/sample/analytical/limitation/hist2d_limitation_sample.py b/sample/analytical/limitation/hist2d_limitation_sample.py index d847c792..0183c8a1 100644 --- a/sample/analytical/limitation/hist2d_limitation_sample.py +++ b/sample/analytical/limitation/hist2d_limitation_sample.py @@ -159,10 +159,10 @@ def soloplot(): cb = fig.colorbar(hst2d[3]) - temp_for_title = decimal.Decimal(Tvalue[l]).quantize( - decimal.Decimal('0.001'), rounding=decimal.ROUND_HALF_UP + temp_for_title = decimal.Decimal(1/Tvalue[l]).quantize( + decimal.Decimal('0.00001'), rounding=decimal.ROUND_HALF_UP ) - figtitlestr = f'τ = {temp_for_title}' + figtitlestr = f'beta = {temp_for_title}' ax.set_title(figtitlestr) @@ -178,7 +178,7 @@ def soloplot(): ax.set_ylim(x2_min,x2_max) ax.set_aspect('equal') #軸サイズ設定と図の保存 - fig.savefig(f'{dirname}/{l}_T_{temp_for_title}_burn_in_{burn_in}.png',dpi=300) + fig.savefig(f'{dirname}/{l}_beta_{temp_for_title}_burn_in_{burn_in}.png',dpi=300) l+= 1 From 9982dd0fee67e907fb6fadefd47ccf3c5e13c50a Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Wed, 1 Nov 2023 17:41:41 +0900 Subject: [PATCH 44/67] Add tutorial of limitation --- doc/common/img/limitation_beta_max.pdf | Bin 0 -> 28121 bytes doc/common/img/limitation_beta_max.png | Bin 0 -> 27412 bytes doc/common/img/limitation_beta_min.pdf | Bin 0 -> 68638 bytes doc/common/img/limitation_beta_min.png | Bin 0 -> 67183 bytes doc/ja/source/tutorial/index.rst | 2 + doc/ja/source/tutorial/limitation.rst | 192 +++++++++++++++++++++++++ 6 files changed, 194 insertions(+) create mode 100644 doc/common/img/limitation_beta_max.pdf create mode 100644 doc/common/img/limitation_beta_max.png create mode 100644 doc/common/img/limitation_beta_min.pdf create mode 100644 doc/common/img/limitation_beta_min.png create mode 100644 doc/ja/source/tutorial/limitation.rst diff --git a/doc/common/img/limitation_beta_max.pdf b/doc/common/img/limitation_beta_max.pdf new file mode 100644 index 0000000000000000000000000000000000000000..49e43d3e974e592cc8efc46d86fc0324fc2bbf9a GIT binary patch literal 28121 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�G(L>l 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 %Q{GqfW8m+h7 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 z
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⪅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 z
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 V@bEgJ1sF|SjFN}v!4nnA{|EgkCk_Ar literal 0 HcmV?d00001 diff --git a/doc/common/img/limitation_beta_min.png b/doc/common/img/limitation_beta_min.png new file mode 100644 index 0000000000000000000000000000000000000000..7360c7983fbe9f9a92b3e3ab979a9fa2daf5ecb4 GIT binary patch literal 67183 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 literal 0 HcmV?d00001 diff --git a/doc/ja/source/tutorial/index.rst b/doc/ja/source/tutorial/index.rst index 133470a5..8b3ebded 100644 --- a/doc/ja/source/tutorial/index.rst +++ b/doc/ja/source/tutorial/index.rst @@ -38,6 +38,7 @@ TRHEPDでは原子座標を与えた場合に、回折データがシミュレ の5つのアルゴリズムが用意されています。 本チュートリアルでは、最初に順問題プログラム ``sim_trhepd_rheed`` の実行方法、 その後に ``minsearch`` , ``mapper_mpi``, ``bayes``, ``exchange``, ``pamc`` の実行方法について順に説明します。 +また、制約式を用いて探索範囲を制限出来る ``[runner.limitation]`` セクションを使用した実行方法も説明しています。 最後に、自分で順問題ソルバーを定義する簡単な例について説明します。 .. toctree:: @@ -48,6 +49,7 @@ TRHEPDでは原子座標を与えた場合に、回折データがシミュレ mpi bayes exchange + limitation pamc solver_simple diff --git a/doc/ja/source/tutorial/limitation.rst b/doc/ja/source/tutorial/limitation.rst new file mode 100644 index 00000000..dd53f3be --- /dev/null +++ b/doc/ja/source/tutorial/limitation.rst @@ -0,0 +1,192 @@ +制約式を適用したレプリカ交換モンテカルロ法による探索 +========================================================================== + +ここでは、 ``[runner.limitation]`` セクションに設定できる制約式機能のチュートリアルを示します。 +例として、レプリカ交換モンテカルロ法を、Himmelblauを対象に探索する計算に制約式を適用します。 + +サンプルファイルの場所 +~~~~~~~~~~~~~~~~~~~~~~~~ + +サンプルファイルは ``sample/analytical/limitation`` にあります。 +フォルダには以下のファイルが格納されています。 + +- ``ref.txt`` + + 計算が正しく実行されたか確認するためのファイル(本チュートリアルを行うことで得られる ``best_result.txt`` の回答)。 + +- ``input.toml`` + + メインプログラムの入力ファイル。 + +- ``do.sh`` + + 本チュートリアルを一括計算するために準備されたスクリプト + +以下、これらのファイルについて説明したあと、実際の計算結果を紹介します。 + +入力ファイルの説明 +~~~~~~~~~~~~~~~~~~~ + +メインプログラム用の入力ファイル ``input.toml`` について説明します。 +``input.toml`` の詳細については入力ファイルに記載されています。 +以下は、サンプルファイルにある ``input.toml`` の中身になります。 + +.. code-block:: + + [base] + dimension = 2 + output_dir = "output" + + [algorithm] + name = "exchange" + seed = 12345 + + [algorithm.param] + max_list = [6.0, 6.0] + min_list = [-6.0, -6.0] + unit_list = [0.3, 0.3] + + [algorithm.exchange] + Tmin = 1.0 + Tmax = 100000.0 + numsteps = 10000 + numsteps_exchange = 100 + + [solver] + name = "analytical" + function_name = "himmelblau" + + [runner] + [runner.limitation] + co_a = [[1, -1],[1, 1]] + co_b = [[0], [-1]] + +ここではこの入力ファイルを簡単に説明します。 +詳細は入力ファイルのレファレンスを参照してください。 + +``[base]`` セクションはメインプログラム全体のパラメータです。 +``dimension`` は最適化したい変数の個数で、今の場合は2つの変数の最適化を行うので、``2`` を指定します。 + +``[algorithm]`` セクションは用いる探索アルゴリズムを設定します。 +交換モンテカルロ法を用いる場合には、 ``name`` に ``"exchange"`` を指定します。 +``label_list`` は、``value_0x`` (x=1,2) を出力する際につけるラベル名のリストです。 +``seed`` は擬似乱数生成器に与える種です。 + +``[algorithm.param]`` サブセクションは、最適化したいパラメータの範囲などを指定します。 +``min_list`` は最小値、 ``max_list`` は最大値を示します。 + +``[algorithm.exchange]`` サブセクションは、交換モンテカルロ法のハイパーパラメータを指定します。 + +- ``numstep`` はモンテカルロ更新の回数です。 +- ``numsteps_exchange`` で指定した回数のモンテカルロ更新の後に、温度交換を試みます。 +- ``Tmin``, ``Tmax`` はそれぞれ温度の下限・上限です。 +- ``Tlogspace`` が ``true`` の場合、温度を対数空間で等分割します。このオプションはデフォルト値が ``true`` であるため、今回の ``input.toml`` に指定は無いですが、 ``true`` になっています。 + +``[solver]`` セクションではメインプログラムの内部で使用するソルバーを指定します。 +今回は ``analytical`` ソルバーを指定しています。 ``analytical`` ソルバーは ``function_name`` パラメータを用いて関数を設定します。 +今回はHimmelblau 関数を指定しています。 +``analytical`` ソルバーに関してはチュートリアル「順問題ソルバーの追加」を参照してください。 + +``[runner]`` セクションは ``[runner.limitation]`` サブセクションを持ち、この中に制約式を設定します。 +現在、制約式は :math:`N` 次元のパラメータ :math:`x` 、 :math:`M` 行 :math:`N` 列の行列 :math:`A` 、 +:math:`M` 次元の縦ベクトル :math:`b` から定義される :math:`Ax+b>0` の制約式が利用可能です。 +パラメータとしては、以下の項目が設定可能です。 + +- ``co_a`` は行列 :math:`A` を設定します。 +- ``co_b`` は縦ベクトル :math:`b` を設定します。 + +パラメータの詳しい設定方法はマニュアル内「入力ファイル」項の「 [``limitation``] セクション」を参照してください。 +今回は + +.. math:: + + x_{1} − x_{2} > 0\\ + x_{1} + x_{2} − 1 > 0 + +の制約式を課して実行しています。 + +計算実行 +~~~~~~~~~~~~ + +最初にサンプルファイルが置いてあるフォルダへ移動します(以下、本ソフトウェアをダウンロードしたディレクトリ直下にいることを仮定します). + +.. code-block:: + + cd sample/analytical/limitation + +そのあとに、メインプログラムを実行します(計算時間は通常のPCで20秒程度で終わります)。 + +.. code-block:: + + mpiexec -np 10 python3 ../../../src/py2dmat_main.py input.toml | tee log.txt + +ここではプロセス数10のMPI並列を用いた計算を行っています。 +(Open MPI を用いる場合で、使えるコア数よりも要求プロセス数の方が多い時には、 +``mpiexec`` コマンドに ``--oversubscribed`` オプションを追加してください。) +実行すると、 ``output`` フォルダが生成され、その中に各ランクのフォルダが作成されます。 +更にその中には、各モンテカルロステップで評価したパラメータおよび目的関数の値を記した ``trial.txt`` ファイルと、 +実際に採択されたパラメータを記した ``result.txt`` ファイルが作成されます。 +ともに書式は同じで、最初の2列がステップ数とプロセス内のwalker 番号、次が温度、3列目が目的関数の値、4列目以降がパラメータです。 +以下は、 ``output/0/result.txt`` ファイルの冒頭部分です。 + +.. code-block:: + + # step walker T fx x1 x2 + 0 0 1.0 187.94429125133564 5.155393113805774 -2.203493345018569 + 1 0 1.0 148.23606736778044 4.9995614992887525 -2.370212436322816 + 2 0 1.0 148.23606736778044 4.9995614992887525 -2.370212436322816 + 3 0 1.0 148.23606736778044 4.9995614992887525 -2.370212436322816 + +最後に、 ``output/best_result.txt`` に、目的関数が最小となったパラメータとそれを得たランク、モンテカルロステップの情報が書き込まれます。 + +.. code-block:: + + nprocs = 10 + rank = 2 + step = 4523 + walker = 0 + fx = 0.00010188398524402734 + x1 = 3.584944906595298 + x2 = -1.8506985826548874 + +なお、一括計算するスクリプトとして ``do.sh`` を用意しています。 +``do.sh`` では ``best_result.txt`` と ``ref.txt`` の差分も比較しています。 +以下、説明は割愛しますが、その中身を掲載します。 + +.. code-block:: + + #!/bin/bash + mpiexec -np 10 --oversubscribe python3 ../../../src/py2dmat_main.py input.toml + + echo diff output/best_result.txt ref.txt + res=0 + diff output/best_result.txt ref.txt || res=$? + if [ $res -eq 0 ]; then + echo TEST PASS + true + else + echo TEST FAILED: best_result.txt and ref.txt differ + false + fi + +計算結果の可視化 +~~~~~~~~~~~~~~~~~~~ + +``result.txt`` を図示して、制約式を満たした座標のみを探索しているかを確認します。 +今回の場合は、以下のコマンドを打つことで2次元パラメータ空間の図が ``<実行日>_histogram`` フォルダ内に作成されます。 +生成されるヒストグラムは、burn-in期間として最初の1000ステップ分の探索を捨てたデータを使用しています。 + +.. code-block:: + + python3 hist2d_limitation_sample.py -p 10 -i input.toml -b 0.1 + +作成された図には2本の直線 :math:`x_{1} − x_{2} = 0, x_{1} + x_{2} − 1 = 0` と +探索結果(事後確率分布のヒストグラム)を図示しています。 +図を見ると :math:`x_{1} − x_{2} > 0, x_{1} + x_{2} − 1 > 0` の範囲のみ探索をしていることが確認できます。 +以下に図の一部を掲載します。 + +.. figure:: ../../../common/img/limitation_beta_min.* + +.. figure:: ../../../common/img/limitation_beta_max.* + + サンプルされたパラメータと確率分布。横軸は ``value_01 (x1)`` , 縦軸は ``value_02 (x2)`` を表す。 From 0afb0e658bb5e9525177b1919cc39e4aecafef8c Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Fri, 3 Nov 2023 20:04:35 +0900 Subject: [PATCH 45/67] normalization = "MULTI_SPOT" -> normalization = "MANY_BEAM" --- src/py2dmat/solver/sim_trhepd_rheed.py | 36 +++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index 92e0fd42..cd645eaf 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -395,21 +395,21 @@ def __init__(self, info, d_timer): # solver.post info_post = info_s.get("post", {}) - v = info_post.get("normalization", "TOTAL") - available_normalization = ["TOTAL", "MULTI_SPOT"] + v = info_post.get("normalization", "") + available_normalization = ["TOTAL", "MANY_BEAM"] if v == "MAX": raise exception.InputError('ERROR: normalization == "MAX" is not available') if v not in available_normalization: msg ="ERROR: normalization must be " - msg+="MULTI_SPOT or TOTAL" + msg+="MANY_BEAM or TOTAL" raise exception.InputError(msg) self.normalization = v v = info_post.get("weight_type", None) available_weight_type = ["calc", "manual"] - if self.normalization == "MULTI_SPOT": + if self.normalization == "MANY_BEAM": if v is None : - msg ='ERROR: If normalization = "MULTI_SPOT", ' + msg ='ERROR: If normalization = "MANY_BEAM", ' msg+='"weight_type" must be set in [solver.post].' raise exception.InputError(msg) elif v not in available_weight_type: @@ -419,16 +419,16 @@ def __init__(self, info, d_timer): else: if v is not None : if self.mpirank == 0: - msg ='NOTICE: If normalization = "MULTI_SPOT" is not set, ' + msg ='NOTICE: If normalization = "MANY_BEAM" is not set, ' msg+='"weight_type" is NOT considered in the calculation.' print(msg) self.weight_type = None self.weight_type = v v = info_post.get("spot_weight", []) - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + if self.normalization=="MANY_BEAM" and self.weight_type=="manual": if v == [] : - msg ='ERROR: With normalization="MULTI_SPOT" and ' + msg ='ERROR: With normalization="MANY_BEAM" and ' msg+='weight_type=="manual", the "spot_weight" option ' msg+='must be set in [solver.post].' raise exception.InputError(msg) @@ -446,9 +446,9 @@ def __init__(self, info, d_timer): v = info_post.get("Rfactor_type", "A") if v not in ["A", "B", "A2"]: raise exception.InputError("ERROR: Rfactor_type must be A, A2 or B") - if self.normalization=="MULTI_SPOT": + if self.normalization=="MANY_BEAM": if (v!="A") and (v!="A2") : - msg ='With normalization="MULTI_SPOT", ' + msg ='With normalization="MANY_BEAM", ' msg+='only Rfactor_type="A" or Rfactor_type="A2" is valid.' raise exception.InputError(msg) self.Rfactor_type = v @@ -517,7 +517,7 @@ def __init__(self, info, d_timer): "ERROR: The 'exp_number' setting is wrong." ) - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + if self.normalization=="MANY_BEAM" and self.weight_type=="manual": if len(v) != len(self.spot_weight): raise exception.InputError( "ERROR:len('exp_number') and len('spot_weight') do not match." @@ -541,7 +541,7 @@ def __init__(self, info, d_timer): I_reference_normalized = I_reference/I_reference_norm I_reference_norm_l = np.array([I_reference_norm]) self.I_reference_normalized_l = np.array([I_reference_normalized]) - elif self.normalization=="MULTI_SPOT" and self.weight_type=="calc": + elif self.normalization=="MANY_BEAM" and self.weight_type=="calc": I_reference_norm = np.sum(I_reference) I_reference_normalized = I_reference/I_reference_norm if loop_index == 0: #first loop @@ -555,7 +555,7 @@ def __init__(self, info, d_timer): [[self.I_reference_normalized_l], [I_reference_normalized]] ) - elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + elif self.normalization=="MANY_BEAM" and self.weight_type=="manual": I_reference_norm = np.sum(I_reference) I_reference_normalized = I_reference/I_reference_norm if loop_index == 0: #first loop @@ -571,7 +571,7 @@ def __init__(self, info, d_timer): ) else: msg ="ERROR: normalization must be " - msg+="MULTI_SPOT or TOTAL" + msg+="MANY_BEAM or TOTAL" raise exception.InputError(msg) # solver.config info_config = info_s.get("config", {}) @@ -630,7 +630,7 @@ def __init__(self, info, d_timer): "ERROR: 'cal_number' must be a list type." ) - if self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + if self.normalization=="MANY_BEAM" and self.weight_type=="manual": if len(self.spot_weight) != len(v): raise exception.InputError( "len('cal_number') and len('spot_weight') do not match." @@ -872,7 +872,7 @@ def _calc_I_from_file(self): conv_I_calculated_normalized_l = np.array( [conv_I_calculated_normalized] ) - elif self.normalization=="MULTI_SPOT" and self.weight_type=="calc": + elif self.normalization=="MANY_BEAM" and self.weight_type=="calc": conv_I_calculated_norm = np.sum(conv_I_calculated) conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm if loop_index == 0: #first loop @@ -894,7 +894,7 @@ def _calc_I_from_file(self): if loop_index == beam_number_reference-1: #first loop self.spot_weight = ( conv_I_calculated_norm_l / sum(conv_I_calculated_norm_l) )**2 - elif self.normalization=="MULTI_SPOT" and self.weight_type=="manual": + elif self.normalization=="MANY_BEAM" and self.weight_type=="manual": conv_I_calculated_norm = np.sum(conv_I_calculated) conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm if loop_index == 0: #first loop @@ -915,7 +915,7 @@ def _calc_I_from_file(self): ) else: msg ="ERROR: normalization must be " - msg+="MULTI_SPOT or TOTAL" + msg+="MANY_BEAM or TOTAL" raise exception.InputError(msg) if self.isLogmode : From e0923209c541e687be1e96aa59a95497415eaafa Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 11 Nov 2023 18:32:34 +0900 Subject: [PATCH 46/67] update document --- doc/ja/source/solver/sim-trhepd-rheed.rst | 194 ++++++++++++++-------- 1 file changed, 128 insertions(+), 66 deletions(-) diff --git a/doc/ja/source/solver/sim-trhepd-rheed.rst b/doc/ja/source/solver/sim-trhepd-rheed.rst index bdd609f5..ea2ded00 100644 --- a/doc/ja/source/solver/sim-trhepd-rheed.rst +++ b/doc/ja/source/solver/sim-trhepd-rheed.rst @@ -25,17 +25,11 @@ [``solver``] セクション ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- ``run_scheme`` - - 形式: string型。"subprocess"または"connect_so"のいずれかをとります。 - - 説明: ソルバーとして使用するファイルを指定します。前者は ``surf.exe`` 、後者は ``surf.so`` を使用したいときに指定します。 - - ``generate_rocking_curve`` 形式: 真偽値 (default: false) - 説明: ``RockingCurve.txt`` の生成をするかどうか + 説明: ``RockingCurve_calculated.txt`` の生成をするかどうか。 ``RockingCurve_calculated.txt`` は作業ディレクトリ ``Log%%%_###`` の中に保存されます。このオプションが"true"であっても、 ``remove_work_dir`` ([``post``] セクション)が"true"であれば ``Log%%%_###`` は削除されてしまうため、注意してください。 [``config``] セクション(サブセクション) @@ -65,30 +59,71 @@ 説明: 表面構造のアウトプットファイル。 +- ``calculated_first_line`` + + 形式: 整数型 (default: 5) + + 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む最初の行を指定。 + +- ``calculated_last_line`` + + 形式: 整数型 (default: 5 + [``reference``] セクション(サブセクション)にて指定した実験データファイルの視写角数 - 1) + + 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む最後の行を指定。 + +- ``calculated_info_line`` + + 形式: 整数型 (default: 2) + + 説明: ソルバーにより計算された出力ファイルの行を指定するパラメータ。出力ファイル内に記されているglancing angle数やbeam数が記してある行を指定。 + - ``cal_number`` - 形式: 整数型のリスト。 + 形式: 整数型のリスト (default: None、設定必須) - 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む列を指定。複数指定が可能。 + 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む列(ビーム)を指定。複数指定が可能。設定した値は、後述の ``exp_number`` ([``reference``] セクション)の値とリストの長さを一致させる必要があります。 [``post``] セクション(サブセクション) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``normalization`` - 形式: string型。"TOTAL"または"MAX"のいずれかをとります。 (default: "TOTAL") + 形式: string型。"TOTAL"または"MANY_BEAM"のいずれかをとります。 (default: ""、設定必須) - 説明: 実験・計算のデータベクトルの規格化の方法。全体の和で規格化するか最大値で規格化するかを指定します。 + 説明: 実験・計算のデータベクトルの規格化の方法。"TOTAL"の場合、全体の和で規格化をします。ただしビームの本数が1つのみ適用できる規格化方法なので、 ``cal_number`` ([``config``] セクション)および ``exp_number`` ([``reference``] セクション)で設定したリストの長さが1である必要が有ります。"MANY_BEAM"はビームの本数が複数であるときに利用できる規格化方法です。後述の ``weight_type`` によって規格化方法が変わります。 -- ``Rfactor_type`` + **なお、 normalization="MAX" は廃止となりました。** + +- ``weight_type`` + + 形式: string型または ``None`` 。"calc"または"manual"のいずれかを設定する必要があります。 (default: ``None`` 、 ``normalization = "MANY_BEAM"`` としたとき設定必須) - 形式: string型。"A"または"B"のいずれかをとります。 (default: "A") + 説明: 目的関数値を計算するときの、ビームごとの重みの計算方法を指定します。 :math:`n` をビームのindex( :math:`n = 1,2,3..` ) 、 :math:`m` を視射角のindexとして、計算データを :math:`v^{(n)} = (v^{(n)}_{1}, v^{(n)}_{2}, .. ,v^{(n)}_{m})` と表すとします。 + "calc"とした場合、各ビームごとの重み :math:`w^{(n)}` は次の式で与えられます。 :math:`w^{(n)} = ( \sum_i^m v^{(n)}_{i} / \sum_j^n \sum_i^m v^{(j)}_i )^{2}.` + "manual"とした場合、オプション ``spot_weight`` を用いることで、ユーザーが重みを指定可能です。 - 説明: Rファクターの計算方法の指定。 - 実験・計算のデータベクトルを、それぞれ、:math:`u = (u_{1}, u_{2},...,u_{m})`, - :math:`v = (v_{1}, v_{2},...,v_{m})` と書いたとき、 - "A"タイプを指定すると、Rファクター値は :math:`R = (\sum_i^m (u_{i}-v_{i})^{2})^{1/2}` で計算され、 - "B"タイプを指定すると、Rファクター値は :math:`R = (\sum_i^m (u_{i}-v_{i})^{2})^{1/2}/( \sum_i^m u_{i}^2 + \sum_i^m v_{i}^2)` で計算されます。 +- ``spot_weight`` + + 形式: float型のリスト。 (default: [] 、 ``weight_type = "manual"`` としたとき設定必須) + + 説明: オプション ``weight_type`` を"manual"と設定した際に設定できます。 + それ以外の指定では、このオプションは計算に反映されません。目的関数値を計算するときの、ビームごとの重みを設定します。また、このオプションで指定された重みは総和が1になります。 + 例えば、[3,2,1]を指定すると、 :math:`w^{(1)}=1/2, w^{(2)}=1/3, w^{(3)}=1/6` となります。 + +- ``Rfactor_type`` + + 形式: string型。"A"、"A2"または"B"のいずれかをとります。 (default: "A") + + 説明: 目的関数値の計算方法の指定。 + 実験・計算のデータベクトルを、それぞれ :math:`u^{(n)} = (u^{(n)}_{1}, u^{(n)}_{2},...,u^{(n)}_{m})`, :math:`v^{(n)} = (v^{(n)}_{1}, v^{(n)}_{2},...,v^{(n)}_{m})` と書くとします。 + また、各ビームごとの重みを :math:`w^{(n)}` とします。:math:`n` はビームのindexです( :math:`n = 1,2,3..` )。 + "A"タイプを指定すると、目的関数値は :math:`R = [ \sum_{j}^{n} w^{(j)} \{ \sum_{i}^{m} (u^{(j)}_{i}-v^{(j)}_{i})^{2} \} ]^{1/2}` + で計算されるRファクター値となります。 + "A2"タイプを指定すると、目的関数値は :math:`R^{2} = \sum_{j}^{n} w^{(j)} \{ \sum_{i}^{m} (u^{(j)}_{i}-v^{(j)}_{i})^{2} \}` + で計算されるRファクターの二乗の値となります。 + "B"タイプを指定すると、目的関数値は :math:`R = (\sum_{i}^{m} (u^{(1)}_{i}-v^{(1)}_{i})^{2})^{1/2}/( \sum_{i}^{m} (u^{(1)}_{i})^{2} + \sum_{i}^{m} (v^{(1)}_{i})^2)` + で計算されるRファクター値となります。 + "B"タイプはビームが1つの実験・計算データを用いた実行( :math:`n=1` )のみ対応しています。 - ``omega`` @@ -100,7 +135,7 @@ 形式: 真偽値 (default: false) - 説明: R-factor を読み取った後に作業ディレクトリ ``Log%%%_###`` を削除するかどうか + 説明: R-factor を読み取った後に作業ディレクトリ ``Log%%%_###`` を削除するかどうか。なお、 ``generate_rocking_curve`` ([``solver``] セクション) が"true"であっても、本オプションが"true"ならば ``Log%%%_###`` を削除します。 [``param``] セクション(サブセクション) @@ -112,12 +147,6 @@ 説明: ソルバーの入力ファイルを作成するための参照用テンプレートファイルで利用するプレースホルダーのリスト。これらの文字列が探索中のパラメータの値に置換されます。 -- ``degree_max`` - - 形式: 実数型 (default: 6.0) - - 説明: 最大角度(度単位)の指定 - [``reference``] セクション(サブセクション) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,18 +156,23 @@ 説明: 実験データファイルへのパス。 -- ``first`` +- ``reference_first_line`` 形式: 整数型 (default: 1) 説明: 実験データファイルを読み込む範囲を指定するパラメータ。実験ファイルを読み込む最初の行を指定。 -- ``last`` +- ``reference_last_line`` - 形式: 整数型 (default: 56) + 形式: 整数型 (default: 実験データファイルの最後の行の行数) 説明: 実験データファイルを読み込む範囲を指定するパラメータ。実験ファイルを読み込む最後の行を指定。 +- ``exp_number`` + + 形式: 整数型のリスト (default: None、設定必須) + + 説明: 実験データファイルを読み込む範囲を指定するパラメータ。読み込む列を指定。複数指定が可能。設定した値は、前述の ``cal_number`` ([``config``] セクション)の値とリストの長さを一致させる必要があります。 ソルバー用補助ファイル ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -154,45 +188,45 @@ .. code-block:: 2 ,NELMS, -------- Ge(001)-c4x2 - 32,1.0,0.1 ,Ge Z,da1,sap + 32,1.2,0.15 ,Ge Z,da1,sap 0.6,0.6,0.6 ,BH(I),BK(I),BZ(I) - 32,1.0,0.1 ,Ge Z,da1,sap + 32,1.2,0.15 ,Ge Z,da1,sap 0.4,0.4,0.4 ,BH(I),BK(I),BZ(I) - 9,4,0,0,2, 2.0,-0.5,0.5 ,NSGS,msa,msb,nsa,nsb,dthick,DXS,DYS + 9,4,0,0,2,1.7,-0.5,0.5 ,NSGS,msa,msb,nsa,nsb,dthick,DXS,DYS 8 ,NATM - 1, 1.0, 1.34502591 1 value_01 ,IELM(I),ocr(I),X(I),Y(I),Z(I) - 1, 1.0, 0.752457792 1 value_02 - 2, 1.0, 1.480003343 1.465005851 value_03 - 2, 1.0, 2 1.497500418 2.281675 - 2, 1.0, 1 1.5 1.991675 - 2, 1.0, 0 1 0.847225 - 2, 1.0, 2 1 0.807225 - 2, 1.0, 1.009998328 1 0.597225 + 1, 1.0, value_01, 1.00000, 5.231000 ,IELM(I),ocr(I),X(I),Y(I),Z(I + 1, 1.0, value_02, 1.00000, 4.371000 + 2, 1.0, 1.50000, 1.50000, 3.596000 + 2, 1.0, 2.00000, 1.49751, 2.100000 + 2, 1.0, 1.00000, 1.50000, 2.000000 + 2, 1.0, 0.00000, 1.00000, 0.849425 + 2, 1.0, 2.00000, 1.00000, 0.809425 + 2, 1.0, 1.00997, 1.00000, 0.599425 1,1 ,(WDOM,I=1,NDOM) - -この場合、 ``value_01``, ``value_02``, ``value_03`` が動かすパラメータとなります。 +この場合、 ``value_01``, ``value_02`` が動かすパラメータとなります。 ターゲット参照ファイル ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ターゲットにするデータが格納されたファイル ``experiment.txt`` を指定します。 -第一列に角度、第二列に反射強度に重みをかけて計算した値が入ってます。 -以下、ファイルの例を指定します。 +第一列に角度、第二列以降に反射強度にコンボリューションを計算した値が入ってます。 +以下、ファイルの例を示します。 .. code-block:: - 0.100000 0.002374995 - 0.200000 0.003614789 - 0.300000 0.005023215 - 0.400000 0.006504978 - 0.500000 0.007990674 - 0.600000 0.009441623 - 0.700000 0.010839445 - 0.800000 0.012174578 - 0.900000 0.013439485 - 1.000000 0.014625579 + 3.00000e-01 8.17149e-03 1.03057e-05 8.88164e-15 ... + 4.00000e-01 1.13871e-02 4.01611e-05 2.23952e-13 ... + 5.00000e-01 1.44044e-02 1.29668e-04 4.53633e-12 ... + 6.00000e-01 1.68659e-02 3.49471e-04 7.38656e-11 ... + 7.00000e-01 1.85375e-02 7.93037e-04 9.67719e-10 ... + 8.00000e-01 1.93113e-02 1.52987e-03 1.02117e-08 ... + 9.00000e-01 1.92590e-02 2.53448e-03 8.69136e-08 ... + 1.00000e+00 1.86780e-02 3.64176e-03 5.97661e-07 ... + 1.10000e+00 1.80255e-02 4.57932e-03 3.32760e-06 ... + 1.20000e+00 1.77339e-02 5.07634e-03 1.50410e-05 ... + 1.30000e+00 1.80264e-02 4.99008e-03 5.53791e-05 ... ... @@ -222,21 +256,49 @@ output-filename : surf-bulkP.s -``RockingCurve.txt`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``RockingCurve_calculated.txt`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``generate_rocking_curve`` ([``solver``] セクション) が"true"の場合のみ ``Log%%%%%_#####`` フォルダに出力されます。 + +ファイル冒頭には文頭に ``#`` が付いたヘッダーが記されます。ヘッダーには探索変数の値、目的関数値 ``f(x)`` オプションで指定した ``Rfactor_type`` ``normalization` ``weight_type`` ``cal_number`` 、オプションで指定またはプログラムが計算したビームごとの重み ``spot_weight`` 、データ部分の列に何が記されているか( ``# 0 glanceing_angle`` など)が記されています。 + +``#`` が付いていない部分はデータ表記部分になります。1列目は視写角、2列目以降は各ビームの強度が記しています。どのビームの強度が記されているかはヘッダーの表記で確認できます。例えば + +.. code-block:: + + # #0 glancing_angle + # #1 cal_number=1 + # #2 cal_number=2 + # #3 cal_number=4 + +との記載があれば、1列目は視写角、2列目は計算データファイルの1列目に相当するビームの反射強度、3列目は計算データファイルの2列目に相当するビームの反射強度、4列目は計算データファイルの4列目に相当するビームの反射強度が記されていることがわかります。 + +また、各列の反射強度は各列の総和が1になるように規格化されています。目的関数値(R-factor及びR-factorの二乗)を算出する際は、ビームごとの重み ``spot_weight`` を加味して計算されています。 -``Log%%%%%_#####`` フォルダに出力されます。 -1行目にヘッダ、2行目以降は角度、コンボリューションされた計算値・実験値、規格化された計算値・実験値と、生の計算値が順に出力されます。 以下、出力例です。 .. code-block:: - #degree convolution_I_calculated I_experiment convolution_I_calculated(normalized) I_experiment(normalized) I_calculated - 0.1 0.0023816127859192407 0.002374995 0.004354402952499057 0.005364578226620574 0.001722 - 0.2 0.003626530149456865 0.003614789 0.006630537795012198 0.008164993342397588 0.003397 - 0.3 0.00504226607469267 0.005023215 0.009218987407498791 0.011346310125551366 0.005026 - 0.4 0.006533558304296079 0.006504978 0.011945579793136154 0.01469327865677437 0.006607 - 0.5 0.00803056955158873 0.007990674 0.014682628499657693 0.018049130948243314 0.008139 - 0.6 0.009493271317558538 0.009441623 0.017356947736613827 0.021326497600946535 0.00962 - 0.7 0.010899633015118851 0.010839445 0.019928258053867838 0.024483862338931763 0.01105 - ... + #value_01 = 0.00000 value_02 = 0.00000 + #Rfactor_type = A + #normalization = MANY_BEAM + #weight_type = manual + #fx(x) = 0.03686180462340505 + #cal_number = [1, 2, 4, 6, 8] + #spot_weight = [0.933 0.026 0.036 0.003 0.002] + #NOTICE : Intensities are NOT multiplied by spot_weight. + #The intensity I_(spot) for each spot is normalized as in the following equation. + #sum( I_(spot) ) = 1 + # + # #0 glancing_angle + # #1 cal_number=1 + # #2 cal_number=2 + # #3 cal_number=4 + # #4 cal_number=6 + # #5 cal_number=8 + 0.30000 1.278160358686800e-02 1.378767858296659e-04 8.396046839668212e-14 1.342648818357391e-30 6.697979700048016e-53 + 0.40000 1.778953628930054e-02 5.281839702773564e-04 2.108814173486245e-12 2.467220122612354e-28 7.252675318478533e-50 + 0.50000 2.247181148723425e-02 1.671115124520428e-03 4.250758278908295e-11 3.632860054842994e-26 6.291667506376419e-47 + ... + From 63980bcee17dd4bf4dbb2b332b40c60e60f7a0f6 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 11 Nov 2023 19:19:23 +0900 Subject: [PATCH 47/67] add comment --- src/py2dmat/solver/sim_trhepd_rheed.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index cd645eaf..555ba485 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -175,7 +175,8 @@ def __init__(self, info, d_timer): self.dimension = info.solver["dimension"] else: self.dimension = info.base["dimension"] - + + #read info info_s = info.solver self.run_scheme = info_s["run_scheme"] self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) @@ -573,6 +574,7 @@ def __init__(self, info, d_timer): msg ="ERROR: normalization must be " msg+="MANY_BEAM or TOTAL" raise exception.InputError(msg) + # solver.config info_config = info_s.get("config", {}) self.surface_output_file = info_config.get( @@ -722,7 +724,7 @@ def _post(self, fitted_x_list): time_end = time.perf_counter() self.detail_timer["calculate_R-factor"] += time_end - time_sta - #generate rocking curve + #generate RockingCurve_calculated.txt dimension = self.dimension string_list = self.string_list cal_number = self.cal_number @@ -820,8 +822,7 @@ def _calc_I_from_file(self): self.isWarning_calcnline = True calc_number_of_g_angles = calculated_nlines - # Define the array for the rocking curve data. - # Note the components with (beam-index)=0 are the degree data + # Define the array for the original calculated data. RC_data_org = np.zeros((calc_number_of_g_angles, calc_number_of_beams_org+1)) for g_angle_index in range(calc_number_of_g_angles): line_index = (calculated_first_line - 1) + g_angle_index @@ -838,6 +839,7 @@ def _calc_I_from_file(self): if self.isLogmode : time_sta = time.perf_counter() verbose_mode = False + # convolution data_convolution = lib_make_convolution.calc( RC_data_org, calc_number_of_beams_org, @@ -860,6 +862,8 @@ def _calc_I_from_file(self): glancing_angle = data_convolution[:,0] beam_number_reference = len(cal_number) + + # Normalization of calculated data. for loop_index in range(beam_number_reference): cal_index = cal_number[loop_index] conv_I_calculated = data_convolution[:,cal_index] @@ -892,6 +896,7 @@ def _calc_I_from_file(self): [conv_I_calculated_normalized]] ) if loop_index == beam_number_reference-1: #first loop + #calculate spot_weight self.spot_weight = ( conv_I_calculated_norm_l / sum(conv_I_calculated_norm_l) )**2 elif self.normalization=="MANY_BEAM" and self.weight_type=="manual": From 9e5ac8325e48ee6cc2936d88d6f05b1d11222a89 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sat, 11 Nov 2023 20:51:07 +0900 Subject: [PATCH 48/67] add TypeHint --- src/py2dmat/solver/sim_trhepd_rheed.py | 64 ++++++++++++++++++-------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index 555ba485..378e5495 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -1,27 +1,34 @@ -from typing import List import itertools import os import os.path import shutil -from pathlib import Path import subprocess import time -from . import lib_make_convolution +import ctypes +import copy import numpy as np import py2dmat from py2dmat import exception, mpi +from . import lib_make_convolution -import ctypes - -from typing import TYPE_CHECKING +#for type hints +from pathlib import Path +from typing import List, Dict, Optional, TYPE_CHECKING -import copy +if TYPE_CHECKING: + from mpi4py import MPI class Solver(py2dmat.solver.SolverBase): + mpicomm: Optional["MPI.Comm"] + mpisize: int + mpirank: int + run_scheme: List[str] + isLogmode: bool + detail_timer: Optional[Dict[str, float]] path_to_solver: Path - + def __init__(self, info: py2dmat.Info): super().__init__(info) self.mpicomm = mpi.comm() @@ -62,7 +69,7 @@ def __init__(self, info: py2dmat.Info): self.input = Solver.Input(info,self.detail_timer) self.output = Solver.Output(info,self.detail_timer) - def set_detail_timer(self): + def set_detail_timer(self) -> None: # TODO: Operate log_mode with toml file. Generate txt of detail_timer. if self.isLogmode: self.detail_timer = {} @@ -78,7 +85,7 @@ def set_detail_timer(self): else: self.detail_timer = None - def default_run_scheme(self): + def default_run_scheme(self) -> str: """ Return ------- @@ -100,7 +107,7 @@ def prepare(self, message: py2dmat.Message) -> None: def get_results(self) -> float: return self.output.get_results(self.work_dir) - def load_so(self): + def load_so(self) -> None: self.lib = np.ctypeslib.load_library("surf.so", os.path.dirname(__file__)) self.lib.surf_so.argtypes = ( @@ -114,7 +121,7 @@ def load_so(self): ) self.lib.surf_so.restype = ctypes.c_void_p - def launch_so(self): + def launch_so(self) -> None: n_template_file = len(self.input.template_file) m_template_file = self.input.surf_tempalte_width_for_fortran @@ -149,13 +156,20 @@ def run(self, nprocs: int = 1, nthreads: int = 1) -> None: self.detail_timer["launch_STR"] += time_end - time_sta class Input(object): + mpicomm: Optional["MPI.Comm"] + mpisize: int + mpirank: int + root_dir: Path output_dir: Path dimension: int + run_scheme: str + generate_rocking_curve: bool string_list: List[str] bulk_output_file: Path surface_input_file: Path surface_template_file: Path + template_file_origin: Optional[List[str]] def __init__(self, info, d_timer): self.mpicomm = mpi.comm() @@ -240,7 +254,7 @@ def __init__(self, info, d_timer): f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" ) - def load_surface_template_file(self, filename): + def load_surface_template_file(self, filename) : template_file = [] with open(self.surface_template_file) as f: for line in f: @@ -361,18 +375,30 @@ class Output(object): """ Output manager. """ + mpicomm: Optional["MPI.Comm"] + mpisize: int + mpirank: int + run_scheme: str + generate_rocking_curve: bool dimension: int - string_list: List[str] - surface_output_file: str normalization: str + weight_type: Optional[str] + spot_weight: List Rfactor_type: str + omega: float + remove_work_dir: bool + string_list: List[str] + reference_first_line: int + reference_last_line: Optional[int] + reference_path: str + exp_number: Optional[List[int]] + I_reference_normalized_l: np.ndarray + surface_output_file: str calculated_first_line: int calculated_last_line: int - - I_reference: List[float] - I_reference_norm: float - I_reference_normalized: List[float] + calculated_info_line: int + cal_number: Optional[List[int]] def __init__(self, info, d_timer): self.mpicomm = mpi.comm() From 5c34d84ba8edf725cb5adf6025a96d07390a47a8 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sun, 12 Nov 2023 15:20:33 +0900 Subject: [PATCH 49/67] Adjustment of variable types --- doc/ja/source/solver/sim-trhepd-rheed.rst | 4 +- src/py2dmat/solver/sim_trhepd_rheed.py | 48 +++++++++++------------ 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/doc/ja/source/solver/sim-trhepd-rheed.rst b/doc/ja/source/solver/sim-trhepd-rheed.rst index ea2ded00..19882d5e 100644 --- a/doc/ja/source/solver/sim-trhepd-rheed.rst +++ b/doc/ja/source/solver/sim-trhepd-rheed.rst @@ -79,7 +79,7 @@ - ``cal_number`` - 形式: 整数型のリスト (default: None、設定必須) + 形式: 整数型のリスト (default: []、設定必須) 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む列(ビーム)を指定。複数指定が可能。設定した値は、後述の ``exp_number`` ([``reference``] セクション)の値とリストの長さを一致させる必要があります。 @@ -170,7 +170,7 @@ - ``exp_number`` - 形式: 整数型のリスト (default: None、設定必須) + 形式: 整数型のリスト (default: []、設定必須) 説明: 実験データファイルを読み込む範囲を指定するパラメータ。読み込む列を指定。複数指定が可能。設定した値は、前述の ``cal_number`` ([``config``] セクション)の値とリストの長さを一致させる必要があります。 diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index 378e5495..e3bc5f74 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -24,9 +24,9 @@ class Solver(py2dmat.solver.SolverBase): mpicomm: Optional["MPI.Comm"] mpisize: int mpirank: int - run_scheme: List[str] + run_scheme: str isLogmode: bool - detail_timer: Optional[Dict[str, float]] + detail_timer: Dict path_to_solver: Path def __init__(self, info: py2dmat.Info): @@ -37,7 +37,7 @@ def __init__(self, info: py2dmat.Info): self._name = "sim_trhepd_rheed_mb_connect" - self.run_scheme = info.solver.get("run_scheme",None) + self.run_scheme = info.solver.get("run_scheme","") scheme_list = ["subprocess","connect_so"] scheme_judge = [i == self.run_scheme for i in scheme_list] @@ -66,8 +66,8 @@ def __init__(self, info: py2dmat.Info): self.isLogmode = False self.set_detail_timer() - self.input = Solver.Input(info,self.detail_timer) - self.output = Solver.Output(info,self.detail_timer) + self.input = Solver.Input(info,self.isLogmode,self.detail_timer) + self.output = Solver.Output(info,self.isLogmode,self.detail_timer) def set_detail_timer(self) -> None: # TODO: Operate log_mode with toml file. Generate txt of detail_timer. @@ -83,7 +83,7 @@ def set_detail_timer(self) -> None: self.detail_timer["make_RockingCurve.txt"] = 0 self.detail_timer["delete_Log-directory"] = 0 else: - self.detail_timer = None + self.detail_timer = {} def default_run_scheme(self) -> str: """ @@ -169,18 +169,15 @@ class Input(object): bulk_output_file: Path surface_input_file: Path surface_template_file: Path - template_file_origin: Optional[List[str]] + template_file_origin: List[str] - def __init__(self, info, d_timer): + def __init__(self, info, isLogmode, detail_timer): self.mpicomm = mpi.comm() self.mpisize = mpi.size() self.mpirank = mpi.rank() - if d_timer is None: - self.isLogmode = False - else: - self.isLogmode = True - self.detail_timer = d_timer + self.isLogmode = isLogmode + self.detail_timer = detail_timer self.root_dir = info.base["root_dir"] self.output_dir = info.base["output_dir"] @@ -392,24 +389,21 @@ class Output(object): reference_first_line: int reference_last_line: Optional[int] reference_path: str - exp_number: Optional[List[int]] + exp_number: List I_reference_normalized_l: np.ndarray surface_output_file: str calculated_first_line: int calculated_last_line: int calculated_info_line: int - cal_number: Optional[List[int]] + cal_number: List - def __init__(self, info, d_timer): + def __init__(self, info, isLogmode, detail_timer): self.mpicomm = mpi.comm() self.mpisize = mpi.size() self.mpirank = mpi.rank() - if d_timer is None: - self.isLogmode = False - else: - self.isLogmode = True - self.detail_timer = d_timer + self.isLogmode = isLogmode + self.detail_timer = detail_timer if "dimension" in info.solver: self.dimension = info.solver["dimension"] @@ -418,6 +412,10 @@ def __init__(self, info, d_timer): info_s = info.solver self.run_scheme = info_s["run_scheme"] + + #If self.run_scheme == "connect_so", + #the contnts of surface_output_file are retailned in self.surf_output. + self.surf_output = np.array([]) self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) # solver.post @@ -527,9 +525,9 @@ def __init__(self, info, d_timer): self.angle_number_experiment = data_experiment.shape[0] self.beam_number_exp_raw = data_experiment.shape[1] - v = info_ref.get("exp_number", None) + v = info_ref.get("exp_number", []) - if v == None : + if len(v) == 0 : raise exception.InputError( "ERROR: You have to set the 'exp_number'." ) @@ -647,8 +645,8 @@ def __init__(self, info, d_timer): ) self.calculated_info_line = v - v = info_config.get("cal_number",None) - if v == None : + v = info_config.get("cal_number",[]) + if len(v) == 0 : raise exception.InputError( "ERROR: You have to set the 'cal_number'." ) From 70c842beef435c87ceed5842fe3c177d97238329 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Sun, 12 Nov 2023 17:55:12 +0900 Subject: [PATCH 50/67] Adjustment of variable types --- src/py2dmat/_runner.py | 78 +++++++++++++++++++--------------- src/py2dmat/util/limitation.py | 24 +++-------- 2 files changed, 50 insertions(+), 52 deletions(-) diff --git a/src/py2dmat/_runner.py b/src/py2dmat/_runner.py index 7e21e21f..f60818fb 100644 --- a/src/py2dmat/_runner.py +++ b/src/py2dmat/_runner.py @@ -184,47 +184,55 @@ def __init__( self.ndim = info.base["dimension"] if limitation is None: info_limitation = info.runner.get("limitation",{}) - co_a: Optional[np.ndarray] = py2dmat.util.read_matrix.read_matrix( + co_a: np.ndarray = py2dmat.util.read_matrix.read_matrix( info_limitation.get("co_a", []) ) - co_b: Optional[np.ndarray] = py2dmat.util.read_matrix.read_matrix( + co_b: np.ndarray = py2dmat.util.read_matrix.read_matrix( info_limitation.get("co_b", []) ) - if co_a is not None: - if co_a.size == 0: - co_a = None - else: - if co_a.ndim != 2: - raise InputError("co_a should be a matrix") - if co_a.shape[1] != self.ndim: - msg ='The number of columns in co_a should be equal to' - msg+='the value of "dimension" in the [base] section' - raise InputError(msg) - n_row_co_a = co_a.shape[0] - if co_b is not None: - if co_b.size == 0: - if co_a is None: - co_b = None - else: # co_a is not None: - msg = "ERROR: co_a is defined but co_b is not." - raise InputError(msg) - elif co_b.ndim == 2: - if co_a is not None: - if co_b.shape[0] == 1 or co_b.shape[1] == 1: - co_b = co_b.reshape(-1) - else: - raise InputError("co_b should be a vector") - if co_b.size != n_row_co_a: - msg ='The number of row in co_a should be equal to' - msg+='the number of size in co_b' - raise InputError(msg) - else: # co_a is None: - msg = "ERROR: co_b is defined but co_a is not." + if co_a.size == 0: + is_set_co_a = False + else: + is_set_co_a = True + if co_a.ndim != 2: + raise InputError("co_a should be a matrix") + if co_a.shape[1] != self.ndim: + msg ='The number of columns in co_a should be equal to' + msg+='the value of "dimension" in the [base] section' + raise InputError(msg) + n_row_co_a = co_a.shape[0] + if co_b.size == 0: + if not is_set_co_a : + is_set_co_b = False + else: # is_set_co_a is True + msg = "ERROR: co_a is defined but co_b is not." + raise InputError(msg) + elif co_b.ndim == 2: + if is_set_co_a: + if co_b.shape[0] == 1 or co_b.shape[1] == 1: + is_set_co_b = True + co_b = co_b.reshape(-1) + else: + raise InputError("co_b should be a vector") + if co_b.size != n_row_co_a: + msg ='The number of row in co_a should be equal to' + msg+='the number of size in co_b' raise InputError(msg) + else: # not is_set_co_a: + msg = "ERROR: co_b is defined but co_a is not." + raise InputError(msg) + elif co_b.ndim > 2: + raise InputError("co_b should be a vector") + + if is_set_co_a and is_set_co_b: + is_limitation = True + elif (not is_set_co_a) and (not is_set_co_b): + is_limitation = False + else: + msg = "ERROR: Both co_a and co_b must be defined." + raise InputError(msg) - elif co_b.ndim > 2: - raise InputError("co_b should be a vector") - self.limitation = py2dmat.util.limitation.Inequality(co_a, co_b) + self.limitation = py2dmat.util.limitation.Inequality(co_a, co_b, is_limitation) def prepare(self, proc_dir: Path): self.logger.prepare(proc_dir) diff --git a/src/py2dmat/util/limitation.py b/src/py2dmat/util/limitation.py index 0c973f7f..5a1f03e4 100644 --- a/src/py2dmat/util/limitation.py +++ b/src/py2dmat/util/limitation.py @@ -6,23 +6,14 @@ # for type hints from pathlib import Path -from typing import List, Optional, TYPE_CHECKING, Dict, Tuple +from typing import List, Optional, Dict class LimitationBase(metaclass=ABCMeta): @abstractmethod - def __init__ (self, a: Optional[np.ndarray] = None, - b: Optional[np.ndarray] = None): - if (a is not None) or (b is not None): - if a is None: - msg = "ERROR: b is defined but a is not." - raise RuntimeError(msg) - if b is None: - msg = "ERROR: a is defined but b is not." - raise RuntimeError(msg) - if (a is None) and (b is None): - self.islimitary = False - else: - self.islimitary = True + def __init__ (self, a: np.ndarray, b: np.ndarray, is_limitary: bool): + + self.islimitary = is_limitary + if self.islimitary: self.a = a self.b = b self.n_formura = a.shape[0] @@ -33,9 +24,8 @@ def judge(self, x: np.ndarray) -> bool: pass class Inequality(LimitationBase): - def __init__ (self, a: Optional[np.ndarray] = None, - b: Optional[np.ndarray] = None): - super().__init__(a, b) + def __init__ (self, a: np.ndarray, b: np.ndarray, is_limitary: bool): + super().__init__(a, b, is_limitary) def judge(self, x: np.ndarray) -> bool: if self.islimitary : From b149b2301bbd668e41c363bf865692b01f264798 Mon Sep 17 00:00:00 2001 From: hiwamoto Date: Mon, 13 Nov 2023 19:49:00 +0900 Subject: [PATCH 51/67] Slight adjustments to the document --- doc/ja/source/solver/sim-trhepd-rheed.rst | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/ja/source/solver/sim-trhepd-rheed.rst b/doc/ja/source/solver/sim-trhepd-rheed.rst index 19882d5e..6f936375 100644 --- a/doc/ja/source/solver/sim-trhepd-rheed.rst +++ b/doc/ja/source/solver/sim-trhepd-rheed.rst @@ -81,7 +81,7 @@ 形式: 整数型のリスト (default: []、設定必須) - 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む列(ビーム)を指定。複数指定が可能。設定した値は、後述の ``exp_number`` ([``reference``] セクション)の値とリストの長さを一致させる必要があります。 + 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込むデータ列を指定。複数指定が可能。設定した値は、後述の ``exp_number`` ([``reference``] セクション)の値とリストの長さを一致させる必要があります。 [``post``] セクション(サブセクション) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ 形式: string型。"TOTAL"または"MANY_BEAM"のいずれかをとります。 (default: ""、設定必須) - 説明: 実験・計算のデータベクトルの規格化の方法。"TOTAL"の場合、全体の和で規格化をします。ただしビームの本数が1つのみ適用できる規格化方法なので、 ``cal_number`` ([``config``] セクション)および ``exp_number`` ([``reference``] セクション)で設定したリストの長さが1である必要が有ります。"MANY_BEAM"はビームの本数が複数であるときに利用できる規格化方法です。後述の ``weight_type`` によって規格化方法が変わります。 + 説明: 実験・計算のデータベクトルの規格化の方法。"TOTAL"の場合、全体の和で規格化をします。ただし計算に使用するデータ列が1つのみ適用できる規格化方法なので、 ``cal_number`` ([``config``] セクション)および ``exp_number`` ([``reference``] セクション)で設定したリストの長さが1である必要が有ります。"MANY_BEAM"はデータ列が2つ以上であるときに利用できる規格化方法です。後述の ``weight_type`` によって規格化方法が変わります。 **なお、 normalization="MAX" は廃止となりました。** @@ -98,8 +98,8 @@ 形式: string型または ``None`` 。"calc"または"manual"のいずれかを設定する必要があります。 (default: ``None`` 、 ``normalization = "MANY_BEAM"`` としたとき設定必須) - 説明: 目的関数値を計算するときの、ビームごとの重みの計算方法を指定します。 :math:`n` をビームのindex( :math:`n = 1,2,3..` ) 、 :math:`m` を視射角のindexとして、計算データを :math:`v^{(n)} = (v^{(n)}_{1}, v^{(n)}_{2}, .. ,v^{(n)}_{m})` と表すとします。 - "calc"とした場合、各ビームごとの重み :math:`w^{(n)}` は次の式で与えられます。 :math:`w^{(n)} = ( \sum_i^m v^{(n)}_{i} / \sum_j^n \sum_i^m v^{(j)}_i )^{2}.` + 説明: 目的関数値を計算するときの、データ列ごとの重みの計算方法を指定します。 :math:`n` をデータ列のindex( :math:`n = 1,2,3..` ) 、 :math:`m` を視射角のindexとして、計算データを :math:`v^{(n)} = (v^{(n)}_{1}, v^{(n)}_{2}, .. ,v^{(n)}_{m})` と表すとします。 + "calc"とした場合、データ列ごとの重み :math:`w^{(n)}` は次の式で与えられます。 :math:`w^{(n)} = ( \sum_i^m v^{(n)}_{i} / \sum_j^n \sum_i^m v^{(j)}_i )^{2}.` "manual"とした場合、オプション ``spot_weight`` を用いることで、ユーザーが重みを指定可能です。 - ``spot_weight`` @@ -107,7 +107,7 @@ 形式: float型のリスト。 (default: [] 、 ``weight_type = "manual"`` としたとき設定必須) 説明: オプション ``weight_type`` を"manual"と設定した際に設定できます。 - それ以外の指定では、このオプションは計算に反映されません。目的関数値を計算するときの、ビームごとの重みを設定します。また、このオプションで指定された重みは総和が1になります。 + それ以外の指定では、このオプションは計算に反映されません。目的関数値を計算するときの、データ列ごとの重みを設定します。また、このオプションで指定された重みは総和が1になります。 例えば、[3,2,1]を指定すると、 :math:`w^{(1)}=1/2, w^{(2)}=1/3, w^{(3)}=1/6` となります。 - ``Rfactor_type`` @@ -116,14 +116,14 @@ 説明: 目的関数値の計算方法の指定。 実験・計算のデータベクトルを、それぞれ :math:`u^{(n)} = (u^{(n)}_{1}, u^{(n)}_{2},...,u^{(n)}_{m})`, :math:`v^{(n)} = (v^{(n)}_{1}, v^{(n)}_{2},...,v^{(n)}_{m})` と書くとします。 - また、各ビームごとの重みを :math:`w^{(n)}` とします。:math:`n` はビームのindexです( :math:`n = 1,2,3..` )。 + また、各データ列の重みを :math:`w^{(n)}` とします。:math:`n` はデータ列のindexです( :math:`n = 1,2,3..` )。 "A"タイプを指定すると、目的関数値は :math:`R = [ \sum_{j}^{n} w^{(j)} \{ \sum_{i}^{m} (u^{(j)}_{i}-v^{(j)}_{i})^{2} \} ]^{1/2}` で計算されるRファクター値となります。 "A2"タイプを指定すると、目的関数値は :math:`R^{2} = \sum_{j}^{n} w^{(j)} \{ \sum_{i}^{m} (u^{(j)}_{i}-v^{(j)}_{i})^{2} \}` で計算されるRファクターの二乗の値となります。 "B"タイプを指定すると、目的関数値は :math:`R = (\sum_{i}^{m} (u^{(1)}_{i}-v^{(1)}_{i})^{2})^{1/2}/( \sum_{i}^{m} (u^{(1)}_{i})^{2} + \sum_{i}^{m} (v^{(1)}_{i})^2)` で計算されるRファクター値となります。 - "B"タイプはビームが1つの実験・計算データを用いた実行( :math:`n=1` )のみ対応しています。 + "B"タイプはデータ列が1つの実験・計算データを用いた実行( :math:`n=1` )のみ対応しています。 - ``omega`` @@ -172,7 +172,7 @@ 形式: 整数型のリスト (default: []、設定必須) - 説明: 実験データファイルを読み込む範囲を指定するパラメータ。読み込む列を指定。複数指定が可能。設定した値は、前述の ``cal_number`` ([``config``] セクション)の値とリストの長さを一致させる必要があります。 + 説明: 実験データファイルを読み込む範囲を指定するパラメータ。読み込むデータ列を指定。複数指定が可能。設定した値は、前述の ``cal_number`` ([``config``] セクション)の値とリストの長さを一致させる必要があります。 ソルバー用補助ファイル ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -261,9 +261,9 @@ ``generate_rocking_curve`` ([``solver``] セクション) が"true"の場合のみ ``Log%%%%%_#####`` フォルダに出力されます。 -ファイル冒頭には文頭に ``#`` が付いたヘッダーが記されます。ヘッダーには探索変数の値、目的関数値 ``f(x)`` オプションで指定した ``Rfactor_type`` ``normalization` ``weight_type`` ``cal_number`` 、オプションで指定またはプログラムが計算したビームごとの重み ``spot_weight`` 、データ部分の列に何が記されているか( ``# 0 glanceing_angle`` など)が記されています。 +ファイル冒頭には文頭に ``#`` が付いたヘッダーが記されます。ヘッダーには探索変数の値、目的関数値 ``f(x)`` オプションで指定した ``Rfactor_type`` ``normalization` ``weight_type`` ``cal_number`` 、オプションで指定またはプログラムが計算したデータ列ごとの重み ``spot_weight`` 、データ部分の列に何が記されているか( ``# 0 glanceing_angle`` など)が記されています。 -``#`` が付いていない部分はデータ表記部分になります。1列目は視写角、2列目以降は各ビームの強度が記しています。どのビームの強度が記されているかはヘッダーの表記で確認できます。例えば +``#`` が付いていない部分はデータ表記部分になります。1列目は視写角、2列目以降はデータ列ごとに強度が記しています。どのデータ列が記されているかはヘッダーの表記で確認できます。例えば .. code-block:: @@ -272,9 +272,9 @@ # #2 cal_number=2 # #3 cal_number=4 -との記載があれば、1列目は視写角、2列目は計算データファイルの1列目に相当するビームの反射強度、3列目は計算データファイルの2列目に相当するビームの反射強度、4列目は計算データファイルの4列目に相当するビームの反射強度が記されていることがわかります。 +との記載があれば、1列目は視写角、2列目は計算データファイルの1列目に相当する反射強度、3列目は計算データファイルの2列目に相当する反射強度、4列目は計算データファイルの4列目に相当する反射強度が記されていることがわかります。 -また、各列の反射強度は各列の総和が1になるように規格化されています。目的関数値(R-factor及びR-factorの二乗)を算出する際は、ビームごとの重み ``spot_weight`` を加味して計算されています。 +また、各列の反射強度は各列の総和が1になるように規格化されています。目的関数値(R-factor及びR-factorの二乗)を算出する際は、データ列ごとの重み ``spot_weight`` を加味して計算されています。 以下、出力例です。 From d2c927b9c75279c7d8e974846b12791afe828e2c Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Thu, 22 Feb 2024 09:49:22 +0900 Subject: [PATCH 52/67] reformat --- src/py2dmat/solver/lib_make_convolution.py | 44 +- src/py2dmat/solver/sim_trhepd_rheed.py | 692 +++++++++++---------- 2 files changed, 381 insertions(+), 355 deletions(-) diff --git a/src/py2dmat/solver/lib_make_convolution.py b/src/py2dmat/solver/lib_make_convolution.py index 8d591013..a4cc12c4 100644 --- a/src/py2dmat/solver/lib_make_convolution.py +++ b/src/py2dmat/solver/lib_make_convolution.py @@ -1,40 +1,50 @@ import numpy as np -import sys import copy + def calc(RC_data_org, number_of_beams, number_of_glancing_angles, omega, verbose_mode): - sigma = 0.5 * omega / (np.sqrt(2.0*np.log(2.0))) + sigma = 0.5 * omega / (np.sqrt(2.0 * np.log(2.0))) def g(x): - g = (1.0 / (sigma*np.sqrt(2.0*np.pi))) * np.exp(-0.5 * x ** 2.0 / sigma ** 2.0) + g = (1.0 / (sigma * np.sqrt(2.0 * np.pi))) * np.exp( + -0.5 * x**2.0 / sigma**2.0 + ) return g - RC_data_cnv = np.zeros((number_of_glancing_angles, number_of_beams+1)) - #copy glancing angle - RC_data_cnv[:,0] = copy.deepcopy(RC_data_org[:,0]) + RC_data_cnv = np.zeros((number_of_glancing_angles, number_of_beams + 1)) + # copy glancing angle + RC_data_cnv[:, 0] = copy.deepcopy(RC_data_org[:, 0]) if verbose_mode: - print("RC_data_org =\n",RC_data_org) - print("RC_data_cnv =\n",RC_data_cnv) - print('angle_interval=', angle_interval) + print("RC_data_org =\n", RC_data_org) + print("RC_data_cnv =\n", RC_data_cnv) for beam_index in range(number_of_beams): for index in range(number_of_glancing_angles): integral = 0.0 angle_interval = 0.0 for index2 in range(number_of_glancing_angles): - if index2 == number_of_glancing_angles - 1 : - pass - else : - angle_interval = RC_data_org[index2+1,0] - RC_data_org[index2,0] - integral += RC_data_org[index2,beam_index+1] * g(RC_data_org[index,0] - RC_data_org[index2,0]) * angle_interval + if index2 < number_of_glancing_angles - 1: + angle_interval = RC_data_org[index2 + 1, 0] - RC_data_org[index2, 0] + integral += ( + RC_data_org[index2, beam_index + 1] + * g(RC_data_org[index, 0] - RC_data_org[index2, 0]) + * angle_interval + ) if verbose_mode: - print("beam_index, index, index2, g(RC_data_org[index,0] - RC_data_org[index2,0]) =",beam_index, index, index2, g(RC_data_org[index,0] - RC_data_org[index2,0])) - RC_data_cnv[index, beam_index+1]=integral + print( + "beam_index, index, index2, g(RC_data_org[index,0] - RC_data_org[index2,0]) =", + beam_index, + index, + index2, + g(RC_data_org[index, 0] - RC_data_org[index2, 0]), + ) + RC_data_cnv[index, beam_index + 1] = integral if verbose_mode: - print("RC_data_cnv =\n",RC_data_cnv) + print("RC_data_cnv =\n", RC_data_cnv) return RC_data_cnv + diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index e3bc5f74..e27838bc 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -2,10 +2,8 @@ import os import os.path import shutil -import subprocess import time import ctypes -import copy import numpy as np @@ -13,13 +11,14 @@ from py2dmat import exception, mpi from . import lib_make_convolution -#for type hints +# for type hints from pathlib import Path from typing import List, Dict, Optional, TYPE_CHECKING if TYPE_CHECKING: from mpi4py import MPI + class Solver(py2dmat.solver.SolverBase): mpicomm: Optional["MPI.Comm"] mpisize: int @@ -28,47 +27,47 @@ class Solver(py2dmat.solver.SolverBase): isLogmode: bool detail_timer: Dict path_to_solver: Path - + def __init__(self, info: py2dmat.Info): super().__init__(info) self.mpicomm = mpi.comm() self.mpisize = mpi.size() self.mpirank = mpi.rank() - + self._name = "sim_trhepd_rheed_mb_connect" - self.run_scheme = info.solver.get("run_scheme","") - scheme_list = ["subprocess","connect_so"] + self.run_scheme = info.solver.get("run_scheme", "") + scheme_list = ["subprocess", "connect_so"] scheme_judge = [i == self.run_scheme for i in scheme_list] if not any(scheme_judge): - raise exception.InputError( - "ERROR : Input scheme is incorrect." - ) + raise exception.InputError("ERROR : Input scheme is incorrect.") if self.run_scheme == "connect_so": self.load_so() - + elif self.run_scheme == "subprocess": - #path to surf.exe + # path to surf.exe p2solver = info.solver["config"].get("surface_exec_file", "surf.exe") if os.path.dirname(p2solver) != "": # ignore ENV[PATH] self.path_to_solver = self.root_dir / Path(p2solver).expanduser() else: - for P in itertools.chain([self.root_dir], os.environ["PATH"].split(":")): + for P in itertools.chain( + [self.root_dir], os.environ["PATH"].split(":") + ): self.path_to_solver = Path(P) / p2solver if os.access(self.path_to_solver, mode=os.X_OK): break if not os.access(self.path_to_solver, mode=os.X_OK): raise exception.InputError(f"ERROR: solver ({p2solver}) is not found") - + self.isLogmode = False self.set_detail_timer() - self.input = Solver.Input(info,self.isLogmode,self.detail_timer) - self.output = Solver.Output(info,self.isLogmode,self.detail_timer) - + self.input = Solver.Input(info, self.isLogmode, self.detail_timer) + self.output = Solver.Output(info, self.isLogmode, self.detail_timer) + def set_detail_timer(self) -> None: # TODO: Operate log_mode with toml file. Generate txt of detail_timer. if self.isLogmode: @@ -106,55 +105,55 @@ def prepare(self, message: py2dmat.Message) -> None: def get_results(self) -> float: return self.output.get_results(self.work_dir) - + def load_so(self) -> None: - self.lib = np.ctypeslib.load_library("surf.so", - os.path.dirname(__file__)) + self.lib = np.ctypeslib.load_library("surf.so", os.path.dirname(__file__)) self.lib.surf_so.argtypes = ( - ctypes.POINTER(ctypes.c_int), - ctypes.POINTER(ctypes.c_int), - np.ctypeslib.ndpointer(), - ctypes.POINTER(ctypes.c_int), - ctypes.POINTER(ctypes.c_int), - np.ctypeslib.ndpointer(), - np.ctypeslib.ndpointer() - ) + ctypes.POINTER(ctypes.c_int), + ctypes.POINTER(ctypes.c_int), + np.ctypeslib.ndpointer(), + ctypes.POINTER(ctypes.c_int), + ctypes.POINTER(ctypes.c_int), + np.ctypeslib.ndpointer(), + np.ctypeslib.ndpointer(), + ) self.lib.surf_so.restype = ctypes.c_void_p - + def launch_so(self) -> None: - + n_template_file = len(self.input.template_file) - m_template_file = self.input.surf_tempalte_width_for_fortran + m_template_file = self.input.surf_template_width_for_fortran n_bulk_file = len(self.input.bulk_file) m_bulk_file = self.input.bulk_out_width_for_fortran - + # NOTE: The "20480" is related to the following directive in surf_so.f90. # character(c_char), intent(inout) :: surf_out(20480) - emp_str = ' '*20480 + emp_str = " " * 20480 self.output.surf_output = np.array([emp_str.encode()]) self.lib.surf_so( - ctypes.byref(ctypes.c_int(n_template_file)), - ctypes.byref(ctypes.c_int(m_template_file)), - self.input.template_file, - ctypes.byref(ctypes.c_int(n_bulk_file)), - ctypes.byref(ctypes.c_int(m_bulk_file)), - self.input.bulk_file, - self.output.surf_output - ) + ctypes.byref(ctypes.c_int(n_template_file)), + ctypes.byref(ctypes.c_int(m_template_file)), + self.input.template_file, + ctypes.byref(ctypes.c_int(n_bulk_file)), + ctypes.byref(ctypes.c_int(m_bulk_file)), + self.input.bulk_file, + self.output.surf_output, + ) self.output.surf_output = self.output.surf_output[0].decode().splitlines() - + def run(self, nprocs: int = 1, nthreads: int = 1) -> None: - if self.isLogmode : time_sta = time.perf_counter() - + if self.isLogmode: + time_sta = time.perf_counter() + if self.run_scheme == "connect_so": self.launch_so() elif self.run_scheme == "subprocess": self._run_by_subprocess([str(self.path_to_solver)]) - + if self.isLogmode: time_end = time.perf_counter() self.detail_timer["launch_STR"] += time_end - time_sta - + class Input(object): mpicomm: Optional["MPI.Comm"] mpisize: int @@ -175,7 +174,7 @@ def __init__(self, info, isLogmode, detail_timer): self.mpicomm = mpi.comm() self.mpisize = mpi.size() self.mpirank = mpi.rank() - + self.isLogmode = isLogmode self.detail_timer = detail_timer @@ -186,19 +185,19 @@ def __init__(self, info, isLogmode, detail_timer): self.dimension = info.solver["dimension"] else: self.dimension = info.base["dimension"] - - #read info + + # read info info_s = info.solver self.run_scheme = info_s["run_scheme"] self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) - + # NOTE: - # surf_tempalte_width_for_fortran: Number of strings per line of template.txt data for surf.so. + # surf_template_width_for_fortran: Number of strings per line of template.txt data for surf.so. # bulk_out_width_for_fortran: Number of strings per line of bulkP.txt data for surf.so. - if self.run_scheme=="connect_so": - self.surf_tempalte_width_for_fortran = 128 + if self.run_scheme == "connect_so": + self.surf_template_width_for_fortran = 128 self.bulk_out_width_for_fortran = 1024 - + info_param = info_s.get("param", {}) v = info_param.setdefault("string_list", ["value_01", "value_02"]) if len(v) != self.dimension: @@ -219,15 +218,15 @@ def __init__(self, info, isLogmode, detail_timer): raise exception.InputError( f"ERROR: surface_template_file ({self.surface_template_file}) does not exist" ) - + if self.mpirank == 0: self._check_template() - temp_origin = self.load_surface_template_file(filename) + temp_origin = self.load_surface_template_file(filename) else: temp_origin = None - self.template_file_origin = self.mpicomm.bcast(temp_origin,root=0) + self.template_file_origin = self.mpicomm.bcast(temp_origin, root=0) - if self.run_scheme == "connect_so": + if self.run_scheme == "connect_so": filename = info_config.get("bulk_output_file", "bulkP.txt") filename = Path(filename).expanduser().resolve() self.bulk_output_file = self.root_dir / filename @@ -235,12 +234,12 @@ def __init__(self, info, isLogmode, detail_timer): raise exception.InputError( f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" ) - + if self.mpirank == 0: bulk_f = self.load_bulk_output_file(filename) else: bulk_f = None - self.bulk_file = self.mpicomm.bcast(bulk_f,root=0) + self.bulk_file = self.mpicomm.bcast(bulk_f, root=0) else: filename = info_config.get("bulk_output_file", "bulkP.b") @@ -251,14 +250,14 @@ def __init__(self, info, isLogmode, detail_timer): f"ERROR: bulk_output_file ({self.bulk_output_file}) does not exist" ) - def load_surface_template_file(self, filename) : + def load_surface_template_file(self, filename): template_file = [] with open(self.surface_template_file) as f: for line in f: template_file.append(line) return template_file - def load_bulk_output_file(self, filename) : + def load_bulk_output_file(self, filename): bulk_file = [] with open(self.bulk_output_file) as f: for line in f: @@ -269,12 +268,13 @@ def load_bulk_output_file(self, filename) : return bulk_f def prepare(self, message: py2dmat.Message): - if self.isLogmode : time_sta = time.perf_counter() - + if self.isLogmode: + time_sta = time.perf_counter() + x_list = message.x step = message.step iset = message.set - + dimension = self.dimension string_list = self.string_list bulk_output_file = self.bulk_output_file @@ -285,33 +285,36 @@ def prepare(self, message: py2dmat.Message): fitted_value += format(x_list[index], ".8f") fitted_value = fitted_value[: len(string_list[index])] fitted_x_list.append(fitted_value) - - if self.isLogmode : - time_end = time.perf_counter() + + if self.isLogmode: + time_end = time.perf_counter() self.detail_timer["make_surf_input"] += time_end - time_sta - - if self.isLogmode : time_sta = time.perf_counter() - + + if self.isLogmode: + time_sta = time.perf_counter() + + folder_name = "." if self.generate_rocking_curve: folder_name = self._pre_bulk(step, bulk_output_file, iset) else: if self.run_scheme == "connect_so": folder_name = "." - + elif self.run_scheme == "subprocess": - #make workdir and copy bulk output file + # make workdir and copy bulk output file folder_name = self._pre_bulk(step, bulk_output_file, iset) - - if self.isLogmode : - time_end = time.perf_counter() + + if self.isLogmode: + time_end = time.perf_counter() self.detail_timer["prepare_Log-directory"] += time_end - time_sta - if self.isLogmode : time_sta = time.perf_counter() - + if self.isLogmode: + time_sta = time.perf_counter() + self._replace(fitted_x_list, folder_name) - - if self.isLogmode : - time_end = time.perf_counter() + + if self.isLogmode: + time_end = time.perf_counter() self.detail_timer["make_surf_input"] += time_end - time_sta return fitted_x_list, folder_name @@ -321,7 +324,7 @@ def _pre_bulk(self, Log_number, bulk_output_file, iset): os.makedirs(folder_name, exist_ok=True) if self.run_scheme == "connect_so": pass - else: #self.run_scheme == "subprocess": + else: # self.run_scheme == "subprocess": shutil.copy( bulk_output_file, os.path.join(folder_name, bulk_output_file.name) ) @@ -330,24 +333,24 @@ def _pre_bulk(self, Log_number, bulk_output_file, iset): def _replace(self, fitted_x_list, folder_name): template_file = [] if self.run_scheme == "subprocess": - file_output = open(os.path.join(folder_name, self.surface_input_file), "w") + file_output = open( + os.path.join(folder_name, self.surface_input_file), "w" + ) for line in self.template_file_origin: for index in range(self.dimension): if line.find(self.string_list[index]) != -1: line = line.replace( - self.string_list[index], - fitted_x_list[index] - ) + self.string_list[index], fitted_x_list[index] + ) if self.run_scheme == "connect_so": line = line.replace("\t", " ").replace("\n", " ") - line = line.encode().ljust(self.surf_tempalte_width_for_fortran) + line = line.encode().ljust(self.surf_template_width_for_fortran) template_file.append(line) - + elif self.run_scheme == "subprocess": file_output.write(line) - if self.run_scheme == "connect_so": self.template_file = np.array(template_file) elif self.run_scheme == "subprocess": @@ -372,6 +375,7 @@ class Output(object): """ Output manager. """ + mpicomm: Optional["MPI.Comm"] mpisize: int mpirank: int @@ -412,9 +416,9 @@ def __init__(self, info, isLogmode, detail_timer): info_s = info.solver self.run_scheme = info_s["run_scheme"] - - #If self.run_scheme == "connect_so", - #the contnts of surface_output_file are retailned in self.surf_output. + + # If self.run_scheme == "connect_so", + # the contents of surface_output_file are retailned in self.surf_output. self.surf_output = np.array([]) self.generate_rocking_curve = info_s.get("generate_rocking_curve", False) @@ -423,58 +427,60 @@ def __init__(self, info, isLogmode, detail_timer): v = info_post.get("normalization", "") available_normalization = ["TOTAL", "MANY_BEAM"] if v == "MAX": - raise exception.InputError('ERROR: normalization == "MAX" is not available') + raise exception.InputError( + 'ERROR: normalization == "MAX" is not available' + ) if v not in available_normalization: - msg ="ERROR: normalization must be " - msg+="MANY_BEAM or TOTAL" + msg = "ERROR: normalization must be " + msg += "MANY_BEAM or TOTAL" raise exception.InputError(msg) self.normalization = v v = info_post.get("weight_type", None) available_weight_type = ["calc", "manual"] if self.normalization == "MANY_BEAM": - if v is None : - msg ='ERROR: If normalization = "MANY_BEAM", ' - msg+='"weight_type" must be set in [solver.post].' + if v is None: + msg = 'ERROR: If normalization = "MANY_BEAM", ' + msg += '"weight_type" must be set in [solver.post].' raise exception.InputError(msg) elif v not in available_weight_type: - msg ="ERROR: weight_type must be " - msg+="calc or manual" + msg = "ERROR: weight_type must be " + msg += "calc or manual" raise exception.InputError(msg) else: - if v is not None : + if v is not None: if self.mpirank == 0: - msg ='NOTICE: If normalization = "MANY_BEAM" is not set, ' - msg+='"weight_type" is NOT considered in the calculation.' - print(msg) + msg = 'NOTICE: If normalization = "MANY_BEAM" is not set, ' + msg += '"weight_type" is NOT considered in the calculation.' + print(msg) self.weight_type = None self.weight_type = v v = info_post.get("spot_weight", []) - if self.normalization=="MANY_BEAM" and self.weight_type=="manual": - if v == [] : - msg ='ERROR: With normalization="MANY_BEAM" and ' - msg+='weight_type=="manual", the "spot_weight" option ' - msg+='must be set in [solver.post].' + if self.normalization == "MANY_BEAM" and self.weight_type == "manual": + if v == []: + msg = 'ERROR: With normalization="MANY_BEAM" and ' + msg += 'weight_type=="manual", the "spot_weight" option ' + msg += "must be set in [solver.post]." raise exception.InputError(msg) - self.spot_weight = np.array(v)/sum(v) + self.spot_weight = np.array(v) / sum(v) else: if v != []: if self.mpirank == 0: - msg ='NOTICE: With the specified "normalization" option, ' - msg+='the "spot_weight" you specify in the toml file is ignored, ' - msg+='since the spot_weight is automatically calculated within the program.' + msg = 'NOTICE: With the specified "normalization" option, ' + msg += 'the "spot_weight" you specify in the toml file is ignored, ' + msg += "since the spot_weight is automatically calculated within the program." print(msg) - if self.normalization== "TOTAL": + if self.normalization == "TOTAL": self.spot_weight = np.array([1]) v = info_post.get("Rfactor_type", "A") if v not in ["A", "B", "A2"]: raise exception.InputError("ERROR: Rfactor_type must be A, A2 or B") - if self.normalization=="MANY_BEAM": - if (v!="A") and (v!="A2") : - msg ='With normalization="MANY_BEAM", ' - msg+='only Rfactor_type="A" or Rfactor_type="A2" is valid.' + if self.normalization == "MANY_BEAM": + if (v != "A") and (v != "A2"): + msg = 'With normalization="MANY_BEAM", ' + msg += 'only Rfactor_type="A" or Rfactor_type="A2" is valid.' raise exception.InputError(msg) self.Rfactor_type = v @@ -482,10 +488,9 @@ def __init__(self, info, isLogmode, detail_timer): if v <= 0.0: raise exception.InputError("ERROR: omega should be positive") self.omega = v - + self.remove_work_dir = info_post.get("remove_work_dir", False) - - + # solver.param info_param = info_s.get("param", {}) v = info_param.setdefault("string_list", ["value_01", "value_02"]) @@ -505,7 +510,7 @@ def __init__(self, info, isLogmode, detail_timer): firstline = v # None is dummy value - # If "reference_last_line" is not specified in the toml file, + # If "reference_last_line" is not specified in the toml file, # the last line of the reference file is used for the R-factor calculation. v = info_ref.setdefault("reference_last_line", None) if v is None: @@ -520,83 +525,79 @@ def __init__(self, info, isLogmode, detail_timer): reference_path = info_ref.get("path", "experiment.txt") data_experiment = self.read_experiment( - reference_path, firstline, lastline, - reference_are_read_to_final_line ) + reference_path, firstline, lastline, reference_are_read_to_final_line + ) self.angle_number_experiment = data_experiment.shape[0] self.beam_number_exp_raw = data_experiment.shape[1] - + v = info_ref.get("exp_number", []) - - if len(v) == 0 : - raise exception.InputError( - "ERROR: You have to set the 'exp_number'." - ) + + if len(v) == 0: + raise exception.InputError("ERROR: You have to set the 'exp_number'.") if not isinstance(v, list): - raise exception.InputError( - "ERROR: 'exp_number' must be a list type." - ) + raise exception.InputError("ERROR: 'exp_number' must be a list type.") - if max(v) > self.beam_number_exp_raw : - raise exception.InputError( - "ERROR: The 'exp_number' setting is wrong." - ) + if max(v) > self.beam_number_exp_raw: + raise exception.InputError("ERROR: The 'exp_number' setting is wrong.") - if self.normalization=="MANY_BEAM" and self.weight_type=="manual": + if self.normalization == "MANY_BEAM" and self.weight_type == "manual": if len(v) != len(self.spot_weight): raise exception.InputError( - "ERROR:len('exp_number') and len('spot_weight') do not match." + "ERROR:len('exp_number') and len('spot_weight') do not match." ) - if self.normalization=="TOTAL" and len(v)!=1: - msg ='When normalization=="TOTAL" is specified, ' - msg+='only one beam data can be specified with ' - msg+='"exp_number" option.' + if self.normalization == "TOTAL" and len(v) != 1: + msg = 'When normalization=="TOTAL" is specified, ' + msg += "only one beam data can be specified with " + msg += '"exp_number" option.' raise exception.InputError(msg) self.exp_number = v - - #Normalization of reference data + + # Normalization of reference data self.beam_number_experiment = len(self.exp_number) for loop_index in range(self.beam_number_experiment): exp_index = self.exp_number[loop_index] - I_reference = data_experiment[:,exp_index] + I_reference = data_experiment[:, exp_index] if self.normalization == "TOTAL": I_reference_norm = np.sum(I_reference) - I_reference_normalized = I_reference/I_reference_norm + I_reference_normalized = I_reference / I_reference_norm I_reference_norm_l = np.array([I_reference_norm]) self.I_reference_normalized_l = np.array([I_reference_normalized]) - elif self.normalization=="MANY_BEAM" and self.weight_type=="calc": + elif self.normalization == "MANY_BEAM" and self.weight_type == "calc": I_reference_norm = np.sum(I_reference) - I_reference_normalized = I_reference/I_reference_norm - if loop_index == 0: #first loop + I_reference_normalized = I_reference / I_reference_norm + if loop_index == 0: # first loop I_reference_norm_l = np.array([I_reference_norm]) - self.I_reference_normalized_l = np.array([I_reference_normalized]) - else : # N-th loop + self.I_reference_normalized_l = np.array( + [I_reference_normalized] + ) + else: # N-th loop I_reference_norm_l = np.block( - [I_reference_norm_l, I_reference_norm] - ) + [I_reference_norm_l, I_reference_norm] + ) self.I_reference_normalized_l = np.block( - [[self.I_reference_normalized_l], - [I_reference_normalized]] - ) - elif self.normalization=="MANY_BEAM" and self.weight_type=="manual": + [[self.I_reference_normalized_l], [I_reference_normalized]] + ) + elif self.normalization == "MANY_BEAM" and self.weight_type == "manual": I_reference_norm = np.sum(I_reference) - I_reference_normalized = I_reference/I_reference_norm - if loop_index == 0: #first loop + I_reference_normalized = I_reference / I_reference_norm + if loop_index == 0: # first loop I_reference_norm_l = np.array([I_reference_norm]) - self.I_reference_normalized_l = np.array([I_reference_normalized]) - else : # N-th loop + self.I_reference_normalized_l = np.array( + [I_reference_normalized] + ) + else: # N-th loop I_reference_norm_l = np.block( [I_reference_norm_l, I_reference_norm] - ) + ) self.I_reference_normalized_l = np.block( - [[self.I_reference_normalized_l], - [I_reference_normalized]] - ) + [[self.I_reference_normalized_l], [I_reference_normalized]] + ) else: - msg ="ERROR: normalization must be " - msg+="MANY_BEAM or TOTAL" + msg = "ERROR: normalization must be " + msg += "MANY_BEAM or TOTAL" raise exception.InputError(msg) # solver.config @@ -613,31 +614,32 @@ def __init__(self, info, isLogmode, detail_timer): self.calculated_first_line = v v = info_config.get( - "calculated_last_line", - self.calculated_first_line + self.angle_number_experiment-1 - ) + "calculated_last_line", + self.calculated_first_line + self.angle_number_experiment - 1, + ) if not (isinstance(v, int) and v >= 0): raise exception.InputError( "ERROR: calculated_last_line should be non-negative integer" ) self.calculated_last_line = v - - # Number of lines in the computation file + + # Number of lines in the computation file # used for R-factor calculations. - self.calculated_nlines = (self.calculated_last_line - - self.calculated_first_line + 1 ) - - if self.angle_number_experiment != self.calculated_nlines : + self.calculated_nlines = ( + self.calculated_last_line - self.calculated_first_line + 1 + ) + + if self.angle_number_experiment != self.calculated_nlines: raise exception.InputError( "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." ) - - # Variable indicating whether the warning - # "self.calculated_nlines does not match - # the number of glancing angles in the calculated file" + + # Variable indicating whether the warning + # "self.calculated_nlines does not match + # the number of glancing angles in the calculated file" # is displayed. self.isWarning_calcnline = False - + v = info_config.get("calculated_info_line", 2) if not (isinstance(v, int) and v >= 0): raise exception.InputError( @@ -645,26 +647,22 @@ def __init__(self, info, isLogmode, detail_timer): ) self.calculated_info_line = v - v = info_config.get("cal_number",[]) - if len(v) == 0 : - raise exception.InputError( - "ERROR: You have to set the 'cal_number'." - ) - + v = info_config.get("cal_number", []) + if len(v) == 0: + raise exception.InputError("ERROR: You have to set the 'cal_number'.") + if not isinstance(v, list): - raise exception.InputError( - "ERROR: 'cal_number' must be a list type." - ) - - if self.normalization=="MANY_BEAM" and self.weight_type=="manual": + raise exception.InputError("ERROR: 'cal_number' must be a list type.") + + if self.normalization == "MANY_BEAM" and self.weight_type == "manual": if len(self.spot_weight) != len(v): raise exception.InputError( "len('cal_number') and len('spot_weight') do not match." ) - if self.normalization=="TOTAL" and len(v)!=1: - msg ='When normalization=="TOTAL" is specified, ' - msg+='only one beam data can be specified with ' - msg+='"cal_number" option.' + if self.normalization == "TOTAL" and len(v) != 1: + msg = 'When normalization=="TOTAL" is specified, ' + msg += "only one beam data can be specified with " + msg += '"cal_number" option.' raise exception.InputError(msg) self.cal_number = v @@ -675,28 +673,28 @@ def read_experiment(self, ref_path, first, last, read_to_final_line): Elines = file_input.readlines() firstline = first - if read_to_final_line : + if read_to_final_line: lastline = len(Elines) else: lastline = last - - n_exp_row = lastline-firstline+1 - + + n_exp_row = lastline - firstline + 1 + # get value from data - for row_index in range(n_exp_row) : + for row_index in range(n_exp_row): line_index = firstline + row_index - 1 line = Elines[line_index] data = line.split() # first loop if row_index == 0: n_exp_column = len(data) - data_e = np.zeros((n_exp_row, n_exp_column)) #init value - + data_e = np.zeros((n_exp_row, n_exp_column)) # init value + for column_index in range(n_exp_column): data_e[row_index, column_index] = float(data[column_index]) else: data_e = None - data_exp = self.mpicomm.bcast(data_e,root=0) + data_exp = self.mpicomm.bcast(data_e, root=0) return data_exp def prepare(self, fitted_x_list): @@ -707,57 +705,62 @@ def get_results(self, work_dir) -> float: Get Rfactor obtained by the solver program. Returns ------- - """ + """ # Calculate Rfactor and Output numerical results cwd = os.getcwd() os.chdir(work_dir) Rfactor = self._post(self.fitted_x_list) os.chdir(cwd) - #delete Log-directory - if self.isLogmode : time_sta = time.perf_counter() - + # delete Log-directory + if self.isLogmode: + time_sta = time.perf_counter() + if self.run_scheme == "subprocess": if self.remove_work_dir: + def rmtree_error_handler(function, path, excinfo): print(f"WARNING: Failed to remove a working directory, {path}") + shutil.rmtree(work_dir, onerror=rmtree_error_handler) - - if self.isLogmode : + + if self.isLogmode: time_end = time.perf_counter() - self.detail_timer["delete_Log-directory"] += time_end - time_sta + self.detail_timer["delete_Log-directory"] += time_end - time_sta return Rfactor def _post(self, fitted_x_list): I_experiment_normalized_l = self.I_reference_normalized_l - + ( glancing_angle, conv_number_of_g_angle, conv_I_calculated_norm_l, conv_I_calculated_normalized_l, ) = self._calc_I_from_file() - - if self.isLogmode : time_sta = time.perf_counter() + + if self.isLogmode: + time_sta = time.perf_counter() Rfactor = self._calc_Rfactor( - conv_number_of_g_angle, - conv_I_calculated_normalized_l, - I_experiment_normalized_l, - ) - if self.isLogmode : + conv_number_of_g_angle, + conv_I_calculated_normalized_l, + I_experiment_normalized_l, + ) + if self.isLogmode: time_end = time.perf_counter() self.detail_timer["calculate_R-factor"] += time_end - time_sta - - #generate RockingCurve_calculated.txt + + # generate RockingCurve_calculated.txt dimension = self.dimension string_list = self.string_list cal_number = self.cal_number spot_weight = self.spot_weight - weight_type = self.weight_type + weight_type = self.weight_type Rfactor_type = self.Rfactor_type normalization = self.normalization - if self.generate_rocking_curve : - if self.isLogmode : time_sta = time.perf_counter() + if self.generate_rocking_curve: + if self.isLogmode: + time_sta = time.perf_counter() with open("RockingCurve_calculated.txt", "w") as file_RC: # Write headers file_RC.write("#") @@ -773,13 +776,17 @@ def _post(self, fitted_x_list): file_RC.write("#fx(x) = {}\n".format(Rfactor)) file_RC.write("#cal_number = {}\n".format(cal_number)) file_RC.write("#spot_weight = {}\n".format(spot_weight)) - file_RC.write("#NOTICE : Intensities are NOT multiplied by spot_weight.\n") - file_RC.write("#The intensity I_(spot) for each spot is normalized as in the following equation.\n") + file_RC.write( + "#NOTICE : Intensities are NOT multiplied by spot_weight.\n" + ) + file_RC.write( + "#The intensity I_(spot) for each spot is normalized as in the following equation.\n" + ) file_RC.write("#sum( I_(spot) ) = 1\n") file_RC.write("#\n") - + label_column = ["glancing_angle"] - fmt_rc = '%.5f' + fmt_rc = "%.5f" for i in range(len(cal_number)): label_column.append(f"cal_number={self.cal_number[i]}") fmt_rc += " %.15e" @@ -789,22 +796,20 @@ def _post(self, fitted_x_list): file_RC.write("\n") g_angle_for_rc = np.array([glancing_angle]) np.savetxt( - file_RC, - np.block( - [g_angle_for_rc.T, - conv_I_calculated_normalized_l.T] - ), - fmt=fmt_rc - ) - - if self.isLogmode : + file_RC, + np.block([g_angle_for_rc.T, conv_I_calculated_normalized_l.T]), + fmt=fmt_rc, + ) + + if self.isLogmode: time_end = time.perf_counter() - self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta + self.detail_timer["make_RockingCurve.txt"] += time_end - time_sta return Rfactor def _calc_I_from_file(self): - if self.isLogmode : time_sta = time.perf_counter() - + if self.isLogmode: + time_sta = time.perf_counter() + surface_output_file = self.surface_output_file calculated_first_line = self.calculated_first_line calculated_last_line = self.calculated_last_line @@ -818,146 +823,155 @@ def _calc_I_from_file(self): if self.run_scheme == "connect_so": Clines = self.surf_output - + elif self.run_scheme == "subprocess": file_input = open(self.surface_output_file, "r") Clines = file_input.readlines() file_input.close() # Reads the number of glancing angles and beams - line = Clines[calculated_info_line-1] + line = Clines[calculated_info_line - 1] line = line.replace(",", "") data = line.split() - + calc_number_of_g_angles_org = int(data[1]) - calc_number_of_beams_org = int(data[2]) - + calc_number_of_beams_org = int(data[2]) + if calc_number_of_g_angles_org != calculated_nlines: - if self.mpirank == 0 and not self.isWarning_calcnline : - msg ="WARNING:\n" - msg+="The number of lines in the calculated file " - msg+="that you have set up does not match " - msg+="the number of glancing angles in the calculated file.\n" - msg+="The number of lines (nline) in the calculated file " - msg+="used for the R-factor calculation " - msg+="is determined by the following values\n" - msg+='nline = "calculated_last_line" - "calculated_first_line" + 1.' + if self.mpirank == 0 and not self.isWarning_calcnline: + msg = "WARNING:\n" + msg += "The number of lines in the calculated file " + msg += "that you have set up does not match " + msg += "the number of glancing angles in the calculated file.\n" + msg += "The number of lines (nline) in the calculated file " + msg += "used for the R-factor calculation " + msg += "is determined by the following values\n" + msg += ( + 'nline = "calculated_last_line" - "calculated_first_line" + 1.' + ) print(msg) self.isWarning_calcnline = True calc_number_of_g_angles = calculated_nlines - + # Define the array for the original calculated data. - RC_data_org = np.zeros((calc_number_of_g_angles, calc_number_of_beams_org+1)) + RC_data_org = np.zeros( + (calc_number_of_g_angles, calc_number_of_beams_org + 1) + ) for g_angle_index in range(calc_number_of_g_angles): line_index = (calculated_first_line - 1) + g_angle_index - line = Clines[ line_index ] + line = Clines[line_index] line = line.replace(",", "") data = line.split() - RC_data_org[g_angle_index,0]=float(data[0]) + RC_data_org[g_angle_index, 0] = float(data[0]) for beam_index in range(calc_number_of_beams_org): - RC_data_org[g_angle_index, beam_index+1] = data[beam_index+1] + RC_data_org[g_angle_index, beam_index + 1] = data[beam_index + 1] - if self.isLogmode : + if self.isLogmode: time_end = time.perf_counter() self.detail_timer["load_STR_result"] += time_end - time_sta - - if self.isLogmode : time_sta = time.perf_counter() + + if self.isLogmode: + time_sta = time.perf_counter() verbose_mode = False # convolution data_convolution = lib_make_convolution.calc( - RC_data_org, - calc_number_of_beams_org, - calc_number_of_g_angles, - omega, - verbose_mode, - ) - - if self.isLogmode : + RC_data_org, + calc_number_of_beams_org, + calc_number_of_g_angles, + omega, + verbose_mode, + ) + + if self.isLogmode: time_end = time.perf_counter() self.detail_timer["convolution"] += time_end - time_sta - if self.isLogmode : time_sta = time.perf_counter() - + if self.isLogmode: + time_sta = time.perf_counter() + angle_number_convolution = data_convolution.shape[0] - if self.angle_number_experiment !=angle_number_convolution: + if self.angle_number_experiment != angle_number_convolution: raise exception.InputError( "ERROR: The number of glancing angles in the calculation data does not match the number of glancing angles in the experimental data." ) - glancing_angle = data_convolution[:,0] - + glancing_angle = data_convolution[:, 0] + beam_number_reference = len(cal_number) # Normalization of calculated data. for loop_index in range(beam_number_reference): cal_index = cal_number[loop_index] - conv_I_calculated = data_convolution[:,cal_index] + conv_I_calculated = data_convolution[:, cal_index] if self.normalization == "TOTAL": conv_I_calculated_norm = np.sum(conv_I_calculated) - conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm - conv_I_calculated_norm_l = np.array( - [conv_I_calculated_norm] - ) + conv_I_calculated_normalized = ( + conv_I_calculated / conv_I_calculated_norm + ) + conv_I_calculated_norm_l = np.array([conv_I_calculated_norm]) conv_I_calculated_normalized_l = np.array( - [conv_I_calculated_normalized] - ) - elif self.normalization=="MANY_BEAM" and self.weight_type=="calc": + [conv_I_calculated_normalized] + ) + elif self.normalization == "MANY_BEAM" and self.weight_type == "calc": conv_I_calculated_norm = np.sum(conv_I_calculated) - conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm - if loop_index == 0: #first loop - conv_I_calculated_norm_l = np.array( - [conv_I_calculated_norm] - ) + conv_I_calculated_normalized = ( + conv_I_calculated / conv_I_calculated_norm + ) + if loop_index == 0: # first loop + conv_I_calculated_norm_l = np.array([conv_I_calculated_norm]) conv_I_calculated_normalized_l = np.array( - [conv_I_calculated_normalized] - ) - else: # N-th loop + [conv_I_calculated_normalized] + ) + else: # N-th loop conv_I_calculated_norm_l = np.block( - [conv_I_calculated_norm_l, - conv_I_calculated_norm] - ) + [conv_I_calculated_norm_l, conv_I_calculated_norm] + ) conv_I_calculated_normalized_l = np.block( - [[conv_I_calculated_normalized_l], - [conv_I_calculated_normalized]] - ) - if loop_index == beam_number_reference-1: #first loop - #calculate spot_weight - self.spot_weight = ( conv_I_calculated_norm_l - / sum(conv_I_calculated_norm_l) )**2 - elif self.normalization=="MANY_BEAM" and self.weight_type=="manual": + [ + [conv_I_calculated_normalized_l], + [conv_I_calculated_normalized], + ] + ) + if loop_index == beam_number_reference - 1: # first loop + # calculate spot_weight + self.spot_weight = ( + conv_I_calculated_norm_l / sum(conv_I_calculated_norm_l) + ) ** 2 + elif self.normalization == "MANY_BEAM" and self.weight_type == "manual": conv_I_calculated_norm = np.sum(conv_I_calculated) - conv_I_calculated_normalized = conv_I_calculated/conv_I_calculated_norm - if loop_index == 0: #first loop - conv_I_calculated_norm_l = np.array( - [conv_I_calculated_norm] - ) + conv_I_calculated_normalized = ( + conv_I_calculated / conv_I_calculated_norm + ) + if loop_index == 0: # first loop + conv_I_calculated_norm_l = np.array([conv_I_calculated_norm]) conv_I_calculated_normalized_l = np.array( - [conv_I_calculated_normalized] - ) - else: # N-th loop + [conv_I_calculated_normalized] + ) + else: # N-th loop conv_I_calculated_norm_l = np.block( - [conv_I_calculated_norm_l, - conv_I_calculated_norm] - ) + [conv_I_calculated_norm_l, conv_I_calculated_norm] + ) conv_I_calculated_normalized_l = np.block( - [[conv_I_calculated_normalized_l], - [conv_I_calculated_normalized]] - ) + [ + [conv_I_calculated_normalized_l], + [conv_I_calculated_normalized], + ] + ) else: - msg ="ERROR: normalization must be " - msg+="MANY_BEAM or TOTAL" + msg = "ERROR: normalization must be " + msg += "MANY_BEAM or TOTAL" raise exception.InputError(msg) - - if self.isLogmode : + + if self.isLogmode: time_end = time.perf_counter() self.detail_timer["normalize_calc_I"] += time_end - time_sta - + return ( glancing_angle, angle_number_convolution, conv_I_calculated_norm_l, - conv_I_calculated_normalized_l - ) - + conv_I_calculated_normalized_l, + ) + def _calc_Rfactor(self, n_g_angle, calc_result, exp_result): spot_weight = self.spot_weight n_spot = len(spot_weight) @@ -966,35 +980,37 @@ def _calc_Rfactor(self, n_g_angle, calc_result, exp_result): for spot_index in range(n_spot): R_spot = 0.0 for angle_index in range(n_g_angle): - R_spot += (exp_result[spot_index, angle_index] - - calc_result[spot_index, angle_index] )**2 + R_spot += ( + exp_result[spot_index, angle_index] + - calc_result[spot_index, angle_index] + ) ** 2 R_spot = spot_weight[spot_index] * R_spot - R += R_spot + R += R_spot R = np.sqrt(R) elif self.Rfactor_type == "A2": R = 0.0 for spot_index in range(n_spot): R_spot = 0.0 for angle_index in range(n_g_angle): - R_spot += (exp_result[spot_index, angle_index] - - calc_result[spot_index, angle_index] )**2 + R_spot += ( + exp_result[spot_index, angle_index] + - calc_result[spot_index, angle_index] + ) ** 2 R_spot = spot_weight[spot_index] * R_spot - R += R_spot + R += R_spot else: # self.Rfactor_type == "B" - all_exp_result = [] + all_exp_result = [] all_calc_result = [] for spot_index in range(n_spot): for angle_index in range(n_g_angle): - all_exp_result.append( - exp_result[spot_index, angle_index]) - all_calc_result.append( - calc_result[spot_index, angle_index]) + all_exp_result.append(exp_result[spot_index, angle_index]) + all_calc_result.append(calc_result[spot_index, angle_index]) y1 = 0.0 y2 = 0.0 y3 = 0.0 for I_exp, I_calc in zip(all_exp_result, all_calc_result): y1 += (I_exp - I_calc) ** 2 - y2 += I_exp ** 2 - y3 += I_calc ** 2 + y2 += I_exp**2 + y3 += I_calc**2 R = y1 / (y2 + y3) return R From 14846c519e157ccc2ca50deda042723a1df8568d Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Thu, 22 Feb 2024 16:51:06 +0900 Subject: [PATCH 53/67] update docs --- doc/en/source/input.rst | 50 ++++++ doc/en/source/solver/sim-trhepd-rheed.rst | 205 ++++++++++++++++------ doc/en/source/tutorial/index.rst | 1 + doc/en/source/tutorial/limitation.rst | 175 ++++++++++++++++++ doc/ja/source/input.rst | 2 +- doc/ja/source/solver/sim-trhepd-rheed.rst | 77 +++++--- doc/ja/source/tutorial/limitation.rst | 1 - src/py2dmat/solver/sim_trhepd_rheed.py | 2 +- 8 files changed, 437 insertions(+), 76 deletions(-) create mode 100644 doc/en/source/tutorial/limitation.rst diff --git a/doc/en/source/input.rst b/doc/en/source/input.rst index 3edb49c6..f28d61e9 100644 --- a/doc/en/source/input.rst +++ b/doc/en/source/input.rst @@ -24,6 +24,10 @@ The input file consists of the following six sections. - Define the mapping from a parameter searched by ``Algorithm`` . +- ``limitation`` + + - Define the limitation (constration) of parameter searched by ``Algorithm`` . + - ``log`` - Specify parameters related to logging of solver calls. @@ -157,6 +161,52 @@ mean \end{matrix} \right). + +[``limitation``] section +************************* + +This section defines the limitation (constraint) in an :math:`N` dimensional parameter searched by ``Algorithm``, :math:`x`, in addition of ``min_list`` and ``max_list``. + +In the current version, a linear inequation with the form :math:`Ax+b>0` is available. + +- ``co_a`` + + Format: List of list of float, or a string (default: ``[]``) + + Description: :math:`N \times M` matrix :math:`A`. An empty list ``[]`` is a shorthand of an identity matrix. + If you want to set it by a string, arrange the elements of the matrix separated with spaces and newlines (see the example). + + +- ``co_b`` + + Format: List of float, or a string (default: ``[]``) + + Description: :math:`M` dimensional vector :math:`b`. An empty list ``[]`` is a shorthand of a zero vector. + If you want to set it by a string, arrange the elements of the vector separated with spaces. + +For example, both :: + + A = [[1,1], [0,1]] + +and :: + + A = """ + 1 1 + 0 1 + """ + +mean + +.. math:: + + A = \left( + \begin{matrix} + 1 & 1 \\ + 0 & 1 + \end{matrix} + \right). + + [``log``] section ************************ diff --git a/doc/en/source/solver/sim-trhepd-rheed.rst b/doc/en/source/solver/sim-trhepd-rheed.rst index 4e2cb2f7..da3fc4d6 100644 --- a/doc/en/source/solver/sim-trhepd-rheed.rst +++ b/doc/en/source/solver/sim-trhepd-rheed.rst @@ -19,10 +19,20 @@ The ``surf.exe`` is called from ``py2dmat``. Input parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Input parameters can be specified in subcsections ``config``, ``post``, ``param``, ``reference`` in ``solver`` section. +Input parameters can be specified in subsections ``config``, ``post``, ``param``, ``reference`` in ``solver`` section. -[``config``] section +[``solver``] section ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- ``generate_rocking_curve`` + + Format: boolean (default: false) + + Description: Whether to generate ``RockingCurve_calculated.txt``. + If ``true``, ``RockingCurve_calculated.txt`` will be generated in the working directory ``Log%%%_###``. + Note that if ``remove_work_dir`` (in [``post``] subsection) is ``true``, ``Log%%%_###`` will be removed. + +[``solver.config``] subsection +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``surface_exec_file`` @@ -60,30 +70,94 @@ Input parameters can be specified in subcsections ``config``, ``post``, ``param` Description: One of the parameters that specifies the range of output files to be read, calculated by the solver. This parameter specifies the last line to be read. -- ``row_number`` +- ``calculated_info_line`` - Format: integer (default: 8) + Format: integer (default: 2) - Description: One of the parameters that specifies the range of output files to be read, calculated by the solver. This parameter specifies the column to be read. + Description: One of the parameters that specifies the range of output files to be read, calculated by the solver. + This parameter specifies the line to be read, which contains the number of glancing angles (second column) and the number of beams (third column). + +- ``cal_number`` -[``post``] section -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Format: List of integers -- ``normalization`` + Description: Columns of dataset to be read. Multiple columns can be specified (many-beam condition). - Format: string ("TOTAL" or "MAX", default: "TOTAL") - Description: This parameter specifies whether the experimental and computational data vectors are normalized by the sum of the whole values or by the maximum value. +[``solver.post``] subsection +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This subsection is used to the postprocess -- to specify how to calculate the objective function, that is, the deviation between the experimental and computational data, and to draw the rocking curve. - ``Rfactor_type`` Format: string ("A" or "B", default: "A") - Description: This parameter specifies how to calculate the R-factor. - The experimental and computational data vectors are denoted as :math:`u = (u_{1}, u_{2},...,u_{m})`, - :math:`v = (v_{1}, v_{2},...,v_{m})`, respectively. - When "A" type is chosen, R-factor is defined as :math:`R = (\sum_i^m (u_{i}-v_{i})^{2})^{1/2}`. - When "B" type is chosen, R-factor is defined as :math:`R = (\sum_i^m (u_{i}-v_{i})^{2})^{1/2}/( \sum_i^m u_{i}^2 + \sum_i^m v_{i}^2)`. + Description: This parameter specifies how to calculate the R-factor to be minimized. + Let :math:`n` be the number of dataset, :math:`m` be the number of glancing angles, and :math:`v^{(n)} = (v^{(n)}_{1}, v^{(n)}_{2}, \dots ,v^{(n)}_{m})` be the calculated data. + With the weights of the beams, :math:`w^{(j)}`, R-factors is defined as follows: + + - "A" type: + + .. math:: + + R = \sqrt{ \sum_{j}^{n} w^{(j)} \sum_{i}^{m} \left(u^{(j)}_{i}-v^{(j)}_{i}\right)^{2} } + + - "A2" type: + + .. math:: + + R^{2} = \sum_{j}^{n} w^{(j)} \sum_{i}^{m} \left(u^{(j)}_{i}-v^{(j)}_{i}\right)^{2} + + - "B" type: + + .. math:: + + R = \frac{\sum_{i}^{m} \left(u^{(1)}_{i}-v^{(1)}_{i}\right)^{2}}{\sum_{i}^{m} \left(u^{(1)}_{i}\right)^{2} + \sum_{i}^{m} (v^{(1)}_{i})^2} + + - "B" type is available only for the single dataset (:math:`n=1`). + + +- ``normalization`` + + Format: string ("TOTAL" or "MANY_BEAM") + + Description: This parameter specifies how to normalize the experimental and computational data vectors. + + - "TOTAL" + + - To normalize the data as the summation is 1. + - The number of dataset should be one (the number of ``cal_number`` should be one). + + - "MANY_BEAM" + + - To normalize with weights as specified by ``weight_type``. + + **NOTE: "MAX" is no longer available** + +- ``weight_type`` + + Format: string or ``None``. "calc" or "manual" (default: ``None``) + + Description: The weights of the datasets for the "MANY_BEAM" normalization. + + - "calc" + + .. math:: + + w^{(n)} = \left(\frac{\sum_i^m v^{(n)}_{i}}{\sum_j^n \sum_i^m v^{(j)}_i} \right)^2 + + - "manual" + + :math:`w^{(n)}` is specified by ``spot_weight``. + +- ``spot_weight`` + + Format: list of float (mandatory when ``weight_type`` is "manual") + + Description: The weights of the beams in the calculation of R-factor. + The weights are automatically normalized as the sum be 1. + For example, [3,2,1] means :math:`w^{(1)}=1/2, w^{(2)}=1/3, w^{(3)}=1/6`. - ``omega`` @@ -95,9 +169,9 @@ Input parameters can be specified in subcsections ``config``, ``post``, ``param` Format: boolean (default: false) - Description: Whether to remove working directories after reading R-factor or not + Description: Whether to remove working directories ``Log%%%_###`` after reading R-factor or not -[``param``] section +[``solver.param``] subsection ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``string_list`` @@ -106,14 +180,9 @@ Input parameters can be specified in subcsections ``config``, ``post``, ``param` Description: List of placeholders to be used in the reference template file to create the input file for the solver. These strings will be replaced with the values of the parameters being searched for. -- ``degree_max`` - - Format: float (default: 6.0) - - Description: Maximum angle (in degrees) -[``reference``] section -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +[``solver.reference``] subsection +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``path`` @@ -121,18 +190,24 @@ Input parameters can be specified in subcsections ``config``, ``post``, ``param` Description: Path to the experimental data file. -- ``first`` +- ``reference_first_line`` Format: integer (default: 1) Description: One of the parameters that specify the range of experimental data files to be read. This parameter specifies the first line of the experimental file to be read. -- ``last`` +- ``reference_last_line`` Format: integer (default: 56) Description: One of the parameters that specify the range of experimental data files to be read. This parameter specifies the last line of the experimental file to be read. +- ``exp_number`` + + Format: List of integers + + Description: Columns of dataset to be read. Multiple columns can be specified (many-beam condition). + Reference file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -169,21 +244,22 @@ In this case, ``value_01``, ``value_02``, and ``value_03`` are the parameters to Target file ^^^^^^^^^^^^^^ This file (``experiment.txt``) contains the data to be targeted. -The first column contains the angle, and the second column contains the calculated value of the reflection intensity multiplied by the weight. +The first column contains the angle, and the second and following columns contain the calculated value of the reflection intensity multiplied by the weight. An example of the file is shown below. .. code-block:: - 0.100000 0.002374995 - 0.200000 0.003614789 - 0.300000 0.005023215 - 0.400000 0.006504978 - 0.500000 0.007990674 - 0.600000 0.009441623 - 0.700000 0.010839445 - 0.800000 0.012174578 - 0.900000 0.013439485 - 1.000000 0.014625579 + 3.00000e-01 8.17149e-03 1.03057e-05 8.88164e-15 ... + 4.00000e-01 1.13871e-02 4.01611e-05 2.23952e-13 ... + 5.00000e-01 1.44044e-02 1.29668e-04 4.53633e-12 ... + 6.00000e-01 1.68659e-02 3.49471e-04 7.38656e-11 ... + 7.00000e-01 1.85375e-02 7.93037e-04 9.67719e-10 ... + 8.00000e-01 1.93113e-02 1.52987e-03 1.02117e-08 ... + 9.00000e-01 1.92590e-02 2.53448e-03 8.69136e-08 ... + 1.00000e+00 1.86780e-02 3.64176e-03 5.97661e-07 ... + 1.10000e+00 1.80255e-02 4.57932e-03 3.32760e-06 ... + 1.20000e+00 1.77339e-02 5.07634e-03 1.50410e-05 ... + 1.30000e+00 1.80264e-02 4.99008e-03 5.53791e-05 ... ... @@ -210,20 +286,49 @@ An example is shown below. output-filename : surf-bulkP.s -``RockingCurve.txt`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``RockingCurve_calculated.txt`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This file is located in the ``Log%%%%%_#####`` folder. -The first line is the header, and the second and subsequent lines are the angle, convoluted calculated/experimental values, normalized calculated/experimental values, and raw calculated values in that order. -An example is shown below. +At the beginning of the file, the lines beginning with ``#`` are headers. +The header contains the values of the input variables, the objective function value ``f(x)``, the parameters ``Rfactor_type``, ``normalization``, ``weight_type``, ``cal_number``, ``spot_weight``, and what is marked in the data portion columns (e.g. ``# #0 glancing_angle``). + +The header is followed by the data. +The first column shows the glancing angle, and the second and subsequent columns show the intensity of each data column. +You can see which data columns are marked in the header. For example, .. code-block:: - #degree convolution_I_calculated I_experiment convolution_I_calculated(normalized) I_experiment(normalized) I_calculated - 0.1 0.0023816127859192407 0.002374995 0.004354402952499057 0.005364578226620574 0.001722 - 0.2 0.003626530149456865 0.003614789 0.006630537795012198 0.008164993342397588 0.003397 - 0.3 0.00504226607469267 0.005023215 0.009218987407498791 0.011346310125551366 0.005026 - 0.4 0.006533558304296079 0.006504978 0.011945579793136154 0.01469327865677437 0.006607 - 0.5 0.00803056955158873 0.007990674 0.014682628499657693 0.018049130948243314 0.008139 - 0.6 0.009493271317558538 0.009441623 0.017356947736613827 0.021326497600946535 0.00962 - 0.7 0.010899633015118851 0.010839445 0.019928258053867838 0.024483862338931763 0.01105 - ... + # #0 glancing_angle + # #1 cal_number=1 + # #2 cal_number=2 + # #3 cal_number=4 + +shows that the first column is the glancing angle, and the second, third, and fourth columns are the calculated data corresponding to the first, second, and fourth columns of the calculated data file, respectively. + +Intencities in each column are normalized so that the sum of the intensity is 1. +To calculate the objective function value (R-factor and R-factor squared), the data columns are weighted by ``spot_weight`` and normalized by ``normalization``. + +.. code-block:: + + #value_01 = 0.00000 value_02 = 0.00000 + #Rfactor_type = A + #normalization = MANY_BEAM + #weight_type = manual + #fx(x) = 0.03686180462340505 + #cal_number = [1, 2, 4, 6, 8] + #spot_weight = [0.933 0.026 0.036 0.003 0.002] + #NOTICE : Intensities are NOT multiplied by spot_weight. + #The intensity I_(spot) for each spot is normalized as in the following equation. + #sum( I_(spot) ) = 1 + # + # #0 glancing_angle + # #1 cal_number=1 + # #2 cal_number=2 + # #3 cal_number=4 + # #4 cal_number=6 + # #5 cal_number=8 + 0.30000 1.278160358686800e-02 1.378767858296659e-04 8.396046839668212e-14 1.342648818357391e-30 6.697979700048016e-53 + 0.40000 1.778953628930054e-02 5.281839702773564e-04 2.108814173486245e-12 2.467220122612354e-28 7.252675318478533e-50 + 0.50000 2.247181148723425e-02 1.671115124520428e-03 4.250758278908295e-11 3.632860054842994e-26 6.291667506376419e-47 + ... + diff --git a/doc/en/source/tutorial/index.rst b/doc/en/source/tutorial/index.rst index 6b33ffa1..b22f28c5 100644 --- a/doc/en/source/tutorial/index.rst +++ b/doc/en/source/tutorial/index.rst @@ -44,5 +44,6 @@ In this tutorial, we will first introduce how to run the sequential problem prog mpi bayes exchange + limitation pamc solver_simple diff --git a/doc/en/source/tutorial/limitation.rst b/doc/en/source/tutorial/limitation.rst new file mode 100644 index 00000000..baf41136 --- /dev/null +++ b/doc/en/source/tutorial/limitation.rst @@ -0,0 +1,175 @@ +Replica Exchange Monte Carlo search with limitation +========================================================================== + +This tutorial describes the constraint expression function that can be set in the ``[runner.limitation]`` section. +As an example, the replica exchange Monte Carlo method is applied to the calculation of Himmelblau with constraints. + +Sample files location +~~~~~~~~~~~~~~~~~~~~~~~~ + +Sample files are available in the ``sample/analytical/limitation`` directory. +This directory contains the following files. + +- ``ref.txt`` + + File to check if the calculation is executed correctly (answer to obtain by performing this tutorial). + +- ``input.toml`` + + Input file for the main program. + +- ``do.sh`` + + Script prepared to calculate this tutorial at once. + +In the following, we will explain these files, and then introduce the actual calculation results. + +Input files +~~~~~~~~~~~~~~~~~~~ + +The following ``input.toml`` is an input file for the main program. + +.. code-block:: + + [base] + dimension = 2 + output_dir = "output" + + [algorithm] + name = "exchange" + seed = 12345 + + [algorithm.param] + max_list = [6.0, 6.0] + min_list = [-6.0, -6.0] + unit_list = [0.3, 0.3] + + [algorithm.exchange] + Tmin = 1.0 + Tmax = 100000.0 + numsteps = 10000 + numsteps_exchange = 100 + + [solver] + name = "analytical" + function_name = "himmelblau" + + [runner] + [runner.limitation] + co_a = [[1, -1],[1, 1]] + co_b = [[0], [-1]] + +``[base]`` section is the parameter of the main program. +``dimension`` is the number of variables to be optimized, and in this case, it is 2. + +``[algorithm]`` section is the section to set the search algorithm. +``name`` is the name of the search algorithm. In this case, specify ``"exchange"`` for the replica exchange Monte Carlo method. +``seed`` is the seed given to the pseudo-random number generator. + +``[algorithm.param]`` sub-section specifies the range of parameters to be optimized. +``min_list`` indicates the minimum value, and ``max_list`` indicates the maximum value. + +``[algorithm.exchange]`` sub-section specifies the hyperparameters of the replica exchange Monte Carlo method. + +- ``numstep`` is the number of Monte Carlo updates. +- ``numsteps_exchange`` specifies the number of times to attempt temperature exchange. +- ``Tmin`` and ``Tmax`` are the lower and upper limits of the temperature, respectively. +- If ``Tlogspace`` is ``true``, the temperature is divided equally in log space. This option is not specified in this ``input.toml`` because the default value is ``true``. + +``[solver]`` section specifies the solver used internally in the main program. +In this case, the ``analytical`` solver is specified. +The ``analytical`` solver sets the function using the ``function_name`` parameter, and in this case, the Himmelblau function is specified. + +``[runner]`` section has a sub-section ``[runner.limitation]``, and in this section, the constraint expression is set. +In the current version, the constraint expression is defined as :math:`Ax+b>0` where :math:`x` is :math:`N` dimensional input parameter, :math:`A` is a :math:`M \times N` matrix, and :math:`b` is a :math:`M` dimensional vector. +:math:`A` and :math:`b` are set by ``co_a`` and ``co_b``, respectively. +For details, see the ``[limitation]`` section in the input file in the manual. + +In this case, the following constraint is imposed: + +.. math:: + + x_{1} − x_{2} > 0\\ + x_{1} + x_{2} − 1 > 0 + + +Calculation +~~~~~~~~~~~~~~~~ + +First, move to the folder where the sample file is located (assuming that you are directly under the directory where you downloaded this software). + +.. code-block:: + + cd sample/analytical/limitation + +Then, execute the main program as follows (the calculation time will end in about 20 seconds on a normal PC). + +.. code-block:: + + mpiexec -np 10 python3 ../../../src/py2dmat_main.py input.toml | tee log.txt + +In this case, a calculation with 10 MPI parallel processes is performed. +(When using OpenMPI, if the number of processes to be used is greater than the number of available cores, add the ``--oversubscribed`` option to the ``mpiexec`` command.) +After executed, the ``output`` folder is generated, and in it, a subfolder for each rank is created. +Each subfolder contains the results of the calculation. +``trial.txt`` file, which contains the parameters and objective function values evaluated at each Monte Carlo step, and ``result.txt`` file, which contains the parameters actually adopted, are created. +Both files have the same format, with the first two columns being the step number and the walker number within the process, the next being the temperature, the third being the value of the objective function, and the fourth and subsequent being the parameters. +The following is the beginning of the ``output/0/result.txt`` file: + +.. code-block:: + + # step walker T fx x1 x2 + 0 0 1.0 187.94429125133564 5.155393113805774 -2.203493345018569 + 1 0 1.0 148.23606736778044 4.9995614992887525 -2.370212436322816 + 2 0 1.0 148.23606736778044 4.9995614992887525 -2.370212436322816 + 3 0 1.0 148.23606736778044 4.9995614992887525 -2.370212436322816 + +Finally, the best parameter and the rank and Monte Carlo step at which the objective function is minimized are written to ``output/best_result.txt``. + +.. code-block:: + + nprocs = 10 + rank = 2 + step = 4523 + walker = 0 + fx = 0.00010188398524402734 + x1 = 3.584944906595298 + x2 = -1.8506985826548874 + +``do.sh`` is available as a script to calculate all at once. +Additionally, in ``do.sh``, the difference between ``best_result.txt`` and ``ref.txt`` is also compared. + +.. code-block:: + + #!/bin/bash + mpiexec -np 10 --oversubscribe python3 ../../../src/py2dmat_main.py input.toml + + echo diff output/best_result.txt ref.txt + res=0 + diff output/best_result.txt ref.txt || res=$? + if [ $res -eq 0 ]; then + echo TEST PASS + true + else + echo TEST FAILED: best_result.txt and ref.txt differ + false + fi + +Visualization of the calculation result +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By visualizing the ``result.txt`` file, we can confirm that the search is only for coordinates that satisfy the constraint expression. +``hist2d_limitation_sample.py`` is prepared to visualize the 2D parameter space. +This generates a histogram of the posterior probability distribution in the ``_histogram`` folder. +The histogram is generated using the data obtained by discarding the first 1000 steps of the search as a burn-in period. + +.. code-block:: + + python3 hist2d_limitation_sample.py -p 10 -i input.toml -b 0.1 + +The figure shows the posterior probability distribution and the two lines :math:`x_{1} − x_{2} = 0, x_{1} + x_{2} − 1 = 0`, +and it is confirmed that the search is only for the range where :math:`x_{1} − x_{2} > 0, x_{1} + x_{2} − 1 > 0`. + +.. figure:: ../../../common/img/limitation_beta_min.* + +.. figure:: ../../../common/img/limitation_beta_max.* diff --git a/doc/ja/source/input.rst b/doc/ja/source/input.rst index ea2bf59d..d558044e 100644 --- a/doc/ja/source/input.rst +++ b/doc/ja/source/input.rst @@ -172,7 +172,7 @@ py2dmat は入力ファイルの形式に `TOML `_ を採 ``Algorithm`` で探索している :math:`N` 次元のパラメータ :math:`x` に、制約条件を課すことが出来ます。 ``Algorithm`` ごとに定義する探索範囲(例:``exchange`` の ``min_list`` や ``max_list`` ) に加えて課すことが出来ます。 -現在は :math:`M` 行 :math:`N` 列の行列Aと :math:`M` 次元の縦ベクトルbから定義される :math:`Ax+b>0` の制約式が利用可能です。具体的に +現在は :math:`M` 行 :math:`N` 列の行列:math:`A` と :math:`M` 次元の縦ベクトル:math:`b` から定義される :math:`Ax+b>0` の制約式が利用可能です。具体的に .. math:: diff --git a/doc/ja/source/solver/sim-trhepd-rheed.rst b/doc/ja/source/solver/sim-trhepd-rheed.rst index 6f936375..1c9b2a7b 100644 --- a/doc/ja/source/solver/sim-trhepd-rheed.rst +++ b/doc/ja/source/solver/sim-trhepd-rheed.rst @@ -79,18 +79,59 @@ - ``cal_number`` - 形式: 整数型のリスト (default: []、設定必須) + 形式: 整数型のリスト (設定必須) 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込むデータ列を指定。複数指定が可能。設定した値は、後述の ``exp_number`` ([``reference``] セクション)の値とリストの長さを一致させる必要があります。 [``post``] セクション(サブセクション) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +実験と計算の「ズレ」の大きさを示し、最小化すべき関数である「目的関数」の定義や、ロッキングカーブを描くためのコンボリューション半値幅などを指定するセクションです。 + +- ``Rfactor_type`` + + 形式: string型。"A"、"A2"または"B"のいずれかをとります。 (default: "A") + + 説明: 目的関数値の計算方法の指定。 + 視写角のインデックスを :math:`i = 1,2,\dots,m`, ビームのインデックスを :math:`j = 1,2,\dots,n` として、 + 実験・計算のデータをそれぞれ :math:`u^{(j)}_i` と :math:`v^{(j)}_i` で表し、 + 各ビームの重みを :math:`w^{(j)}` と書くとき + + - "A"タイプ: + + .. math:: + + R = \sqrt{ \sum_{j}^{n} w^{(j)} \sum_{i}^{m} \left(u^{(j)}_{i}-v^{(j)}_{i}\right)^{2} } + + - "A2"タイプ: + + .. math:: + + R^{2} = \sum_{j}^{n} w^{(j)} \sum_{i}^{m} \left(u^{(j)}_{i}-v^{(j)}_{i}\right)^{2} + + - "B"タイプ: + + .. math:: + + R = \frac{\sum_{i}^{m} \left(u^{(1)}_{i}-v^{(1)}_{i}\right)^{2}}{\sum_{i}^{m} \left(u^{(1)}_{i}\right)^{2} + \sum_{i}^{m} (v^{(1)}_{i})^2} + + - "B"タイプはデータ列が1つの実験・計算データを用いた実行( :math:`n=1` )のみ対応しています。 + + - ``normalization`` - 形式: string型。"TOTAL"または"MANY_BEAM"のいずれかをとります。 (default: ""、設定必須) + 形式: string型。"TOTAL"または"MANY_BEAM"のいずれかをとります。 (設定必須) + + 説明: 実験・計算のデータベクトルの規格化の方法。 - 説明: 実験・計算のデータベクトルの規格化の方法。"TOTAL"の場合、全体の和で規格化をします。ただし計算に使用するデータ列が1つのみ適用できる規格化方法なので、 ``cal_number`` ([``config``] セクション)および ``exp_number`` ([``reference``] セクション)で設定したリストの長さが1である必要が有ります。"MANY_BEAM"はデータ列が2つ以上であるときに利用できる規格化方法です。後述の ``weight_type`` によって規格化方法が変わります。 + - "TOTAL" + + - 全体の和で規格化をします。 + - 計算に使用するデータ列が1つのみ適用できる規格化方法であり、 ``cal_number`` ([``config``] セクション)および ``exp_number`` ([``reference``] セクション)で設定したリストの長さが1である必要が有ります。 + + - "MANY_BEAM" + + - "MANY_BEAM"はデータ列が2つ以上であるときに利用できる規格化方法です。後述の ``weight_type`` によって規格化方法が変わります。 **なお、 normalization="MAX" は廃止となりました。** @@ -98,33 +139,22 @@ 形式: string型または ``None`` 。"calc"または"manual"のいずれかを設定する必要があります。 (default: ``None`` 、 ``normalization = "MANY_BEAM"`` としたとき設定必須) - 説明: 目的関数値を計算するときの、データ列ごとの重みの計算方法を指定します。 :math:`n` をデータ列のindex( :math:`n = 1,2,3..` ) 、 :math:`m` を視射角のindexとして、計算データを :math:`v^{(n)} = (v^{(n)}_{1}, v^{(n)}_{2}, .. ,v^{(n)}_{m})` と表すとします。 - "calc"とした場合、データ列ごとの重み :math:`w^{(n)}` は次の式で与えられます。 :math:`w^{(n)} = ( \sum_i^m v^{(n)}_{i} / \sum_j^n \sum_i^m v^{(j)}_i )^{2}.` + 説明: 目的関数値を計算するときの、ビームごとの重み :math:`w^{(j)}` の計算方法を指定します。 + "calc"とした場合、データ列ごとの重み :math:`w^{(n)}` は次の式で与えられます。 + + .. math:: + + w^{(j)} = \left(\frac{\sum_{i=1}^m v^{(j)}_{i}}{\sum_{k=1}^n \sum_{i=1}^m v^{(j)}_i} \right)^2 + "manual"とした場合、オプション ``spot_weight`` を用いることで、ユーザーが重みを指定可能です。 - ``spot_weight`` 形式: float型のリスト。 (default: [] 、 ``weight_type = "manual"`` としたとき設定必須) - 説明: オプション ``weight_type`` を"manual"と設定した際に設定できます。 - それ以外の指定では、このオプションは計算に反映されません。目的関数値を計算するときの、データ列ごとの重みを設定します。また、このオプションで指定された重みは総和が1になります。 + 説明: 目的関数値を計算するときの、データ列ごとの重みを設定します。総和が1になるように自動的に規格化されます。 例えば、[3,2,1]を指定すると、 :math:`w^{(1)}=1/2, w^{(2)}=1/3, w^{(3)}=1/6` となります。 -- ``Rfactor_type`` - - 形式: string型。"A"、"A2"または"B"のいずれかをとります。 (default: "A") - - 説明: 目的関数値の計算方法の指定。 - 実験・計算のデータベクトルを、それぞれ :math:`u^{(n)} = (u^{(n)}_{1}, u^{(n)}_{2},...,u^{(n)}_{m})`, :math:`v^{(n)} = (v^{(n)}_{1}, v^{(n)}_{2},...,v^{(n)}_{m})` と書くとします。 - また、各データ列の重みを :math:`w^{(n)}` とします。:math:`n` はデータ列のindexです( :math:`n = 1,2,3..` )。 - "A"タイプを指定すると、目的関数値は :math:`R = [ \sum_{j}^{n} w^{(j)} \{ \sum_{i}^{m} (u^{(j)}_{i}-v^{(j)}_{i})^{2} \} ]^{1/2}` - で計算されるRファクター値となります。 - "A2"タイプを指定すると、目的関数値は :math:`R^{2} = \sum_{j}^{n} w^{(j)} \{ \sum_{i}^{m} (u^{(j)}_{i}-v^{(j)}_{i})^{2} \}` - で計算されるRファクターの二乗の値となります。 - "B"タイプを指定すると、目的関数値は :math:`R = (\sum_{i}^{m} (u^{(1)}_{i}-v^{(1)}_{i})^{2})^{1/2}/( \sum_{i}^{m} (u^{(1)}_{i})^{2} + \sum_{i}^{m} (v^{(1)}_{i})^2)` - で計算されるRファクター値となります。 - "B"タイプはデータ列が1つの実験・計算データを用いた実行( :math:`n=1` )のみ対応しています。 - - ``omega`` 形式: 実数型 (default: 0.5) @@ -261,7 +291,8 @@ ``generate_rocking_curve`` ([``solver``] セクション) が"true"の場合のみ ``Log%%%%%_#####`` フォルダに出力されます。 -ファイル冒頭には文頭に ``#`` が付いたヘッダーが記されます。ヘッダーには探索変数の値、目的関数値 ``f(x)`` オプションで指定した ``Rfactor_type`` ``normalization` ``weight_type`` ``cal_number`` 、オプションで指定またはプログラムが計算したデータ列ごとの重み ``spot_weight`` 、データ部分の列に何が記されているか( ``# 0 glanceing_angle`` など)が記されています。 +ファイル冒頭、 ``#`` で始まる行はヘッダーです。 +ヘッダーには探索変数の値、目的関数値 ``f(x)`` オプションで指定した ``Rfactor_type``, ``normalization`, ``weight_type``, ``cal_number``, オプションで指定またはプログラムが計算したデータ列ごとの重み ``spot_weight``, データ部分のどの列に何が記されているか(例: ``# #0 glanceing_angle`` など)が記されています。 ``#`` が付いていない部分はデータ表記部分になります。1列目は視写角、2列目以降はデータ列ごとに強度が記しています。どのデータ列が記されているかはヘッダーの表記で確認できます。例えば diff --git a/doc/ja/source/tutorial/limitation.rst b/doc/ja/source/tutorial/limitation.rst index dd53f3be..8ad1a8f4 100644 --- a/doc/ja/source/tutorial/limitation.rst +++ b/doc/ja/source/tutorial/limitation.rst @@ -69,7 +69,6 @@ ``[algorithm]`` セクションは用いる探索アルゴリズムを設定します。 交換モンテカルロ法を用いる場合には、 ``name`` に ``"exchange"`` を指定します。 -``label_list`` は、``value_0x`` (x=1,2) を出力する際につけるラベル名のリストです。 ``seed`` は擬似乱数生成器に与える種です。 ``[algorithm.param]`` サブセクションは、最適化したいパラメータの範囲などを指定します。 diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index e27838bc..c8430c03 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -428,7 +428,7 @@ def __init__(self, info, isLogmode, detail_timer): available_normalization = ["TOTAL", "MANY_BEAM"] if v == "MAX": raise exception.InputError( - 'ERROR: normalization == "MAX" is not available' + 'ERROR: normalization == "MAX" is no longer available' ) if v not in available_normalization: msg = "ERROR: normalization must be " From 3366b6bed57b0678226a3fceb7f890d213512160 Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Wed, 28 Feb 2024 16:22:58 +0900 Subject: [PATCH 54/67] update samples --- sample/sim-trhepd-rheed/bayes/input.toml | 12 +++---- sample/sim-trhepd-rheed/exchange/input.toml | 12 +++---- sample/sim-trhepd-rheed/mapper/input.toml | 12 +++---- sample/sim-trhepd-rheed/minsearch/input.toml | 12 +++---- sample/sim-trhepd-rheed/pamc/input.toml | 33 ++++++++++---------- 5 files changed, 41 insertions(+), 40 deletions(-) diff --git a/sample/sim-trhepd-rheed/bayes/input.toml b/sample/sim-trhepd-rheed/bayes/input.toml index 81c8d4cd..14e7a366 100644 --- a/sample/sim-trhepd-rheed/bayes/input.toml +++ b/sample/sim-trhepd-rheed/bayes/input.toml @@ -3,20 +3,20 @@ dimension = 2 [solver] name = "sim-trhepd-rheed" +run_scheme = "subprocess" [solver.config] -calculated_first_line = 5 -calculated_last_line = 74 -row_number = 2 +cal_number = [1] [solver.param] string_list = ["value_01", "value_02" ] -degree_max = 7.0 + +[solver.post] +normalization = "TOTAL" [solver.reference] path = "experiment.txt" -first = 1 -last = 70 +exp_number = [1] [algorithm] name = "bayes" diff --git a/sample/sim-trhepd-rheed/exchange/input.toml b/sample/sim-trhepd-rheed/exchange/input.toml index 2240b0bb..6260334e 100644 --- a/sample/sim-trhepd-rheed/exchange/input.toml +++ b/sample/sim-trhepd-rheed/exchange/input.toml @@ -19,17 +19,17 @@ Tlogspace = true [solver] name = "sim-trhepd-rheed" +run_scheme = "subprocess" [solver.config] -calculated_first_line = 5 -calculated_last_line = 74 -row_number = 2 +cal_number = [1] [solver.param] string_list = ["value_01", "value_02" ] -degree_max = 7.0 [solver.reference] path = "experiment.txt" -first = 1 -last = 70 +exp_number = [1] + +[solver.post] +normalization = "TOTAL" diff --git a/sample/sim-trhepd-rheed/mapper/input.toml b/sample/sim-trhepd-rheed/mapper/input.toml index e67e5066..877387e8 100644 --- a/sample/sim-trhepd-rheed/mapper/input.toml +++ b/sample/sim-trhepd-rheed/mapper/input.toml @@ -3,20 +3,20 @@ dimension = 2 [solver] name = "sim-trhepd-rheed" +run_scheme = "subprocess" [solver.config] -calculated_first_line = 5 -calculated_last_line = 74 -row_number = 2 +cal_number = [1] [solver.param] string_list = ["value_01", "value_02" ] -degree_max = 7.0 + +[solver.post] +normalization = "TOTAL" [solver.reference] path = "experiment.txt" -first = 1 -last = 70 +exp_number = [1] [algorithm] name = "mapper" diff --git a/sample/sim-trhepd-rheed/minsearch/input.toml b/sample/sim-trhepd-rheed/minsearch/input.toml index 61b34835..031a0bc9 100644 --- a/sample/sim-trhepd-rheed/minsearch/input.toml +++ b/sample/sim-trhepd-rheed/minsearch/input.toml @@ -3,20 +3,20 @@ dimension = 3 [solver] name = "sim-trhepd-rheed" +run_scheme = "subprocess" [solver.config] -calculated_first_line = 5 -calculated_last_line = 74 -row_number = 2 +cal_number = [1] [solver.param] string_list = ["value_01", "value_02", "value_03" ] -degree_max = 7.0 [solver.reference] path = "experiment.txt" -first = 1 -last = 70 +exp_number = [1] + +[solver.post] +normalization = "TOTAL" [algorithm] name = "minsearch" diff --git a/sample/sim-trhepd-rheed/pamc/input.toml b/sample/sim-trhepd-rheed/pamc/input.toml index 2a666a8d..d16d54a4 100644 --- a/sample/sim-trhepd-rheed/pamc/input.toml +++ b/sample/sim-trhepd-rheed/pamc/input.toml @@ -2,6 +2,23 @@ dimension = 2 output_dir = "output" +[solver] +name = "sim-trhepd-rheed" +run_scheme = "subprocess" + +[solver.config] +cal_number = [1] + +[solver.param] +string_list = ["value_01", "value_02" ] + +[solver.post] +normalization = "TOTAL" + +[solver.reference] +path = "experiment.txt" +exp_number = [1] + [algorithm] name = "pamc" label_list = ["z1", "z2"] @@ -20,19 +37,3 @@ Tnum = 21 Tlogspace = false nreplica_per_proc = 10 -[solver] -name = "sim-trhepd-rheed" - -[solver.config] -calculated_first_line = 5 -calculated_last_line = 74 -row_number = 2 - -[solver.param] -string_list = ["value_01", "value_02" ] -degree_max = 7.0 - -[solver.reference] -path = "experiment.txt" -first = 1 -last = 70 From 3aecea4ec854de6fcd44b1380a34ed38c6f790af Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Wed, 28 Feb 2024 16:23:10 +0900 Subject: [PATCH 55/67] update error messages --- src/py2dmat/solver/sim_trhepd_rheed.py | 61 +++++++++++++------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index c8430c03..be477317 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -38,10 +38,9 @@ def __init__(self, info: py2dmat.Info): self.run_scheme = info.solver.get("run_scheme", "") scheme_list = ["subprocess", "connect_so"] - scheme_judge = [i == self.run_scheme for i in scheme_list] - if not any(scheme_judge): - raise exception.InputError("ERROR : Input scheme is incorrect.") + if self.run_scheme not in scheme_list: + raise exception.InputError("ERROR : solver.run_scheme should be 'subprocess' or 'connect_so'.") if self.run_scheme == "connect_so": self.load_so() @@ -428,10 +427,10 @@ def __init__(self, info, isLogmode, detail_timer): available_normalization = ["TOTAL", "MANY_BEAM"] if v == "MAX": raise exception.InputError( - 'ERROR: normalization == "MAX" is no longer available' + 'ERROR: solver.post.normalization == "MAX" is no longer available' ) if v not in available_normalization: - msg = "ERROR: normalization must be " + msg = "ERROR: solver.post.normalization must be " msg += "MANY_BEAM or TOTAL" raise exception.InputError(msg) self.normalization = v @@ -440,18 +439,18 @@ def __init__(self, info, isLogmode, detail_timer): available_weight_type = ["calc", "manual"] if self.normalization == "MANY_BEAM": if v is None: - msg = 'ERROR: If normalization = "MANY_BEAM", ' + msg = 'ERROR: If solver.post.normalization = "MANY_BEAM", ' msg += '"weight_type" must be set in [solver.post].' raise exception.InputError(msg) elif v not in available_weight_type: - msg = "ERROR: weight_type must be " + msg = "ERROR: solver.post.weight_type must be " msg += "calc or manual" raise exception.InputError(msg) else: if v is not None: if self.mpirank == 0: - msg = 'NOTICE: If normalization = "MANY_BEAM" is not set, ' - msg += '"weight_type" is NOT considered in the calculation.' + msg = 'NOTICE: If solver.post.normalization = "MANY_BEAM" is not set, ' + msg += '"solver.post.weight_type" is NOT considered in the calculation.' print(msg) self.weight_type = None self.weight_type = v @@ -459,15 +458,15 @@ def __init__(self, info, isLogmode, detail_timer): v = info_post.get("spot_weight", []) if self.normalization == "MANY_BEAM" and self.weight_type == "manual": if v == []: - msg = 'ERROR: With normalization="MANY_BEAM" and ' - msg += 'weight_type=="manual", the "spot_weight" option ' + msg = 'ERROR: With solver.post.normalization="MANY_BEAM" and ' + msg += 'solver.post.weight_type=="manual", the "spot_weight" option ' msg += "must be set in [solver.post]." raise exception.InputError(msg) self.spot_weight = np.array(v) / sum(v) else: if v != []: if self.mpirank == 0: - msg = 'NOTICE: With the specified "normalization" option, ' + msg = 'NOTICE: With the specified "solver.post.normalization" option, ' msg += 'the "spot_weight" you specify in the toml file is ignored, ' msg += "since the spot_weight is automatically calculated within the program." print(msg) @@ -476,11 +475,11 @@ def __init__(self, info, isLogmode, detail_timer): v = info_post.get("Rfactor_type", "A") if v not in ["A", "B", "A2"]: - raise exception.InputError("ERROR: Rfactor_type must be A, A2 or B") + raise exception.InputError("ERROR: solver.post.Rfactor_type must be A, A2 or B") if self.normalization == "MANY_BEAM": if (v != "A") and (v != "A2"): - msg = 'With normalization="MANY_BEAM", ' - msg += 'only Rfactor_type="A" or Rfactor_type="A2" is valid.' + msg = 'With solver.post.normalization="MANY_BEAM", ' + msg += 'only solver.post.Rfactor_type="A" or "A2" is valid.' raise exception.InputError(msg) self.Rfactor_type = v @@ -533,24 +532,24 @@ def __init__(self, info, isLogmode, detail_timer): v = info_ref.get("exp_number", []) if len(v) == 0: - raise exception.InputError("ERROR: You have to set the 'exp_number'.") + raise exception.InputError("ERROR: You have to set the 'solver.reference.exp_number'.") if not isinstance(v, list): - raise exception.InputError("ERROR: 'exp_number' must be a list type.") + raise exception.InputError("ERROR: 'solver.reference.exp_number' must be a list type.") if max(v) > self.beam_number_exp_raw: - raise exception.InputError("ERROR: The 'exp_number' setting is wrong.") + raise exception.InputError("ERROR: The 'solver.reference.exp_number' setting is wrong.") if self.normalization == "MANY_BEAM" and self.weight_type == "manual": if len(v) != len(self.spot_weight): raise exception.InputError( - "ERROR:len('exp_number') and len('spot_weight') do not match." + "ERROR:len('solver.reference.exp_number') and len('solver.post.spot_weight') do not match." ) if self.normalization == "TOTAL" and len(v) != 1: - msg = 'When normalization=="TOTAL" is specified, ' + msg = 'When solver.post.normalization=="TOTAL" is specified, ' msg += "only one beam data can be specified with " - msg += '"exp_number" option.' + msg += '"solver.reference.exp_number" option.' raise exception.InputError(msg) self.exp_number = v @@ -596,7 +595,7 @@ def __init__(self, info, isLogmode, detail_timer): [[self.I_reference_normalized_l], [I_reference_normalized]] ) else: - msg = "ERROR: normalization must be " + msg = "ERROR: solver.post.normalization must be " msg += "MANY_BEAM or TOTAL" raise exception.InputError(msg) @@ -609,7 +608,7 @@ def __init__(self, info, isLogmode, detail_timer): v = info_config.get("calculated_first_line", 5) if not (isinstance(v, int) and v >= 0): raise exception.InputError( - "ERROR: calculated_first_line should be non-negative integer" + "ERROR: solver.config.calculated_first_line should be non-negative integer" ) self.calculated_first_line = v @@ -619,7 +618,7 @@ def __init__(self, info, isLogmode, detail_timer): ) if not (isinstance(v, int) and v >= 0): raise exception.InputError( - "ERROR: calculated_last_line should be non-negative integer" + "ERROR: solver.config.calculated_last_line should be non-negative integer" ) self.calculated_last_line = v @@ -643,26 +642,26 @@ def __init__(self, info, isLogmode, detail_timer): v = info_config.get("calculated_info_line", 2) if not (isinstance(v, int) and v >= 0): raise exception.InputError( - "ERROR: calculated_info_line should be non-negative integer" + "ERROR: solver.config.calculated_info_line should be non-negative integer" ) self.calculated_info_line = v v = info_config.get("cal_number", []) if len(v) == 0: - raise exception.InputError("ERROR: You have to set the 'cal_number'.") + raise exception.InputError("ERROR: You have to set the 'solver.config.cal_number'.") if not isinstance(v, list): - raise exception.InputError("ERROR: 'cal_number' must be a list type.") + raise exception.InputError("ERROR: 'solver.config.cal_number' must be a list type.") if self.normalization == "MANY_BEAM" and self.weight_type == "manual": if len(self.spot_weight) != len(v): raise exception.InputError( - "len('cal_number') and len('spot_weight') do not match." + "len('solver.config.cal_number') and len('solver.post.spot_weight') do not match." ) if self.normalization == "TOTAL" and len(v) != 1: - msg = 'When normalization=="TOTAL" is specified, ' + msg = 'When solver.post.normalization=="TOTAL" is specified, ' msg += "only one beam data can be specified with " - msg += '"cal_number" option.' + msg += '"solver.config.cal_number" option.' raise exception.InputError(msg) self.cal_number = v @@ -957,7 +956,7 @@ def _calc_I_from_file(self): ] ) else: - msg = "ERROR: normalization must be " + msg = "ERROR: solver.post.normalization must be " msg += "MANY_BEAM or TOTAL" raise exception.InputError(msg) From 0fbcf9c897708482e4f5c8f1273456ba1eb09de5 Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Wed, 13 Mar 2024 14:01:21 +0900 Subject: [PATCH 56/67] set run_scheme=subprocess as default for sim-trhepd-rheed --- src/py2dmat/solver/sim_trhepd_rheed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index be477317..6effbf05 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -36,7 +36,7 @@ def __init__(self, info: py2dmat.Info): self._name = "sim_trhepd_rheed_mb_connect" - self.run_scheme = info.solver.get("run_scheme", "") + self.run_scheme = info.solver.get("run_scheme", "subprocess") scheme_list = ["subprocess", "connect_so"] if self.run_scheme not in scheme_list: From 0b2014ee9c837efd0d038bf5004810822c7e359a Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Wed, 13 Mar 2024 14:10:37 +0900 Subject: [PATCH 57/67] move STR manybeam samples --- .../many_beam/mapper_weight_calc}/MeshData.txt | 0 .../many_beam/mapper_weight_calc}/bulk.txt | 0 .../many_beam/mapper_weight_calc}/experiment.txt | 0 .../many_beam/mapper_weight_calc}/input.toml | 0 .../many_beam/mapper_weight_calc}/ref_ColorMap.txt | 0 .../many_beam/mapper_weight_calc}/template.txt | 0 .../many_beam/mapper_weight_manual}/MeshData.txt | 0 .../many_beam/mapper_weight_manual}/bulk.txt | 0 .../many_beam/mapper_weight_manual}/experiment.txt | 0 .../many_beam/mapper_weight_manual}/input.toml | 0 .../many_beam/mapper_weight_manual}/ref_ColorMap.txt | 0 .../many_beam/mapper_weight_manual}/template.txt | 0 .../many_beam/minsearch_weight_calc}/bulk.txt | 0 .../many_beam/minsearch_weight_calc}/experiment.txt | 0 .../many_beam/minsearch_weight_calc}/input.toml | 0 .../many_beam/minsearch_weight_calc}/ref.txt | 0 .../many_beam/minsearch_weight_calc}/template.txt | 0 .../many_beam/minsearch_weight_manual}/bulk.txt | 0 .../many_beam/minsearch_weight_manual}/experiment.txt | 0 .../many_beam/minsearch_weight_manual}/input.toml | 0 .../many_beam/minsearch_weight_manual}/ref.txt | 0 .../many_beam/minsearch_weight_manual}/template.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/bayes/MeshData.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/bayes/bulk.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/bayes/do.sh | 0 sample/sim-trhepd-rheed/{ => single_beam}/bayes/experiment.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/bayes/input.toml | 0 sample/sim-trhepd-rheed/{ => single_beam}/bayes/prepare.sh | 0 sample/sim-trhepd-rheed/{ => single_beam}/bayes/ref_BayesData.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/bayes/template.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/exchange/bulk.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/exchange/do.sh | 0 sample/sim-trhepd-rheed/{ => single_beam}/exchange/experiment.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/exchange/input.toml | 0 .../sim-trhepd-rheed/{ => single_beam}/exchange/plot_result_2d.py | 0 sample/sim-trhepd-rheed/{ => single_beam}/exchange/prepare.sh | 0 sample/sim-trhepd-rheed/{ => single_beam}/exchange/ref.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/exchange/template.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/mapper/MeshData.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/mapper/bulk.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/mapper/do.sh | 0 sample/sim-trhepd-rheed/{ => single_beam}/mapper/experiment.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/mapper/input.toml | 0 .../sim-trhepd-rheed/{ => single_beam}/mapper/plot_colormap_2d.py | 0 sample/sim-trhepd-rheed/{ => single_beam}/mapper/prepare.sh | 0 sample/sim-trhepd-rheed/{ => single_beam}/mapper/ref_ColorMap.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/mapper/template.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/minsearch/bulk.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/minsearch/do.sh | 0 .../sim-trhepd-rheed/{ => single_beam}/minsearch/experiment.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/minsearch/input.toml | 0 sample/sim-trhepd-rheed/{ => single_beam}/minsearch/prepare.sh | 0 sample/sim-trhepd-rheed/{ => single_beam}/minsearch/ref.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/minsearch/template.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/pamc/bulk.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/pamc/do.sh | 0 sample/sim-trhepd-rheed/{ => single_beam}/pamc/experiment.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/pamc/input.toml | 0 sample/sim-trhepd-rheed/{ => single_beam}/pamc/plot_result_2d.py | 0 sample/sim-trhepd-rheed/{ => single_beam}/pamc/prepare.sh | 0 sample/sim-trhepd-rheed/{ => single_beam}/pamc/ref.txt | 0 sample/sim-trhepd-rheed/{ => single_beam}/pamc/template.txt | 0 62 files changed, 0 insertions(+), 0 deletions(-) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm => sim-trhepd-rheed/many_beam/mapper_weight_calc}/MeshData.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm => sim-trhepd-rheed/many_beam/mapper_weight_calc}/bulk.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm => sim-trhepd-rheed/many_beam/mapper_weight_calc}/experiment.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm => sim-trhepd-rheed/many_beam/mapper_weight_calc}/input.toml (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm => sim-trhepd-rheed/many_beam/mapper_weight_calc}/ref_ColorMap.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm => sim-trhepd-rheed/many_beam/mapper_weight_calc}/template.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/mapper_weight_manual}/MeshData.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/mapper_weight_manual}/bulk.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/mapper_weight_manual}/experiment.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/mapper_weight_manual}/input.toml (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/mapper_weight_manual}/ref_ColorMap.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/mapper_weight_manual}/template.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm => sim-trhepd-rheed/many_beam/minsearch_weight_calc}/bulk.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm => sim-trhepd-rheed/many_beam/minsearch_weight_calc}/experiment.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm => sim-trhepd-rheed/many_beam/minsearch_weight_calc}/input.toml (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm => sim-trhepd-rheed/many_beam/minsearch_weight_calc}/ref.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm => sim-trhepd-rheed/many_beam/minsearch_weight_calc}/template.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/minsearch_weight_manual}/bulk.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/minsearch_weight_manual}/experiment.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/minsearch_weight_manual}/input.toml (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/minsearch_weight_manual}/ref.txt (100%) rename sample/{sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt => sim-trhepd-rheed/many_beam/minsearch_weight_manual}/template.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/bayes/MeshData.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/bayes/bulk.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/bayes/do.sh (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/bayes/experiment.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/bayes/input.toml (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/bayes/prepare.sh (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/bayes/ref_BayesData.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/bayes/template.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/exchange/bulk.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/exchange/do.sh (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/exchange/experiment.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/exchange/input.toml (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/exchange/plot_result_2d.py (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/exchange/prepare.sh (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/exchange/ref.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/exchange/template.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/mapper/MeshData.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/mapper/bulk.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/mapper/do.sh (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/mapper/experiment.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/mapper/input.toml (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/mapper/plot_colormap_2d.py (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/mapper/prepare.sh (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/mapper/ref_ColorMap.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/mapper/template.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/minsearch/bulk.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/minsearch/do.sh (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/minsearch/experiment.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/minsearch/input.toml (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/minsearch/prepare.sh (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/minsearch/ref.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/minsearch/template.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/pamc/bulk.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/pamc/do.sh (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/pamc/experiment.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/pamc/input.toml (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/pamc/plot_result_2d.py (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/pamc/prepare.sh (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/pamc/ref.txt (100%) rename sample/sim-trhepd-rheed/{ => single_beam}/pamc/template.txt (100%) diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/MeshData.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/MeshData.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/MeshData.txt rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/MeshData.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/bulk.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/bulk.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/bulk.txt rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/bulk.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/experiment.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/experiment.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/experiment.txt rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/experiment.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/input.toml b/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/input.toml similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/input.toml rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/input.toml diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/ref_ColorMap.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/ref_ColorMap.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/ref_ColorMap.txt rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/ref_ColorMap.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/template.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/template.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm/template.txt rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/template.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/MeshData.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/MeshData.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/MeshData.txt rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/MeshData.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/bulk.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/bulk.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/bulk.txt rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/bulk.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/experiment.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/experiment.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/experiment.txt rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/experiment.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/input.toml b/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/input.toml similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/input.toml rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/input.toml diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/ref_ColorMap.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/ref_ColorMap.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/ref_ColorMap.txt rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/ref_ColorMap.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/template.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/template.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/mapper_ms_norm_set_wgt/template.txt rename to sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/template.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/bulk.txt b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/bulk.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/bulk.txt rename to sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/bulk.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/experiment.txt b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/experiment.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/experiment.txt rename to sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/experiment.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/input.toml b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/input.toml similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/input.toml rename to sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/input.toml diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/ref.txt b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/ref.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/ref.txt rename to sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/ref.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/template.txt b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/template.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm/template.txt rename to sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/template.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/bulk.txt b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/bulk.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/bulk.txt rename to sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/bulk.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/experiment.txt b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/experiment.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/experiment.txt rename to sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/experiment.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/input.toml b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/input.toml similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/input.toml rename to sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/input.toml diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/ref.txt b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/ref.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/ref.txt rename to sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/ref.txt diff --git a/sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/template.txt b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/template.txt similarity index 100% rename from sample/sim-trhepd-rheed_mb_connect/manybeam/minsearch_ms_norm_set_wgt/template.txt rename to sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/template.txt diff --git a/sample/sim-trhepd-rheed/bayes/MeshData.txt b/sample/sim-trhepd-rheed/single_beam/bayes/MeshData.txt similarity index 100% rename from sample/sim-trhepd-rheed/bayes/MeshData.txt rename to sample/sim-trhepd-rheed/single_beam/bayes/MeshData.txt diff --git a/sample/sim-trhepd-rheed/bayes/bulk.txt b/sample/sim-trhepd-rheed/single_beam/bayes/bulk.txt similarity index 100% rename from sample/sim-trhepd-rheed/bayes/bulk.txt rename to sample/sim-trhepd-rheed/single_beam/bayes/bulk.txt diff --git a/sample/sim-trhepd-rheed/bayes/do.sh b/sample/sim-trhepd-rheed/single_beam/bayes/do.sh similarity index 100% rename from sample/sim-trhepd-rheed/bayes/do.sh rename to sample/sim-trhepd-rheed/single_beam/bayes/do.sh diff --git a/sample/sim-trhepd-rheed/bayes/experiment.txt b/sample/sim-trhepd-rheed/single_beam/bayes/experiment.txt similarity index 100% rename from sample/sim-trhepd-rheed/bayes/experiment.txt rename to sample/sim-trhepd-rheed/single_beam/bayes/experiment.txt diff --git a/sample/sim-trhepd-rheed/bayes/input.toml b/sample/sim-trhepd-rheed/single_beam/bayes/input.toml similarity index 100% rename from sample/sim-trhepd-rheed/bayes/input.toml rename to sample/sim-trhepd-rheed/single_beam/bayes/input.toml diff --git a/sample/sim-trhepd-rheed/bayes/prepare.sh b/sample/sim-trhepd-rheed/single_beam/bayes/prepare.sh similarity index 100% rename from sample/sim-trhepd-rheed/bayes/prepare.sh rename to sample/sim-trhepd-rheed/single_beam/bayes/prepare.sh diff --git a/sample/sim-trhepd-rheed/bayes/ref_BayesData.txt b/sample/sim-trhepd-rheed/single_beam/bayes/ref_BayesData.txt similarity index 100% rename from sample/sim-trhepd-rheed/bayes/ref_BayesData.txt rename to sample/sim-trhepd-rheed/single_beam/bayes/ref_BayesData.txt diff --git a/sample/sim-trhepd-rheed/bayes/template.txt b/sample/sim-trhepd-rheed/single_beam/bayes/template.txt similarity index 100% rename from sample/sim-trhepd-rheed/bayes/template.txt rename to sample/sim-trhepd-rheed/single_beam/bayes/template.txt diff --git a/sample/sim-trhepd-rheed/exchange/bulk.txt b/sample/sim-trhepd-rheed/single_beam/exchange/bulk.txt similarity index 100% rename from sample/sim-trhepd-rheed/exchange/bulk.txt rename to sample/sim-trhepd-rheed/single_beam/exchange/bulk.txt diff --git a/sample/sim-trhepd-rheed/exchange/do.sh b/sample/sim-trhepd-rheed/single_beam/exchange/do.sh similarity index 100% rename from sample/sim-trhepd-rheed/exchange/do.sh rename to sample/sim-trhepd-rheed/single_beam/exchange/do.sh diff --git a/sample/sim-trhepd-rheed/exchange/experiment.txt b/sample/sim-trhepd-rheed/single_beam/exchange/experiment.txt similarity index 100% rename from sample/sim-trhepd-rheed/exchange/experiment.txt rename to sample/sim-trhepd-rheed/single_beam/exchange/experiment.txt diff --git a/sample/sim-trhepd-rheed/exchange/input.toml b/sample/sim-trhepd-rheed/single_beam/exchange/input.toml similarity index 100% rename from sample/sim-trhepd-rheed/exchange/input.toml rename to sample/sim-trhepd-rheed/single_beam/exchange/input.toml diff --git a/sample/sim-trhepd-rheed/exchange/plot_result_2d.py b/sample/sim-trhepd-rheed/single_beam/exchange/plot_result_2d.py similarity index 100% rename from sample/sim-trhepd-rheed/exchange/plot_result_2d.py rename to sample/sim-trhepd-rheed/single_beam/exchange/plot_result_2d.py diff --git a/sample/sim-trhepd-rheed/exchange/prepare.sh b/sample/sim-trhepd-rheed/single_beam/exchange/prepare.sh similarity index 100% rename from sample/sim-trhepd-rheed/exchange/prepare.sh rename to sample/sim-trhepd-rheed/single_beam/exchange/prepare.sh diff --git a/sample/sim-trhepd-rheed/exchange/ref.txt b/sample/sim-trhepd-rheed/single_beam/exchange/ref.txt similarity index 100% rename from sample/sim-trhepd-rheed/exchange/ref.txt rename to sample/sim-trhepd-rheed/single_beam/exchange/ref.txt diff --git a/sample/sim-trhepd-rheed/exchange/template.txt b/sample/sim-trhepd-rheed/single_beam/exchange/template.txt similarity index 100% rename from sample/sim-trhepd-rheed/exchange/template.txt rename to sample/sim-trhepd-rheed/single_beam/exchange/template.txt diff --git a/sample/sim-trhepd-rheed/mapper/MeshData.txt b/sample/sim-trhepd-rheed/single_beam/mapper/MeshData.txt similarity index 100% rename from sample/sim-trhepd-rheed/mapper/MeshData.txt rename to sample/sim-trhepd-rheed/single_beam/mapper/MeshData.txt diff --git a/sample/sim-trhepd-rheed/mapper/bulk.txt b/sample/sim-trhepd-rheed/single_beam/mapper/bulk.txt similarity index 100% rename from sample/sim-trhepd-rheed/mapper/bulk.txt rename to sample/sim-trhepd-rheed/single_beam/mapper/bulk.txt diff --git a/sample/sim-trhepd-rheed/mapper/do.sh b/sample/sim-trhepd-rheed/single_beam/mapper/do.sh similarity index 100% rename from sample/sim-trhepd-rheed/mapper/do.sh rename to sample/sim-trhepd-rheed/single_beam/mapper/do.sh diff --git a/sample/sim-trhepd-rheed/mapper/experiment.txt b/sample/sim-trhepd-rheed/single_beam/mapper/experiment.txt similarity index 100% rename from sample/sim-trhepd-rheed/mapper/experiment.txt rename to sample/sim-trhepd-rheed/single_beam/mapper/experiment.txt diff --git a/sample/sim-trhepd-rheed/mapper/input.toml b/sample/sim-trhepd-rheed/single_beam/mapper/input.toml similarity index 100% rename from sample/sim-trhepd-rheed/mapper/input.toml rename to sample/sim-trhepd-rheed/single_beam/mapper/input.toml diff --git a/sample/sim-trhepd-rheed/mapper/plot_colormap_2d.py b/sample/sim-trhepd-rheed/single_beam/mapper/plot_colormap_2d.py similarity index 100% rename from sample/sim-trhepd-rheed/mapper/plot_colormap_2d.py rename to sample/sim-trhepd-rheed/single_beam/mapper/plot_colormap_2d.py diff --git a/sample/sim-trhepd-rheed/mapper/prepare.sh b/sample/sim-trhepd-rheed/single_beam/mapper/prepare.sh similarity index 100% rename from sample/sim-trhepd-rheed/mapper/prepare.sh rename to sample/sim-trhepd-rheed/single_beam/mapper/prepare.sh diff --git a/sample/sim-trhepd-rheed/mapper/ref_ColorMap.txt b/sample/sim-trhepd-rheed/single_beam/mapper/ref_ColorMap.txt similarity index 100% rename from sample/sim-trhepd-rheed/mapper/ref_ColorMap.txt rename to sample/sim-trhepd-rheed/single_beam/mapper/ref_ColorMap.txt diff --git a/sample/sim-trhepd-rheed/mapper/template.txt b/sample/sim-trhepd-rheed/single_beam/mapper/template.txt similarity index 100% rename from sample/sim-trhepd-rheed/mapper/template.txt rename to sample/sim-trhepd-rheed/single_beam/mapper/template.txt diff --git a/sample/sim-trhepd-rheed/minsearch/bulk.txt b/sample/sim-trhepd-rheed/single_beam/minsearch/bulk.txt similarity index 100% rename from sample/sim-trhepd-rheed/minsearch/bulk.txt rename to sample/sim-trhepd-rheed/single_beam/minsearch/bulk.txt diff --git a/sample/sim-trhepd-rheed/minsearch/do.sh b/sample/sim-trhepd-rheed/single_beam/minsearch/do.sh similarity index 100% rename from sample/sim-trhepd-rheed/minsearch/do.sh rename to sample/sim-trhepd-rheed/single_beam/minsearch/do.sh diff --git a/sample/sim-trhepd-rheed/minsearch/experiment.txt b/sample/sim-trhepd-rheed/single_beam/minsearch/experiment.txt similarity index 100% rename from sample/sim-trhepd-rheed/minsearch/experiment.txt rename to sample/sim-trhepd-rheed/single_beam/minsearch/experiment.txt diff --git a/sample/sim-trhepd-rheed/minsearch/input.toml b/sample/sim-trhepd-rheed/single_beam/minsearch/input.toml similarity index 100% rename from sample/sim-trhepd-rheed/minsearch/input.toml rename to sample/sim-trhepd-rheed/single_beam/minsearch/input.toml diff --git a/sample/sim-trhepd-rheed/minsearch/prepare.sh b/sample/sim-trhepd-rheed/single_beam/minsearch/prepare.sh similarity index 100% rename from sample/sim-trhepd-rheed/minsearch/prepare.sh rename to sample/sim-trhepd-rheed/single_beam/minsearch/prepare.sh diff --git a/sample/sim-trhepd-rheed/minsearch/ref.txt b/sample/sim-trhepd-rheed/single_beam/minsearch/ref.txt similarity index 100% rename from sample/sim-trhepd-rheed/minsearch/ref.txt rename to sample/sim-trhepd-rheed/single_beam/minsearch/ref.txt diff --git a/sample/sim-trhepd-rheed/minsearch/template.txt b/sample/sim-trhepd-rheed/single_beam/minsearch/template.txt similarity index 100% rename from sample/sim-trhepd-rheed/minsearch/template.txt rename to sample/sim-trhepd-rheed/single_beam/minsearch/template.txt diff --git a/sample/sim-trhepd-rheed/pamc/bulk.txt b/sample/sim-trhepd-rheed/single_beam/pamc/bulk.txt similarity index 100% rename from sample/sim-trhepd-rheed/pamc/bulk.txt rename to sample/sim-trhepd-rheed/single_beam/pamc/bulk.txt diff --git a/sample/sim-trhepd-rheed/pamc/do.sh b/sample/sim-trhepd-rheed/single_beam/pamc/do.sh similarity index 100% rename from sample/sim-trhepd-rheed/pamc/do.sh rename to sample/sim-trhepd-rheed/single_beam/pamc/do.sh diff --git a/sample/sim-trhepd-rheed/pamc/experiment.txt b/sample/sim-trhepd-rheed/single_beam/pamc/experiment.txt similarity index 100% rename from sample/sim-trhepd-rheed/pamc/experiment.txt rename to sample/sim-trhepd-rheed/single_beam/pamc/experiment.txt diff --git a/sample/sim-trhepd-rheed/pamc/input.toml b/sample/sim-trhepd-rheed/single_beam/pamc/input.toml similarity index 100% rename from sample/sim-trhepd-rheed/pamc/input.toml rename to sample/sim-trhepd-rheed/single_beam/pamc/input.toml diff --git a/sample/sim-trhepd-rheed/pamc/plot_result_2d.py b/sample/sim-trhepd-rheed/single_beam/pamc/plot_result_2d.py similarity index 100% rename from sample/sim-trhepd-rheed/pamc/plot_result_2d.py rename to sample/sim-trhepd-rheed/single_beam/pamc/plot_result_2d.py diff --git a/sample/sim-trhepd-rheed/pamc/prepare.sh b/sample/sim-trhepd-rheed/single_beam/pamc/prepare.sh similarity index 100% rename from sample/sim-trhepd-rheed/pamc/prepare.sh rename to sample/sim-trhepd-rheed/single_beam/pamc/prepare.sh diff --git a/sample/sim-trhepd-rheed/pamc/ref.txt b/sample/sim-trhepd-rheed/single_beam/pamc/ref.txt similarity index 100% rename from sample/sim-trhepd-rheed/pamc/ref.txt rename to sample/sim-trhepd-rheed/single_beam/pamc/ref.txt diff --git a/sample/sim-trhepd-rheed/pamc/template.txt b/sample/sim-trhepd-rheed/single_beam/pamc/template.txt similarity index 100% rename from sample/sim-trhepd-rheed/pamc/template.txt rename to sample/sim-trhepd-rheed/single_beam/pamc/template.txt From 3c36082dfc6e3694ce6ab7319f21fe6850fee705 Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Wed, 13 Mar 2024 14:13:37 +0900 Subject: [PATCH 58/67] fix script --- sample/sim-trhepd-rheed/single_beam/bayes/do.sh | 2 +- sample/sim-trhepd-rheed/single_beam/exchange/do.sh | 2 +- sample/sim-trhepd-rheed/single_beam/mapper/do.sh | 2 +- sample/sim-trhepd-rheed/single_beam/minsearch/do.sh | 2 +- sample/sim-trhepd-rheed/single_beam/pamc/do.sh | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sample/sim-trhepd-rheed/single_beam/bayes/do.sh b/sample/sim-trhepd-rheed/single_beam/bayes/do.sh index 3e6b5b27..ce2dc7bc 100644 --- a/sample/sim-trhepd-rheed/single_beam/bayes/do.sh +++ b/sample/sim-trhepd-rheed/single_beam/bayes/do.sh @@ -2,7 +2,7 @@ sh prepare.sh ./bulk.exe -time python3 ../../../src/py2dmat_main.py input.toml +time python3 ../../../../src/py2dmat_main.py input.toml echo diff BayesData.txt ref_BayesData.txt res=0 diff --git a/sample/sim-trhepd-rheed/single_beam/exchange/do.sh b/sample/sim-trhepd-rheed/single_beam/exchange/do.sh index 5e3ea1f3..f23ec020 100644 --- a/sample/sim-trhepd-rheed/single_beam/exchange/do.sh +++ b/sample/sim-trhepd-rheed/single_beam/exchange/do.sh @@ -2,7 +2,7 @@ sh prepare.sh ./bulk.exe -time mpiexec --oversubscribe -np 4 python3 ../../../src/py2dmat_main.py input.toml +time mpiexec --oversubscribe -np 4 python3 ../../../../src/py2dmat_main.py input.toml echo diff best_result.txt ref.txt res=0 diff --git a/sample/sim-trhepd-rheed/single_beam/mapper/do.sh b/sample/sim-trhepd-rheed/single_beam/mapper/do.sh index a1b9afbe..93e021d8 100644 --- a/sample/sim-trhepd-rheed/single_beam/mapper/do.sh +++ b/sample/sim-trhepd-rheed/single_beam/mapper/do.sh @@ -2,7 +2,7 @@ sh prepare.sh ./bulk.exe -time python3 ../../../src/py2dmat_main.py input.toml +time python3 ../../../../src/py2dmat_main.py input.toml echo diff ColorMap.txt ref_ColorMap.txt res=0 diff --git a/sample/sim-trhepd-rheed/single_beam/minsearch/do.sh b/sample/sim-trhepd-rheed/single_beam/minsearch/do.sh index 0318f8ab..121237c7 100644 --- a/sample/sim-trhepd-rheed/single_beam/minsearch/do.sh +++ b/sample/sim-trhepd-rheed/single_beam/minsearch/do.sh @@ -2,7 +2,7 @@ sh ./prepare.sh ./bulk.exe -time python3 ../../../src/py2dmat_main.py input.toml | tee log.txt +time python3 ../../../../src/py2dmat_main.py input.toml | tee log.txt echo diff res.txt ref.txt res=0 diff --git a/sample/sim-trhepd-rheed/single_beam/pamc/do.sh b/sample/sim-trhepd-rheed/single_beam/pamc/do.sh index ed07aead..088c9c65 100644 --- a/sample/sim-trhepd-rheed/single_beam/pamc/do.sh +++ b/sample/sim-trhepd-rheed/single_beam/pamc/do.sh @@ -2,7 +2,7 @@ sh prepare.sh ./bulk.exe -time mpiexec --oversubscribe -np 4 python3 ../../../src/py2dmat_main.py input.toml +time mpiexec --oversubscribe -np 4 python3 ../../../../src/py2dmat_main.py input.toml echo diff output/fx.txt ref.txt res=0 From b17831d6e6b42bc612f09b317b5f24d79b27b229 Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Wed, 13 Mar 2024 14:21:19 +0900 Subject: [PATCH 59/67] update tutorials (fix file paths) --- doc/en/source/tutorial/bayes.rst | 12 ++++++------ doc/en/source/tutorial/exchange.rst | 14 +++++++------- doc/en/source/tutorial/minsearch.rst | 14 +++++++------- doc/en/source/tutorial/mpi.rst | 12 ++++++------ doc/en/source/tutorial/pamc.rst | 12 ++++++------ doc/ja/source/tutorial/bayes.rst | 10 +++++----- doc/ja/source/tutorial/exchange.rst | 14 +++++++------- doc/ja/source/tutorial/minsearch.rst | 14 +++++++------- doc/ja/source/tutorial/mpi.rst | 12 ++++++------ doc/ja/source/tutorial/pamc.rst | 10 +++++----- 10 files changed, 62 insertions(+), 62 deletions(-) diff --git a/doc/en/source/tutorial/bayes.rst b/doc/en/source/tutorial/bayes.rst index bcf80073..bc5c1370 100644 --- a/doc/en/source/tutorial/bayes.rst +++ b/doc/en/source/tutorial/bayes.rst @@ -7,7 +7,7 @@ This tutorial subscribes how to estimate atomic positions from the experimental Sample files ~~~~~~~~~~~~~~~~~~~~~~~~ -Sample files are available from ``sample/sim-trhepd-rheed/bayes`` . +Sample files are available from ``sample/sim-trhepd-rheed/single_beam/bayes`` . This directory includes the following files: - ``bulk.txt`` @@ -123,14 +123,14 @@ First, move to the folder where the sample file is located (hereinafter, it is a .. code-block:: - cd sample/sim-trhepd-rheed/bayes + cd sample/sim-trhepd-rheed/single_beam/bayes Copy ``bulk.exe`` and ``surf.exe`` as the tutorial for the direct problem. .. code-block:: - cp ../../../../sim-trhepd-rheed/src/TRHEPD/bulk.exe . - cp ../../../../sim-trhepd-rheed/src/TRHEPD/surf.exe . + cp ../../../../../sim-trhepd-rheed/src/TRHEPD/bulk.exe . + cp ../../../../../sim-trhepd-rheed/src/TRHEPD/surf.exe . Execute ``bulk.exe`` to generate ``bulkP.b`` . @@ -142,7 +142,7 @@ Then, run the main program (it takes a few secondes) .. code-block:: - python3 ../../../src/py2dmat_main.py input.toml | tee log.txt + python3 ../../../../src/py2dmat_main.py input.toml | tee log.txt This makes a directory with the name of ``0`` . The following standard output will be shown: @@ -216,7 +216,7 @@ I will omit the explanation below, but I will post the contents. ./bulk.exe - time python3 ../../../src/py2dmat_main.py input.toml + time python3 ../../../../src/py2dmat_main.py input.toml echo diff BayesData.txt ref_BayesData.txt res=0 diff --git a/doc/en/source/tutorial/exchange.rst b/doc/en/source/tutorial/exchange.rst index 6d1b13af..e6dce52c 100644 --- a/doc/en/source/tutorial/exchange.rst +++ b/doc/en/source/tutorial/exchange.rst @@ -6,7 +6,7 @@ This tutorial subscribes how to estimate atomic positions from the experimental Sample files ~~~~~~~~~~~~~~~~~~ -Sample files are available from ``sample/sim-trhepd-rheed/exchange`` . +Sample files are available from ``sample/sim-trhepd-rheed/single_beam/exchange`` . This directory includes the following files: - ``bulk.txt`` @@ -126,14 +126,14 @@ First, move to the folder where the sample file is located (hereinafter, it is a .. code-block:: - cd sample/sim-trhepd-rheed/exchange + cd sample/sim-trhepd-rheed/single_beam/exchange Copy ``bulk.exe`` and ``surf.exe`` as the tutorial for the direct problem. .. code-block:: - cp ../../../../sim-trhepd-rheed/src/TRHEPD/bulk.exe . - cp ../../../../sim-trhepd-rheed/src/TRHEPD/surf.exe . + cp ../../../../../sim-trhepd-rheed/src/TRHEPD/bulk.exe . + cp ../../../../../sim-trhepd-rheed/src/TRHEPD/surf.exe . Execute ``bulk.exe`` to generate ``bulkP.b`` . @@ -145,7 +145,7 @@ Then, run the main program (it takes a few secondes) .. code-block:: - mpiexec -np 4 python3 ../../../src/py2dmat_main.py input.toml | tee log.txt + mpiexec -np 4 python3 ../../../../src/py2dmat_main.py input.toml | tee log.txt Here, the calculation is performed using MPI parallel with 4 processes. @@ -187,7 +187,7 @@ I will omit the explanation below, but I will post the contents. ./bulk.exe - time mpiexec --oversubscribe -np 4 python3 ../../../src/py2dmat_main.py input.toml + time mpiexec --oversubscribe -np 4 python3 ../../../../src/py2dmat_main.py input.toml echo diff best_result.txt ref.txt res=0 @@ -207,7 +207,7 @@ The ``result.txt`` in each rank folder records the data sampled by each replica, .. code-block:: - python3 ../../../script/separateT.py + python3 ../../../../script/separateT.py The data reorganized for each temperature point is written to ``result_T%.txt`` (``%`` is the index of the temperature point). diff --git a/doc/en/source/tutorial/minsearch.rst b/doc/en/source/tutorial/minsearch.rst index 3a668f21..3d20a633 100644 --- a/doc/en/source/tutorial/minsearch.rst +++ b/doc/en/source/tutorial/minsearch.rst @@ -22,7 +22,7 @@ In the main program, the Nelder-Mead method (using `scipy.optimize.fmin Date: Wed, 13 Mar 2024 15:25:08 +0900 Subject: [PATCH 60/67] update samples --- .../many_beam/mapper_weight_calc/input.toml | 19 ++++-------------- .../mapper_weight_calc/ref_ColorMap.txt | 6 +++--- .../many_beam/mapper_weight_manual/input.toml | 18 ++++------------- .../mapper_weight_manual/ref_ColorMap.txt | 4 ++-- .../minsearch_weight_calc/input.toml | 15 ++++---------- .../many_beam/minsearch_weight_calc/ref.txt | 20 +++++++++---------- .../minsearch_weight_manual/input.toml | 17 ++++------------ .../many_beam/minsearch_weight_manual/ref.txt | 20 +++++++++---------- 8 files changed, 41 insertions(+), 78 deletions(-) diff --git a/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/input.toml b/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/input.toml index 228104b8..6e709c73 100644 --- a/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/input.toml +++ b/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/input.toml @@ -3,37 +3,26 @@ dimension = 9 output_dir = "output" [solver] -name = "sim-trhepd-rheed-mb_connect" +name = "sim-trhepd-rheed" run_scheme = "subprocess" generate_rocking_curve = false [solver.config] -#calculated_first_line =5 -#calculated_last_line = 65 -#row_number = 2 -surface_exec_file = "~/tool/sim-trhepd-rheed/src/surf.exe" -bulk_output_file = "bulkP.b" -surface_template_file = "template.txt" cal_number = [1, 2, 4, 6, 8] - [solver.post] -normalization = "MS_NORM" #"TOTAL" for Integration or "MAX" for MAX value -Rfactor_type = "A2" #"A" for Ichimiya's or "B" for Pendry's or "A2" for squared Weight + Ichimiya's +normalization = "MANY_BEAM" +weight_type = "calc" +Rfactor_type = "A2" omega = 0.5 remove_work_dir = false [solver.param] string_list = ["value_01", "value_02","value_03", "value_04","value_05", "value_06", "value_07","value_08", "value_09"] -#degree_max = 6.5 - [solver.reference] path = "experiment.txt" exp_number = [1, 2, 4, 6, 8] -#first =1 -#last = 63 - [algorithm] name = "mapper" diff --git a/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/ref_ColorMap.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/ref_ColorMap.txt index 81dd323e..ac721f98 100644 --- a/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/ref_ColorMap.txt +++ b/sample/sim-trhepd-rheed/many_beam/mapper_weight_calc/ref_ColorMap.txt @@ -4,7 +4,7 @@ 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.001807 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.001808 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.001948 -5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 0.002115 -5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 0.002115 +5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 0.002116 +5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 0.002116 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 0.002114 -5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 0.001927 +5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 0.001926 diff --git a/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/input.toml b/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/input.toml index d1aef925..fb533809 100644 --- a/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/input.toml +++ b/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/input.toml @@ -3,37 +3,27 @@ dimension = 9 output_dir = "output" [solver] -name = "sim-trhepd-rheed-mb_connect" +name = "sim-trhepd-rheed" run_scheme = "subprocess" generate_rocking_curve = false [solver.config] -#calculated_first_line =5 -#calculated_last_line = 65 -#row_number = 2 -surface_exec_file = "~/tool/sim-trhepd-rheed/src/surf.exe" -bulk_output_file = "bulkP.b" -surface_template_file = "template.txt" cal_number = [1, 2, 4, 6, 8] - [solver.post] -normalization = "MS_NORM_SET_WGT" #"TOTAL" for Integration or "MAX" for MAX value -Rfactor_type = "A2" #"A" for Ichimiya's or "B" for Pendry's or "A2" for squared Weight + Ichimiya's +normalization = "MANY_BEAM" +weight_type = "manual" +Rfactor_type = "A2" omega = 0.5 spot_weight = [0.933, 0.026, 0.036, 0.003, 0.002] remove_work_dir = false [solver.param] string_list = ["value_01", "value_02","value_03", "value_04","value_05", "value_06", "value_07","value_08", "value_09"] -#degree_max = 6.5 - [solver.reference] path = "experiment.txt" exp_number = [1, 2, 4, 6, 8] -#first =1 -#last = 63 [algorithm] diff --git a/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/ref_ColorMap.txt b/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/ref_ColorMap.txt index 46550f5a..2e407790 100644 --- a/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/ref_ColorMap.txt +++ b/sample/sim-trhepd-rheed/many_beam/mapper_weight_manual/ref_ColorMap.txt @@ -6,5 +6,5 @@ 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 5.000000 0.003431 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 5.000000 0.003575 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 5.000000 0.003575 -5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 0.003571 -5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 0.004136 +5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 5.000000 0.003572 +5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000 4.000000 5.000000 0.004135 diff --git a/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/input.toml b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/input.toml index 2a7df8bc..b1ecbf09 100644 --- a/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/input.toml +++ b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/input.toml @@ -3,34 +3,27 @@ dimension = 9 output_dir = "output" [solver] -name = "sim-trhepd-rheed-mb_connect" +name = "sim-trhepd-rheed" run_scheme = "subprocess" [solver.config] -surface_exec_file = "/home/kinoshita/tool/sim-trhepd-rheed/src/surf.exe" -bulk_output_file = "bulkP.b" surface_template_file = "template.txt" cal_number = [1, 2, 4, 6, 8] -#calculated_first_line =5 -#calculated_last_line = 67 -#row_number = 2 [solver.post] -normalization = "MS_NORM" #"TOTAL" for Integration or "MAX" for MAX value -Rfactor_type = "A2" #"A" for Ichimiya's or "B" for Pendry's or "A2" for squared Weight + Ichimiya's +normalization = "MANY_BEAM" +weight_type = "calc" +Rfactor_type = "A2" omega = 0.5 remove_work_dir = false [solver.param] string_list = ["value_01", "value_02", "value_03", "value_04", "value_05", "value_06", "value_07", "value_08", "value_09"] -#degree_max = 6.5 [solver.reference] path = "experiment.txt" exp_number = [1, 2, 4, 6, 8] -#first =1 -#last = 63 [algorithm] name = "minsearch" diff --git a/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/ref.txt b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/ref.txt index cf49da3f..c9d084e1 100644 --- a/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/ref.txt +++ b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_calc/ref.txt @@ -1,10 +1,10 @@ -fx = 6.3938405423961675e-09 -X1 = 0.5004690263563492 -X2 = 0.9864825395902956 -X3 = 1.500736054255837 -Y3 = 1.49846022838361 -Z1 = 5.401681359233681 -Z2 = 4.801963397208427 -Z3 = 3.8008746121421977 -Z4 = 2.1004447161065523 -Z5 = 2.000919674433793 +fx = 5.870697010213283e-08 +X1 = 0.498650640494334 +X2 = 0.9822705097865176 +X3 = 1.4991812067698258 +Y3 = 1.4907709351352652 +Z1 = 5.398695624404391 +Z2 = 4.799987213886201 +Z3 = 3.7972188118825647 +Z4 = 2.0996559741875735 +Z5 = 1.9977261612753727 diff --git a/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/input.toml b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/input.toml index 9cb34532..7263dace 100644 --- a/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/input.toml +++ b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/input.toml @@ -3,35 +3,26 @@ dimension = 9 output_dir = "output" [solver] -name = "sim-trhepd-rheed-mb_connect" +name = "sim-trhepd-rheed" run_scheme = "subprocess" [solver.config] -surface_exec_file = "/home/kinoshita/tool/sim-trhepd-rheed/src/surf.exe" -bulk_output_file = "bulkP.b" -surface_template_file = "template.txt" cal_number = [1, 2, 4, 6, 8] -#calculated_first_line =5 -#calculated_last_line = 67 -#row_number = 2 [solver.post] -normalization = "MS_NORM_SET_WGT" #"TOTAL" for Integration or "MAX" for MAX value -Rfactor_type = "A2" #"A" for Ichimiya's or "B" for Pendry's or "A2" for squared Weight + Ichimiya's +normalization = "MANY_BEAM" +weight_type = "manual" +Rfactor_type = "A2" omega = 0.5 spot_weight = [0.933, 0.026, 0.036, 0.003, 0.002] - remove_work_dir = false [solver.param] string_list = ["value_01", "value_02", "value_03", "value_04", "value_05", "value_06", "value_07", "value_08", "value_09"] -#degree_max = 6.5 [solver.reference] path = "experiment.txt" exp_number = [1, 2, 4, 6, 8] -#first =1 -#last = 63 [algorithm] name = "minsearch" diff --git a/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/ref.txt b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/ref.txt index 55016479..ad4880f3 100644 --- a/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/ref.txt +++ b/sample/sim-trhepd-rheed/many_beam/minsearch_weight_manual/ref.txt @@ -1,10 +1,10 @@ -fx = 9.03877847229974e-09 -X1 = 0.5005020046725166 -X2 = 0.98869323286312 -X3 = 1.5004206807677547 -Y3 = 1.4982051821768732 -Z1 = 5.400768705712512 -Z2 = 4.800786853391697 -Z3 = 3.800378633792033 -Z4 = 2.1001028103351684 -Z5 = 2.0002811485701972 +fx = 9.684683478274124e-08 +X1 = 0.49970406829335623 +X2 = 0.9796143149174499 +X3 = 1.500705963094981 +Y3 = 1.4926927133991343 +Z1 = 5.400986081124994 +Z2 = 4.802368383158388 +Z3 = 3.7993453437242017 +Z4 = 2.0993664537497496 +Z5 = 2.0001418106152284 From 4571a8e90c274ca4b8a59f13b5c037bb2b5d1a0d Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Wed, 13 Mar 2024 16:48:18 +0900 Subject: [PATCH 61/67] fix meshgrid --- doc/en/source/algorithm/mapper_mpi.rst | 5 ++-- doc/ja/source/algorithm/mapper_mpi.rst | 7 +++--- src/py2dmat/algorithm/_algorithm.py | 6 +++++ src/py2dmat/algorithm/mapper_mpi.py | 33 ++++++++++++++------------ 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/doc/en/source/algorithm/mapper_mpi.rst b/doc/en/source/algorithm/mapper_mpi.rst index 36acc06d..021f0b17 100644 --- a/doc/en/source/algorithm/mapper_mpi.rst +++ b/doc/en/source/algorithm/mapper_mpi.rst @@ -58,9 +58,10 @@ Mesh definition file ^^^^^^^^^^^^^^^^^^^^^^^^^^ Define the grid space to be explored in this file. -The first column is the index of the mesh, and the second and subsequent columns are the values of variables defined in ``string_list`` in the ``[solver.param]`` section. +1 + ``dimension`` columns are required. +The first column is the index of the mesh, and the second and subsequent columns are the values of parameter. -Below, a sample file is shown. +A sample file for two dimensions is shown below. .. code-block:: diff --git a/doc/ja/source/algorithm/mapper_mpi.rst b/doc/ja/source/algorithm/mapper_mpi.rst index d7b327d3..716defd8 100644 --- a/doc/ja/source/algorithm/mapper_mpi.rst +++ b/doc/ja/source/algorithm/mapper_mpi.rst @@ -60,11 +60,12 @@ MPI 並列を行う場合は、 `mpi4py None: print("mesh after:", mesh) - fx_order = np.argsort(fx_list) - minimum_point = [] - print("mesh_list[fx_order[0]]:") - print(self.mesh_list[fx_order[0]]) - for index in range(1, dimension + 1): - minimum_point.append(self.mesh_list[fx_order[0]][index]) + if iterations > 0: + fx_order = np.argsort(fx_list) + minimum_point = [] + print("mesh_list[fx_order[0]]:") + print(self.mesh_list[fx_order[0]]) + for index in range(1, dimension + 1): + minimum_point.append(self.mesh_list[fx_order[0]][index]) - time_sta = time.perf_counter() - file_CM.write("#Minimum point :") - for value in minimum_point: - file_CM.write(" {:8f}".format(value)) - file_CM.write("\n") - file_CM.write("#R-factor : {:8f}\n".format(fx_list[fx_order[0]])) - file_CM.write("#see Log{}\n".format(round(self.mesh_list[fx_order[0]][0]))) - time_end = time.perf_counter() - self.timer["run"]["file_CM"] += time_end - time_sta + time_sta = time.perf_counter() + file_CM.write("#Minimum point :") + for value in minimum_point: + file_CM.write(" {:8f}".format(value)) + file_CM.write("\n") + file_CM.write("#R-factor : {:8f}\n".format(fx_list[fx_order[0]])) + file_CM.write("#see Log{}\n".format(round(self.mesh_list[fx_order[0]][0]))) + time_end = time.perf_counter() + self.timer["run"]["file_CM"] += time_end - time_sta + else: + file_CM.write("# No mesh point\n") print( "complete main process : rank {:08d}/{:08d}".format( From 390c51cebd60190f7595dc181b8eb058a2c3a1f0 Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Wed, 13 Mar 2024 17:03:43 +0900 Subject: [PATCH 62/67] don't check dimension (for transform) --- src/py2dmat/algorithm/_algorithm.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/py2dmat/algorithm/_algorithm.py b/src/py2dmat/algorithm/_algorithm.py index 58fca558..054b1c83 100644 --- a/src/py2dmat/algorithm/_algorithm.py +++ b/src/py2dmat/algorithm/_algorithm.py @@ -248,10 +248,6 @@ def _meshgrid( ) if data.ndim == 1: data = data.reshape(1, -1) - if data.shape[1] != self.dimension+1: - raise exception.InputError( - f"ERROR: data.shape[1] != dimension+1 ({data.shape[1]} != {self.dimension}+1)" - ) grid = data else: if "min_list" not in info_param: From 33bd63122481b13dbe56707acfd1baaf043e66ad Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Wed, 13 Mar 2024 17:44:25 +0900 Subject: [PATCH 63/67] update gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 8b0e3d36..a2a96bde 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +output +output_* +work + ### https://raw.github.com/github/gitignore/ec246076319913acee4aaeef8caf86b78e586e7a/Python.gitignore # Byte-compiled / optimized / DLL files From 5c477128473a193c8e2db2a14ab07f580c54291f Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Mon, 25 Mar 2024 15:04:49 +0900 Subject: [PATCH 64/67] (sim-trhepd-rheed) accept an integer for cal_number / exp_number --- doc/en/source/solver/sim-trhepd-rheed.rst | 30 +++++++++-------------- doc/ja/source/solver/sim-trhepd-rheed.rst | 22 ++++++----------- src/py2dmat/solver/sim_trhepd_rheed.py | 5 +++- 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/doc/en/source/solver/sim-trhepd-rheed.rst b/doc/en/source/solver/sim-trhepd-rheed.rst index da3fc4d6..7fed33c9 100644 --- a/doc/en/source/solver/sim-trhepd-rheed.rst +++ b/doc/en/source/solver/sim-trhepd-rheed.rst @@ -62,26 +62,20 @@ Input parameters can be specified in subsections ``config``, ``post``, ``param`` Format: integer (default: 5) - Description: One of the parameters that specifies the range of output files to be read, calculated by the solver. This parameter specifies the first line to be read. - -- ``calculated_last_line`` - - Format: integer (default: 60) - - Description: One of the parameters that specifies the range of output files to be read, calculated by the solver. This parameter specifies the last line to be read. + Description: In the output file, the first line to be read as D(x). + The last line is automatically calculated from the number of the reference data. - ``calculated_info_line`` Format: integer (default: 2) - Description: One of the parameters that specifies the range of output files to be read, calculated by the solver. - This parameter specifies the line to be read, which contains the number of glancing angles (second column) and the number of beams (third column). + Description: In the output file, the line contains the information of the calculated data -- the number of glancing angles (second column) and the number of beams (third column). - ``cal_number`` - Format: List of integers + Format: Integer or List of integers - Description: Columns of dataset to be read. Multiple columns can be specified (many-beam condition). + Description: In the output file, the columns to be read as D(x). Multiple columns can be specified (many-beam condition). [``solver.post``] subsection @@ -188,25 +182,25 @@ This subsection is used to the postprocess -- to specify how to calculate the ob Format: string (default: ``experiment.txt``) - Description: Path to the experimental data file. + Description: Path to the reference data file. - ``reference_first_line`` - Format: integer (default: 1) + Format: integer - Description: One of the parameters that specify the range of experimental data files to be read. This parameter specifies the first line of the experimental file to be read. + Description: In the reference data file, the first line to be read as Dexp. The default value is 1, that is, the first line of the file. - ``reference_last_line`` - Format: integer (default: 56) + Format: integer - Description: One of the parameters that specify the range of experimental data files to be read. This parameter specifies the last line of the experimental file to be read. + Description: In the reference data file, the last line to be read as Dexp. If omitted, all lines from the first line to the end of the file will be read. - ``exp_number`` - Format: List of integers + Format: Integer or List of integers - Description: Columns of dataset to be read. Multiple columns can be specified (many-beam condition). + Description: In the reference data file, the column numbers to be read. Multiple columns can be specified (many-beam condition). Reference file diff --git a/doc/ja/source/solver/sim-trhepd-rheed.rst b/doc/ja/source/solver/sim-trhepd-rheed.rst index 1c9b2a7b..42ff8fb2 100644 --- a/doc/ja/source/solver/sim-trhepd-rheed.rst +++ b/doc/ja/source/solver/sim-trhepd-rheed.rst @@ -63,25 +63,19 @@ 形式: 整数型 (default: 5) - 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む最初の行を指定。 - -- ``calculated_last_line`` - - 形式: 整数型 (default: 5 + [``reference``] セクション(サブセクション)にて指定した実験データファイルの視写角数 - 1) - - 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込む最後の行を指定。 + 説明: ``surface_output_file`` ファイル中, D(x) として読み込む最初の行。 なお、最終行は実験データとして読み込んだ行数から自動計算されます。 - ``calculated_info_line`` 形式: 整数型 (default: 2) - 説明: ソルバーにより計算された出力ファイルの行を指定するパラメータ。出力ファイル内に記されているglancing angle数やbeam数が記してある行を指定。 + 説明: ``surface_output_file`` ファイル中, glancing angle数やbeam数が記してある行番号。 - ``cal_number`` 形式: 整数型のリスト (設定必須) - 説明: ソルバーにより計算された出力ファイルを読み込む範囲を指定するパラメータ。読み込むデータ列を指定。複数指定が可能。設定した値は、後述の ``exp_number`` ([``reference``] セクション)の値とリストの長さを一致させる必要があります。 + 説明: ``surface_output_file`` ファイル中, データとして読み出す列番号。複数指定が可能。設定した値は、後述の ``exp_number`` ([``reference``] セクション)の値とリストの長さを一致させる必要があります。 [``post``] セクション(サブセクション) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -188,21 +182,21 @@ - ``reference_first_line`` - 形式: 整数型 (default: 1) + 形式: 整数型 - 説明: 実験データファイルを読み込む範囲を指定するパラメータ。実験ファイルを読み込む最初の行を指定。 + 説明: 実験データファイル中、実験データを読み出す最初の行の番号。省略時は1, すなわち先頭行から読み出します。 - ``reference_last_line`` 形式: 整数型 (default: 実験データファイルの最後の行の行数) - 説明: 実験データファイルを読み込む範囲を指定するパラメータ。実験ファイルを読み込む最後の行を指定。 + 説明: 実験データファイル中、実験データを読み出す最後の行の番号。省略時は最終行まで読み出します。 - ``exp_number`` - 形式: 整数型のリスト (default: []、設定必須) + 形式: 整数型のリスト - 説明: 実験データファイルを読み込む範囲を指定するパラメータ。読み込むデータ列を指定。複数指定が可能。設定した値は、前述の ``cal_number`` ([``config``] セクション)の値とリストの長さを一致させる必要があります。 + 説明: 実験データファイル中、実験データとして読み出す列番号。複数指定が可能。設定した値は、前述の ``cal_number`` ([``config``] セクション)の値とリストの長さを一致させる必要があります。 ソルバー用補助ファイル ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/py2dmat/solver/sim_trhepd_rheed.py b/src/py2dmat/solver/sim_trhepd_rheed.py index 6effbf05..14095a79 100644 --- a/src/py2dmat/solver/sim_trhepd_rheed.py +++ b/src/py2dmat/solver/sim_trhepd_rheed.py @@ -530,7 +530,8 @@ def __init__(self, info, isLogmode, detail_timer): self.beam_number_exp_raw = data_experiment.shape[1] v = info_ref.get("exp_number", []) - + if isinstance(v, int): + v = [v] if len(v) == 0: raise exception.InputError("ERROR: You have to set the 'solver.reference.exp_number'.") @@ -647,6 +648,8 @@ def __init__(self, info, isLogmode, detail_timer): self.calculated_info_line = v v = info_config.get("cal_number", []) + if isinstance(v, int): + v = [v] if len(v) == 0: raise exception.InputError("ERROR: You have to set the 'solver.config.cal_number'.") From 99c78ec0b917a6ccf0ee5a9a8f7425b7f68ad45e Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Mon, 25 Mar 2024 15:59:30 +0900 Subject: [PATCH 65/67] update --- src/py2dmat/util/limitation.py | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/py2dmat/util/limitation.py b/src/py2dmat/util/limitation.py index 5a1f03e4..bc352fe6 100644 --- a/src/py2dmat/util/limitation.py +++ b/src/py2dmat/util/limitation.py @@ -2,41 +2,31 @@ import numpy as np -import py2dmat - -# for type hints -from pathlib import Path -from typing import List, Optional, Dict class LimitationBase(metaclass=ABCMeta): @abstractmethod - def __init__ (self, a: np.ndarray, b: np.ndarray, is_limitary: bool): - + def __init__(self, a: np.ndarray, b: np.ndarray, is_limitary: bool): + self.islimitary = is_limitary if self.islimitary: self.a = a - self.b = b + self.minusb = -b self.n_formura = a.shape[0] self.ndim = a.shape[1] - + @abstractmethod def judge(self, x: np.ndarray) -> bool: pass + class Inequality(LimitationBase): - def __init__ (self, a: np.ndarray, b: np.ndarray, is_limitary: bool): + def __init__(self, a: np.ndarray, b: np.ndarray, is_limitary: bool): super().__init__(a, b, is_limitary) def judge(self, x: np.ndarray) -> bool: - if self.islimitary : - judge_formula = [] - for formula_index in range(self.n_formura): - value_formula = 0 - for dim_index in range(self.ndim): - value_formula += self.a[formula_index, dim_index]*x[dim_index] - value_formula += self.b[formula_index] - judge_formula.append(value_formula>0) - judge_result = all(judge_formula) + if self.islimitary: + Ax = np.einsum("ij,j->i", self.a, x) + judge_result = all(Ax > self.minusb) else: judge_result = True return judge_result From 96f56c9502053628360021dc172e60a9779588b8 Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Tue, 26 Mar 2024 15:22:08 +0900 Subject: [PATCH 66/67] v2.2.0 --- doc/en/source/conf.py | 2 +- doc/ja/source/conf.py | 2 +- pyproject.toml | 2 +- src/py2dmat/__init__.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/en/source/conf.py b/doc/en/source/conf.py index 13e9831f..a926ea8f 100644 --- a/doc/en/source/conf.py +++ b/doc/en/source/conf.py @@ -57,7 +57,7 @@ # The short X.Y version. version = u'2.2' # The full version, including alpha/beta/rc tags. -release = u'2.2-dev' +release = u'2.2.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/ja/source/conf.py b/doc/ja/source/conf.py index c55e1106..74c5faf8 100644 --- a/doc/ja/source/conf.py +++ b/doc/ja/source/conf.py @@ -22,7 +22,7 @@ author = '2DMAT developers' # The full version, including alpha/beta/rc tags -release = '2.2-dev' +release = '2.2.0' # -- General configuration --------------------------------------------------- diff --git a/pyproject.toml b/pyproject.toml index 65aef020..1bbe5800 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "py2dmat" -version = "2.2-dev" +version = "2.2.0" description = "Data-analysis software of quantum beam diffraction experiments for 2D material structure" authors = ["2DMAT developers <2dmat-dev@issp.u-tokyo.ac.jp>"] license = "GPL-3.0-or-later" diff --git a/src/py2dmat/__init__.py b/src/py2dmat/__init__.py index ac50affb..cd0abfa9 100644 --- a/src/py2dmat/__init__.py +++ b/src/py2dmat/__init__.py @@ -24,4 +24,4 @@ from . import algorithm from ._main import main -__version__ = "2.2-dev" +__version__ = "2.2.0" From 9990bdcdd19d0ecffac7eab412827d95f6d39496 Mon Sep 17 00:00:00 2001 From: Yuichi Motoyama Date: Tue, 26 Mar 2024 15:41:17 +0900 Subject: [PATCH 67/67] update readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f625cfb8..49d51584 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ In the future, we plan to add other direct problem solvers and search algorithms | Branch | Build status | Documentation | | :----: | :-----------------------------------------: | :---------------------------------------------------------------------------------------: | | [master][source/master] (latest) | [![master][ci/master/badge]][ci/master/uri] | [![doc_en][doc/en/badge]][doc/en/uri] [![doc_ja][doc/ja/badge]][doc/ja/uri] | -| [v2.1.0][source/stable] (latest stable) | -- | [![doc_en][doc/en/badge]][doc/stable/en/uri] [![doc_ja][doc/ja/badge]][doc/stable/ja/uri] | +| [v2.2.0][source/stable] (latest stable) | -- | [![doc_en][doc/en/badge]][doc/stable/en/uri] [![doc_ja][doc/ja/badge]][doc/stable/ja/uri] | ## py2dmat @@ -98,12 +98,12 @@ author = {Yuichi Motoyama and Kazuyoshi Yoshimi and Izumi Mochizuki and Harumich This software was developed with the support of "*Project for advancement of software usability in materials science*" of The Institute for Solid State Physics, The University of Tokyo. [source/master]: https://github.com/issp-center-dev/2DMAT/ -[source/stable]: https://github.com/issp-center-dev/2DMAT/tree/v2.1.0 +[source/stable]: https://github.com/issp-center-dev/2DMAT/tree/v2.2.0 [ci/master/badge]: https://github.com/issp-center-dev/2DMAT/workflows/Test/badge.svg?branch=master [ci/master/uri]: https://github.com/issp-center-dev/2DMAT/actions?query=branch%3Amaster [doc/en/badge]: https://img.shields.io/badge/doc-English-blue.svg [doc/en/uri]: https://issp-center-dev.github.io/2DMAT/manual/master/en/index.html [doc/ja/badge]: https://img.shields.io/badge/doc-Japanese-blue.svg [doc/ja/uri]: https://issp-center-dev.github.io/2DMAT/manual/master/ja/index.html -[doc/stable/en/uri]: https://issp-center-dev.github.io/2DMAT/manual/v2.1.0/en/index.html -[doc/stable/ja/uri]: https://issp-center-dev.github.io/2DMAT/manual/v2.1.0/ja/index.html +[doc/stable/en/uri]: https://issp-center-dev.github.io/2DMAT/manual/v2.2.0/en/index.html +[doc/stable/ja/uri]: https://issp-center-dev.github.io/2DMAT/manual/v2.2.0/ja/index.html