def generate_filename(config, kind=None, name=None, path=None): config = xicsrt_config.get_config(config) prefix = config['general']['output_prefix'] suffix = config['general']['output_suffix'] run_suffix = config['general']['output_run_suffix'] if path is None: path = config['general']['output_path'] if kind is None: ext = '' elif kind == 'image': ext = config['general']['image_ext'] elif kind == 'results': ext = config['general']['results_ext'] elif kind == 'config': ext = config['general']['config_ext'] else: raise Exception(f'Data kind {kind} unknown.') if name is None: name = kind filename = '_'.join(filter(None, (prefix, name, suffix, run_suffix))) + ext filepath = os.path.join(path, filename) return filepath
def raytrace(config): """ Perform a series of ray tracing runs. Each run will rebuild all objects, reset the random seed and then perform the requested number of iterations. If the option 'save_images' is set, then images will be saved at the completion of each run. The saving of these run images is one reason to use this routine rather than just increasing the number of iterations: periodic outputs during long computations. Also see :func:`~xicsrt.xicsrt_multiprocessing.raytrace` for a multiprocessing version of this routine. """ profiler.start('raytrace') # Update the default config with the user config. config = xicsrt_config.get_config(config) check_config(config) # Make local copies of some options. num_runs = config['general']['number_of_runs'] random_seed = config['general']['random_seed'] output_list = [] for ii in range(num_runs): m_log.info('Starting run: {} of {}'.format(ii + 1, num_runs)) config_run = deepcopy(config) config_run['general']['output_run_suffix'] = '{:04d}'.format(ii) # Make sure each run uses a unique random seed. if random_seed is not None: random_seed += ii config_run['general']['random_seed'] = random_seed iteration = raytrace_single(config_run, _internal=True) output_list.append(iteration) output = combine_raytrace(output_list) # Reset the configuration options that were unique to the individual runs. output['config']['general']['output_run_suffix'] = config['general']['output_run_suffix'] output['config']['general']['random_seed'] = config['general']['random_seed'] if config['general']['save_config']: xicsrt_io.save_config(output['config']) if config['general']['save_images']: xicsrt_io.save_images(output) if config['general']['save_results']: xicsrt_io.save_results(output) if config['general']['print_results']: print_raytrace(output) profiler.stop('raytrace') return output
def get_element(config_user, name, section=None, initialize=True): """ Retrieves an raytracing element (source, optic or filter) object. """ config = xicsrt_config.get_config(config_user) if section is None: section = _find_element_section(config, name) disp = Dispatcher(config, section) disp.instantiate(name) obj = disp.get_object(name) if initialize: obj.setup() obj.check_param() obj.initialize() return obj
def add_sources(config): # Update the default config with the user config. config = xicsrt_config.get_config(config) # Combine the user and default object pathlists. pathlist = [] pathlist.extend(config['general']['pathlist_objects']) pathlist.extend(config['general']['pathlist_default']) sources = Dispatcher(config, 'sources') sources.instantiate() sources.setup() sources.initialize() for key in config['sources']: obj = sources.get_object(key) add_surf(obj)
def raytrace_single(config, _internal=False): """ Perform a single raytrace run consisting of multiple iterations. If history is enabled, sort the rays into those that are detected and those that are lost (found and lost). The found ray history will be returned in full. The lost ray history will be truncated to allow analysis of lost ray pattern while still limiting memory usage. private keywords ================ _internal : bool (False) Used when calling this function from `raytrace` as part of the execution of multiple runs. Controls how `history_max_lost` is handled along with how `save_config` and `save_results` are interpreted. """ profiler.start('raytrace_single') # Update the default config with the user config. config = xicsrt_config.config_to_numpy(config) config = xicsrt_config.get_config(config) check_config(config) m_log.info('Seeding np.random with {}'.format(config['general']['random_seed'])) np.random.seed(config['general']['random_seed']) num_iter = config['general']['number_of_iter'] max_lost_iter = int(config['general']['history_max_lost']/num_iter) if _internal: max_lost_iter = max_lost_iter//config['general']['number_of_runs'] # Setup the dispatchers. if 'filters' in config: m_log.debug("Creating filters") filters = Dispatcher(config, 'filters') filters.instantiate() filters.setup() filters.initialize() config['filters'] = filters.get_config() else: filters = None m_log.debug("Creating sources") sources = Dispatcher(config, 'sources') sources.instantiate() sources.apply_filters(filters) sources.setup() sources.check_param() sources.initialize() config['sources'] = sources.get_config() m_log.debug("Creating optics") optics = Dispatcher(config, 'optics') optics.instantiate() optics.apply_filters(filters) optics.setup() optics.check_param() optics.initialize() config['optics'] = optics.get_config() # Do the actual raytracing output_list = [] for ii in range(num_iter): m_log.info('Starting iteration: {} of {}'.format(ii + 1, num_iter)) single = _raytrace_iter(config, sources, optics) sorted = _sort_raytrace(single, max_lost=max_lost_iter) output_list.append(sorted) output = combine_raytrace(output_list) if _internal is False: if config['general']['print_results']: print_raytrace(output) if config['general']['save_config']: xicsrt_io.save_config(output['config']) if config['general']['save_results']: xicsrt_io.save_results(output) if config['general']['save_images']: xicsrt_io.save_images(output) profiler.stop('raytrace_single') # profiler.report() return output
def add_optics(config): for key_opt in config['optics']: config_opt = config['optics'][key_opt] config_opt = xicsrt_config.config_to_numpy(config_opt) if True: w = config_opt['width'] / 2.0 h = config_opt['height'] / 2.0 cx = config_opt['xaxis'] cy = np.cross(config_opt['xaxis'], config_opt['zaxis']) point0 = w * cx + h * cy + config_opt['origin'] point1 = h * cy + config_opt['origin'] point2 = -1 * w * cx + h * cy + config_opt['origin'] point3 = w * cx + config_opt['origin'] point4 = config_opt['origin'] point5 = -1 * w * cx + config_opt['origin'] point6 = w * cx - h * cy + config_opt['origin'] point7 = -1 * h * cy + config_opt['origin'] point8 = -1 * w * cx - h * cy + config_opt['origin'] points = np.array([ point0, point1, point2, point3, point4, point5, point6, point7, point8 ]) x = points[:, 0] y = points[:, 1] z = points[:, 2] # I am sure there is a way to automate this using a meshgrid, # but at the moment this is faster. triangles = ((4, 0, 2), (4, 2, 8), (4, 6, 8), (4, 6, 0)) obj = ipv.plot_trisurf(x, y, z, triangles=triangles, color=[0.5, 0.5, 0.5, 0.5]) obj.material.transparent = True if 'crystal' in str.lower(key_opt) and 'radius' in config_opt: # Initialize the configuration. # This merges the user config that we created # with the default config config = xicsrt_config.get_config(config) # The easiest way to do coordinate transformations is # to use the raytrace objects, since they already have # everything built in. Of course we could do this # by just using some simple matrix multiplications, # but this way we can use existing code. # # We could just instantiate the objects directly as needed, # but since a dispatcher is already available in xicsrt that # does this for us, we might as well use it. This is copied # from xicsrt_raytrace.raytrace_single. name = 'crystal' section = 'optics' optics = Dispatcher(config, section) optics.instantiate() optics.setup() optics.initialize() # Get the crystal object from the dispatcher. optic_obj = optics.get_object(name) crystal_center_ext = config_opt[ 'origin'] + config_opt['zaxis'] * config_opt['radius'] crystal_center_loc = optic_obj.point_to_local(crystal_center_ext) x = np.array([crystal_center_ext[0]]) y = np.array([crystal_center_ext[1]]) z = np.array([crystal_center_ext[2]]) ipv.scatter(x, y, z, color='black', marker="sphere") # Plot the crystal circle. num = 1000 crystal_radius = config_opt['radius'] coord_loc = np.zeros((num, 3)) coord_loc[:, 0] = np.sin(np.linspace( 0.0, np.pi * 2, num)) * config_opt['radius'] + crystal_center_loc[0] coord_loc[:, 1] = crystal_center_loc[1] coord_loc[:, 2] = np.cos(np.linspace( 0.0, np.pi * 2, num)) * config_opt['radius'] + crystal_center_loc[2] coord_ext = optic_obj.point_to_external(coord_loc) x = coord_ext[:, 0] y = coord_ext[:, 1] z = coord_ext[:, 2] lines = np.zeros((num, 2), dtype=int) lines[:, 0] = np.arange(num) lines[:, 1] = np.roll(lines[:, 0], 1) obj = ipv.plot_trisurf(x, y, z, lines=lines, color=[0.0, 0.0, 0.0, 0.5]) rowland_center_ext = config_opt[ 'origin'] + config_opt['zaxis'] * config_opt['radius'] / 2 rowland_center_loc = optic_obj.point_to_local(rowland_center_ext) rowland_radius = crystal_radius / 2 coord_loc = np.zeros((num, 3)) coord_loc[:, 0] = np.sin(np.linspace( 0.0, np.pi * 2, num)) * rowland_radius + rowland_center_loc[0] coord_loc[:, 1] = rowland_center_loc[1] coord_loc[:, 2] = np.cos(np.linspace( 0.0, np.pi * 2, num)) * rowland_radius + rowland_center_loc[2] coord_ext = optic_obj.point_to_external(coord_loc) x = coord_ext[:, 0] y = coord_ext[:, 1] z = coord_ext[:, 2] lines = np.zeros((num, 2), dtype=int) lines[:, 0] = np.arange(num) lines[:, 1] = np.roll(lines[:, 0], 1) obj = ipv.plot_trisurf(x, y, z, lines=lines, color=[0.0, 0.0, 0.0, 0.5])