Source code for xicsrt.xicsrt_config

# -*- coding: utf-8 -*-
"""
.. Authors
    Novimir Pablant <npablant@pppl.gov>
    James Kring <jdk0026@tigermail.auburn.edu>
    Yevgeniy Yakusevich <eugenethree@gmail.com>
"""


import numpy as np
import logging
import os
import copy
from xicsrt.objects._ConfigObject import ConfigObject
from xicsrt.tools import xicsrt_misc

from xicsrt import _version

log = logging.getLogger(__name__)

try:
    import xicsrt_contrib
except:
    log.debug('The xicrsrt_contrib package is not installed.')
else:
    log.debug('The xicrsrt_contrib package is installed.')


[docs] def default_config(): """ number_of_iter : int (1) Number of raytracing iterations to perform for each raytracing run. Iterations are performed in a single process and with a single initialization of the raytracing objects and the random seed. All iterations will be combined before saving images or output files. number_of_runs : int (1) Number of raytracing runs to perform. For each run, the specified number of iterations will be performed. Raytracing runs can be performed in separate processes enabling the use of multiprocessing. At the start of each run all raytracing objects will be created and initialized. Images and output files will be saved after each run. random_seed : int (None) A random seed to initialize the pseudo-random number generator. If random_seed is equal to None then a random seed will be provided by the python/numpy internals. When a integer seed is provided and multiple raytracing runs are performed, the random seed will be incremented by one for each successive run. This seed can be used to make raytracing runs reproducible on the level of individual rays; however, reproducibility is not guaranteed between different versions of XICSRT or different versions of Python. Random seed initialization performed using `np.random.seed()`. pathlist : list (list()) A list of paths that contain user defined raytracing modules (sources, optics, filters, apertures, etc.). These paths will be searched for filenames that match the requested 'class_name' in the object config. User defined paths are searched before the builtin or contrib paths. pathlist_default : list A list of paths to the builtin and contributed raytracing objects. This option should not be changed by the user, but can be useful for inspection to see what directories are actually being searched. strict_config_check : bool (True) Use strict checking to ensure that the config dictionary only contains valid options for the given object. This helps avoid unexpected behavior as well and alerting to typos in the configuration. When set to `False`, unrecognized config options will be quietly ignored. output_path : str (None) Path in which to save images and results from the raytracing run. If note then the current working path will be used. Use the option `make_directories` to control directory creation. output_prefix : str ("xicsrt") Filenames for images and results are automatically generated. Use this option to add a prefix to the beginning of all filenames. An underscore will be automatically added after the prefix. For images the following format will be used: "prefix_optic_suffix_run.tif". For example: "xicsrt_detector_scan01_0000.tif". output_suffix : str (None) If present this string will be added to automatically generated filenames after the optic name and before the run_suffix. See the option `output_prefix` for more information. output_run_suffix : str (None) This option is used internally and should not be set by the user. image_ext : str ('.tif') Controls the file format of the saved images. Any format supported by the `pillow` package can be used; .tif images are recommended. results_ext : str ('.hdf5') Controls the file format for saving the results dictionary. Currently hdf5 (.hdf5, .h5), pickle (.pickle, .pkl) and json (.json) file formats are supported. The json format is not recommended as it may lead to very large file sizes! make_directories : bool (False) Controls whether the output path should be created if it does not already exist. If False an error will be raised if the output path does not exist. keep_meta : bool (True) Controls whether to calculate and keep metadata and statistics relating to the raytracing. keep_images : bool (True) Controls whether to generate and keep pixelated images of the ray intersections at each optic. Control of image generation for individual optics can also be set within the object specific config sections. keep_history : bool (True) Controls whether to calculate and keep the raytracing history. Rays will be sorted into 'lost' and 'found' rays, where found rays are those that reach the final optic element. The 'found' ray history will be kept in full, the 'lost' ray history will be truncated (see option `history_max_lost`). The ray history provides a great deal of information about the raytracing and enables ray plotting (2d and 3d) and post processing. However, turning on the ray history also *greatly* increases memory usage since the rays must be duplicated and saved for every optical element. If only final intersection images are required, consider setting this option to `False` to improve raytracing performance. history_max_lost : int (10000) Number of 'lost' rays to retain in the raytrace history. Lost rays are those that are launched from the source but that do not reach the last optical element (typically a detector). For many x-ray raytracing applications the number of lost rays will be very large, and retention of all lost rays would quickly exhaust available system memory. To avoid memory issues, while still retaining some lost rays for diagnostic purposes, a randomized truncation of the lost rays is performed. save_config : bool (False) Option whether or not to save the config dictionary. Output format is currently limited to json format (hdf5 and pickle coming soon). save_images : bool (False) Controls saving of images. Images will be saved for every run, and a combined image will be saved at the conclusion of all runs. Control of output for individual optics can be set within the object specific config sections. Image format will be determined by the option `image_ext` (default .tif). Images will be saved to the `output_path`. save_results : bool (False) Controls saving of the raytracing results dictionary. The contents of the results dictionary are controlled by `keep_meta`, `keep_images` and `keep_history`. Results will only be saved after all runs are completed. Output format will be determined by the option `results_ext` (default .hdf5). OUtput will be saved to the `output_path`. print_results : bool (True) Control text output to terminal of raytracing summary and optics specific information. (Note: control of logging/debugging output is controlled through a separate option that is not yet implemented.) version: string The version number of xicsrt when this config was created. This option is set internally and should not be modified by the user. """ config = dict() config['general'] = dict() config['general']['version'] = _version.__version__ config['general']['number_of_iter'] = 1 config['general']['number_of_runs'] = 1 config['general']['random_seed'] = None config['general']['pathlist'] = [] config['general']['pathlist_default'] = get_pathlist_default() config['general']['strict_config_check'] = True config['general']['output_path'] = None config['general']['output_prefix'] = 'xicsrt' config['general']['output_suffix'] = None config['general']['output_run_suffix'] = None config['general']['image_ext'] = '.tif' config['general']['results_ext'] = '.hdf5' config['general']['config_ext'] = '.json' config['general']['make_directories'] = False config['general']['keep_meta'] = True config['general']['keep_images'] = True config['general']['keep_history'] = True config['general']['history_max_lost'] = 10000 config['general']['save_config'] = False config['general']['save_images'] = False config['general']['save_results'] = False config['general']['print_results'] = True config['sources'] = dict() config['optics'] = dict() config['filters'] = dict() config['scenario'] = dict() return config
[docs] def get_config(config_user=None): config = default_config() update_config(config, config_user, strict=False, update=True) return config
[docs] def refresh_config(config_new): """ When a config file is loaded from a another system or from a different user it may contain default values that are not appropriate for the current environment. This function will overwrite these options with new default values where appropriate. """ refresh = {} refresh['general'] = {} refresh['general']['pathlist_default'] = None config_new = copy.deepcopy(config_new) update_config( config_new, refresh, strict=False, update=True, ignore_none=False, ) config = default_config() update_config( config, config_new, strict=False, update=True, ignore_none=True, ) return config
[docs] def get_pathlist_default(): """ Return a list of the default sources and optics directories. These locations will be based on the location of this module. """ pathlist = [] pathlist = _add_pathlist_builtin(pathlist) pathlist = _add_pathlist_contrib(pathlist) return pathlist
[docs] def _add_pathlist_builtin(pathlist): # Add paths to built-in objects. path_module = os.path.dirname(os.path.abspath(__file__)) pathlist.append(os.path.join(path_module, 'filters')) pathlist.append(os.path.join(path_module, 'sources')) pathlist.append(os.path.join(path_module, 'optics')) return pathlist
[docs] def _add_pathlist_contrib(pathlist): # Check if the xicsrt_contrib module was successfully imported. if not 'xicsrt_contrib' in globals(): return pathlist # Add paths to the xicsrt_contrib objects. path_module = os.path.dirname(os.path.abspath(xicsrt_contrib.__file__)) pathlist.append(os.path.join(path_module, 'filters')) pathlist.append(os.path.join(path_module, 'sources')) pathlist.append(os.path.join(path_module, 'optics')) return pathlist
[docs] def config_to_numpy(obj): xicsrt_misc._convert_to_numpy(obj) return obj
[docs] def config_from_numpy(obj): xicsrt_misc._convert_from_numpy(obj) return obj
[docs] def update_config( config, config_new, strict=None, update=None, ignore_none=None, ): """ Overwrite any values in the given config dict with the values in the config_new dict. This will be done recursively to allow nested dictionaries. keywords: strict (True) If True then an error will be raised if an option is found in the user dict that is not found in the default dict. update (False) If True any unmatched options that are found will be retained. When False they will simply be ignored. This option has no effect unless strict = False. ignore_none (False) If True any options found in config_new with a value of None will be ignored. """ _update_config_dict(config, config_new, strict, update, ignore_none) return config
[docs] def _update_config_dict( config, config_new, strict=None, update=None, ignore_none=None, ): """ Recursive worker function for `update_config`. """ if strict is None: strict = True if update is None: update = False if ignore_none is None: ignore_none = False if config_new is None: return for key in config_new: if not key in config: if strict: raise Exception("User option not recognized: {}".format(key)) if update: config[key] = config_new[key] else: if isinstance(config[key], dict) and isinstance(config_new[key], dict): _update_config_dict( config[key], config_new[key], strict=strict, update=update, ignore_none=ignore_none ) else: if ignore_none and config_new[key] is None: pass else: config[key] = config_new[key]