Source code for ghosts.geom

"""geom module

This module provides tools to manipulate telescope geometries, i.e. shifts and rotations
"""

import copy
import pandas as pd
import numpy as np
from ghosts.geom_configs import GEOM_CONFIG_0


[docs] def get_optics_translation(optics, geom_config): """ Return a vector with the translations of the given optics Parameters ---------- optics : `string` the name of an optical element in L1, L2, L3, Filter, Detector geom_config : `dict` a dictionary with shifts and rotations for each optical element Returns ------- translation_vector : `list` of `float` a vector of translations for the optical element """ translation_vector = [geom_config.get(f'{optics}_d{axis}', 0.) for axis in ['x', 'y', 'z']] return translation_vector
[docs] def get_optics_rotation(optics, geom_config): """ Return a vector with the rotations of the given optics Parameters ---------- optics : `string` the name of an optical element in L1, L2, L3, Filter, Detector geom_config : `dict` a dictionary with shifts and rotations for each optical element Returns ------- rotation_vector : `list` of `float` a vector of rotations for the optical element """ return [geom_config.get(f'{optics}_r{axis}', 0.) for axis in ['x', 'y', 'z']]
[docs] def to_panda(geom_config): """ Convert a geometry configuration dictionary to a panda data frame Indexing is done using the beam configuration `geom_id`. Parameters ---------- geom_config : `dict` a dictionary with shifts and rotations for each optical element Returns ------- data_frame : `pandas.DataFrame` a `pandas` data frame with shifts and rotations information """ data_frame = pd.DataFrame(data=geom_config, index=[geom_config['geom_id']]) return data_frame
[docs] def to_dict(geom_frame): """ Convert a geometry panda data frame to a dictionary of use with `tweak_optics` The geom data frame is expected to have only one geometry configuration. Parameters ---------- geom_frame : `pandas.DataFrame` a `pandas` data frame with shifts and rotations information Returns ------- geom_config : `dict` a dictionary with shifts and rotations for each optical element """ geom_id = geom_frame['geom_id'].to_list()[0] geom_config = geom_frame.to_dict('index')[geom_id] return geom_config
[docs] def concat_frames(geom_frame_list): """ Concatenates geometry configuration data frames within one table Parameters ---------- geom_frame_list : `list` of `pandas.DataFrame` a list of geometry configuration data frames Returns ------- geom_concat : `pandas.DataFrame` a `pandas` data frame with several configurations of shifts and rotations information """ tmp_concat = pd.concat(geom_frame_list) geom_concat = tmp_concat.fillna(0) geom_concat.sort_values('geom_id') return geom_concat
[docs] def concat_dicts(geom_dict_list): """ Concatenates geometry configuration dictionaries into a data frame Parameters ---------- geom_dict_list : `list` of `dict` a list of geometry configuration dictionaries Returns ------- geom_concat : `pandas.DataFrame` a `pandas` data frame with several configurations of shifts and rotations information """ frames = [] for one in geom_dict_list: frames.append(to_panda(one)) geom_concat = concat_frames(frames) return geom_concat
# Helpers to create a set of geometries translations
[docs] def translate_optic(optic_name, axis, distance, geom_id=1000000): """ Create a dictionary to translate a piece of optic along an axis Parameters ---------- optic_name : `string` the name of an optical element axis : `string` the name of the translation axis, in [x, y , z] distance : `float` the value of the shift in meters geom_id : `int` the id of the new geometry configuration Returns ------- geom : `dict` a `geom_config` dictionary for the application of the translation """ if axis not in ['x', 'y', 'z']: print(f'Unknown axis {axis}, doing nothing.') return None geom = copy.deepcopy(GEOM_CONFIG_0) geom['geom_id'] = geom_id opt_key = f'{optic_name}_d{axis}' geom[opt_key] = distance return geom
[docs] def rotate_optic(optic_name, axis, angle, geom_id=1000000): """ Rotate one optical element of a telescope given a list of Euler angles Parameters ---------- optic_name : `string` the name of an optical element axis : `string` the name of the rotation axis, usually y angle : `float` the values of angle in degrees geom_id : `int` the id of the new geometry configuration Returns ------- geom : `dict` a `geom_config` dictionary for the application of the rotation """ geom = copy.deepcopy(GEOM_CONFIG_0) geom['geom_id'] = geom_id opt_key = f'{optic_name}_r{axis}' geom[opt_key] = angle return geom
[docs] def build_translation_set(optic_name, axis, shifts_list, base_id=0): """ Build a set of geometries for the given list of translations Parameters ---------- optic_name : `string` the name of an optical element axis : `string` the name of the rotation axis, usually y shifts_list : `list` of `float` the list of distances to scan in meters base_id : `int` the id of the first geometry configuration created, following ids will be `id+1` Returns ------- geoms : `list` of `geom_config` a list of geometry configuration dictionaries """ geoms = [] for i, shift in enumerate(shifts_list): geoms.append(translate_optic(optic_name, axis, shift, geom_id=base_id+i)) return geoms
[docs] def build_rotation_set(optic_name, axis, angles_list, base_id=0): """ Build a set of geometries for the given list of rotations Parameters ---------- optic_name : `string` the name of an optical element axis : `string` the name of the rotation axis, usually y angles_list : `list` of `float` the list of angles to scan in degrees base_id : `int` the id of the first geometry configuration created, following ids will be `id+1` Returns ------- geoms : `list` of `geom_config` a list of geometry configuration dictionaries """ geoms = [] for i, angle in enumerate(angles_list): geoms.append(rotate_optic(optic_name, axis, angle, geom_id=base_id+i)) return geoms
[docs] def build_random_geom(max_angle=0.1, max_shift=0.001): """ Build a random geometry from a base geometry configuration Parameters ---------- max_angle : `float` the maximum value of the rotation angle in degree max_shift : `floats` the maximum value of the shift in meters Returns ------- rnd_geom : `geom.geom_configs` a random geometry """ # generate 30 random numbers numbers = np.random.random([30]) rnd_geom_dict = copy.deepcopy(GEOM_CONFIG_0) optics_keys = list(rnd_geom_dict.keys()) optics_keys.remove('geom_id') for optic, rnd in zip(optics_keys, numbers): mv_type = optic.split('_')[1] if mv_type in ['dx', 'dy', 'dz']: rnd_shift = max_shift * 2 * (rnd - 0.5) rnd_geom_dict[optic] = np.round(rnd_shift, 6) elif mv_type in ['rx', 'ry', 'rz']: rnd_euler_angle = max_angle * 2 * (rnd - 0.5) rnd_geom_dict[optic] = np.round(rnd_euler_angle, 6) # assign a random id rnd_geom_dict['geom_id'] = np.random.randint(1e9) return rnd_geom_dict