gammasimtools 0.6.1__py3-none-any.whl → 0.8.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gammasimtools-0.8.2.dist-info/METADATA +173 -0
- gammasimtools-0.8.2.dist-info/RECORD +345 -0
- {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.2.dist-info}/WHEEL +1 -1
- gammasimtools-0.8.2.dist-info/entry_points.txt +31 -0
- simtools/_dev_version/__init__.py +9 -0
- simtools/_version.py +2 -2
- simtools/applications/calculate_trigger_rate.py +210 -0
- simtools/applications/convert_all_model_parameters_from_simtel.py +372 -0
- simtools/applications/{print_array_elements.py → convert_geo_coordinates_of_array_elements.py} +58 -63
- simtools/applications/convert_model_parameter_from_simtel.py +119 -0
- simtools/applications/{add_file_to_db.py → db_add_file_to_db.py} +70 -60
- simtools/applications/db_add_model_parameters_from_repository_to_db.py +184 -0
- simtools/applications/db_add_value_from_json_to_db.py +105 -0
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +180 -0
- simtools/applications/db_get_array_layouts_from_db.py +162 -0
- simtools/applications/{get_file_from_db.py → db_get_file_from_db.py} +30 -34
- simtools/applications/db_get_parameter_from_db.py +131 -0
- simtools/applications/db_inspect_databases.py +52 -0
- simtools/applications/derive_mirror_rnda.py +39 -255
- simtools/applications/derive_psf_parameters.py +441 -0
- simtools/applications/generate_array_config.py +82 -0
- simtools/applications/generate_corsika_histograms.py +52 -52
- simtools/applications/generate_default_metadata.py +5 -8
- simtools/applications/generate_regular_arrays.py +117 -0
- simtools/applications/generate_simtel_array_histograms.py +97 -56
- simtools/applications/plot_array_layout.py +345 -115
- simtools/applications/production_generate_simulation_config.py +158 -0
- simtools/applications/production_scale_events.py +168 -0
- simtools/applications/simulate_light_emission.py +478 -0
- simtools/applications/simulate_prod.py +97 -175
- simtools/applications/submit_data_from_external.py +9 -12
- simtools/applications/submit_model_parameter_from_external.py +122 -0
- simtools/applications/validate_camera_efficiency.py +35 -102
- simtools/applications/validate_camera_fov.py +20 -19
- simtools/applications/{compare_cumulative_psf.py → validate_cumulative_psf.py} +45 -44
- simtools/applications/validate_file_using_schema.py +111 -47
- simtools/applications/validate_optics.py +17 -22
- simtools/camera_efficiency.py +193 -202
- simtools/configuration/commandline_parser.py +384 -96
- simtools/configuration/configurator.py +55 -71
- simtools/constants.py +5 -5
- simtools/corsika/corsika_config.py +482 -342
- simtools/corsika/corsika_histograms.py +226 -204
- simtools/corsika/corsika_histograms_visualize.py +23 -24
- simtools/corsika/primary_particle.py +159 -0
- simtools/data_model/data_reader.py +25 -20
- simtools/data_model/format_checkers.py +52 -0
- simtools/data_model/metadata_collector.py +211 -185
- simtools/data_model/metadata_model.py +115 -37
- simtools/data_model/model_data_writer.py +335 -26
- simtools/data_model/validate_data.py +366 -154
- simtools/db/db_array_elements.py +130 -0
- simtools/db/db_from_repo_handler.py +106 -0
- simtools/db/db_handler.py +1246 -0
- simtools/io_operations/hdf5_handler.py +3 -1
- simtools/io_operations/io_handler.py +32 -57
- simtools/job_execution/job_manager.py +82 -69
- simtools/layout/array_layout.py +325 -537
- simtools/layout/geo_coordinates.py +8 -11
- simtools/layout/telescope_position.py +163 -86
- simtools/model/array_model.py +312 -259
- simtools/model/calibration_model.py +50 -0
- simtools/model/camera.py +277 -523
- simtools/model/mirrors.py +68 -49
- simtools/model/model_parameter.py +602 -0
- simtools/model/model_utils.py +11 -39
- simtools/model/site_model.py +161 -0
- simtools/model/telescope_model.py +143 -633
- simtools/production_configuration/calculate_statistical_errors_grid_point.py +454 -0
- simtools/production_configuration/event_scaler.py +146 -0
- simtools/production_configuration/generate_simulation_config.py +193 -0
- simtools/production_configuration/interpolation_handler.py +197 -0
- simtools/ray_tracing/__init__.py +0 -0
- simtools/ray_tracing/mirror_panel_psf.py +280 -0
- simtools/{psf_analysis.py → ray_tracing/psf_analysis.py} +133 -47
- simtools/ray_tracing/ray_tracing.py +646 -0
- simtools/runners/__init__.py +0 -0
- simtools/runners/corsika_runner.py +240 -0
- simtools/runners/corsika_simtel_runner.py +225 -0
- simtools/runners/runner_services.py +307 -0
- simtools/runners/simtel_runner.py +224 -0
- simtools/schemas/array_elements.yml +137 -0
- simtools/schemas/integration_tests_config.metaschema.yml +93 -0
- simtools/schemas/metadata.metaschema.yml +6 -0
- simtools/schemas/model_parameter.metaschema.yml +78 -0
- simtools/schemas/{data.metaschema.yml → model_parameter_and_data_schema.metaschema.yml} +27 -44
- simtools/schemas/model_parameters/adjust_gain.schema.yml +37 -0
- simtools/schemas/model_parameters/altitude.schema.yml +37 -0
- simtools/schemas/model_parameters/array_coordinates.schema.yml +33 -0
- simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +77 -0
- simtools/schemas/model_parameters/array_element_position_ground.schema.yml +39 -0
- simtools/schemas/model_parameters/array_element_position_utm.schema.yml +39 -0
- simtools/schemas/model_parameters/array_layouts.schema.yml +48 -0
- simtools/schemas/model_parameters/array_triggers.schema.yml +93 -0
- simtools/schemas/model_parameters/asum_clipping.schema.yml +38 -0
- simtools/schemas/model_parameters/asum_offset.schema.yml +35 -0
- simtools/schemas/model_parameters/asum_shaping.schema.yml +35 -0
- simtools/schemas/model_parameters/asum_threshold.schema.yml +38 -0
- simtools/schemas/model_parameters/atmospheric_profile.schema.yml +32 -0
- simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +35 -0
- simtools/schemas/model_parameters/axes_offsets.schema.yml +53 -0
- simtools/schemas/model_parameters/camera_body_diameter.schema.yml +40 -0
- simtools/schemas/model_parameters/camera_body_shape.schema.yml +45 -0
- simtools/schemas/model_parameters/camera_config_file.schema.yml +40 -0
- simtools/schemas/model_parameters/camera_config_rotate.schema.yml +36 -0
- simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +43 -0
- simtools/schemas/model_parameters/camera_degraded_map.schema.yml +42 -0
- simtools/schemas/model_parameters/camera_depth.schema.yml +42 -0
- simtools/schemas/model_parameters/camera_filter.schema.yml +45 -0
- simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +29 -0
- simtools/schemas/model_parameters/camera_pixels.schema.yml +36 -0
- simtools/schemas/model_parameters/camera_transmission.schema.yml +41 -0
- simtools/schemas/model_parameters/channels_per_chip.schema.yml +36 -0
- simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +35 -0
- simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +27 -0
- simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +38 -0
- simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +28 -0
- simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +23 -0
- simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +27 -0
- simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +28 -0
- simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +27 -0
- simtools/schemas/model_parameters/corsika_observation_level.schema.yml +38 -0
- simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +52 -0
- simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +27 -0
- simtools/schemas/model_parameters/dark_events.schema.yml +32 -0
- simtools/schemas/model_parameters/default_trigger.schema.yml +35 -0
- simtools/schemas/model_parameters/design_model.schema.yml +31 -0
- simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +32 -0
- simtools/schemas/model_parameters/disc_bins.schema.yml +39 -0
- simtools/schemas/model_parameters/disc_start.schema.yml +41 -0
- simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +42 -0
- simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +41 -0
- simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +41 -0
- simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +39 -0
- simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +40 -0
- simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +41 -0
- simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +33 -0
- simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +42 -0
- simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +37 -0
- simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +44 -0
- simtools/schemas/model_parameters/discriminator_threshold.schema.yml +36 -0
- simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +45 -0
- simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +40 -0
- simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +41 -0
- simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +38 -0
- simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +38 -0
- simtools/schemas/model_parameters/dish_shape_length.schema.yml +41 -0
- simtools/schemas/model_parameters/dsum_clipping.schema.yml +38 -0
- simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +38 -0
- simtools/schemas/model_parameters/dsum_offset.schema.yml +37 -0
- simtools/schemas/model_parameters/dsum_pedsub.schema.yml +33 -0
- simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +39 -0
- simtools/schemas/model_parameters/dsum_prescale.schema.yml +44 -0
- simtools/schemas/model_parameters/dsum_presum_max.schema.yml +38 -0
- simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +45 -0
- simtools/schemas/model_parameters/dsum_shaping.schema.yml +44 -0
- simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +32 -0
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +43 -0
- simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +42 -0
- simtools/schemas/model_parameters/effective_focal_length.schema.yml +61 -0
- simtools/schemas/model_parameters/epsg_code.schema.yml +37 -0
- simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +35 -0
- simtools/schemas/model_parameters/fadc_amplitude.schema.yml +46 -0
- simtools/schemas/model_parameters/fadc_bins.schema.yml +40 -0
- simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +50 -0
- simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +38 -0
- simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +42 -0
- simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +49 -0
- simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +47 -0
- simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +51 -0
- simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +37 -0
- simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +43 -0
- simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +49 -0
- simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +43 -0
- simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +39 -0
- simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +42 -0
- simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +40 -0
- simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +50 -0
- simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +42 -0
- simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +41 -0
- simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +42 -0
- simtools/schemas/model_parameters/fadc_max_signal.schema.yml +43 -0
- simtools/schemas/model_parameters/fadc_max_sum.schema.yml +39 -0
- simtools/schemas/model_parameters/fadc_mhz.schema.yml +31 -0
- simtools/schemas/model_parameters/fadc_noise.schema.yml +41 -0
- simtools/schemas/model_parameters/fadc_pedestal.schema.yml +40 -0
- simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +39 -0
- simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +50 -0
- simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +43 -0
- simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +43 -0
- simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +42 -0
- simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +41 -0
- simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +42 -0
- simtools/schemas/model_parameters/flatfielding.schema.yml +37 -0
- simtools/schemas/model_parameters/focal_length.schema.yml +45 -0
- simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +158 -0
- simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +29 -0
- simtools/schemas/model_parameters/focus_offset.schema.yml +66 -0
- simtools/schemas/model_parameters/gain_variation.schema.yml +43 -0
- simtools/schemas/model_parameters/geomag_horizontal.schema.yml +34 -0
- simtools/schemas/model_parameters/geomag_rotation.schema.yml +37 -0
- simtools/schemas/model_parameters/geomag_vertical.schema.yml +34 -0
- simtools/schemas/model_parameters/hg_lg_variation.schema.yml +36 -0
- simtools/schemas/model_parameters/iobuf_maximum.schema.yml +34 -0
- simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +34 -0
- simtools/schemas/model_parameters/laser_events.schema.yml +36 -0
- simtools/schemas/model_parameters/laser_external_trigger.schema.yml +35 -0
- simtools/schemas/model_parameters/laser_photons.schema.yml +32 -0
- simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +34 -0
- simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +34 -0
- simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +33 -0
- simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +33 -0
- simtools/schemas/model_parameters/laser_var_photons.schema.yml +33 -0
- simtools/schemas/model_parameters/laser_wavelength.schema.yml +33 -0
- simtools/schemas/model_parameters/led_events.schema.yml +34 -0
- simtools/schemas/model_parameters/led_photons.schema.yml +34 -0
- simtools/schemas/model_parameters/led_pulse_offset.schema.yml +32 -0
- simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +33 -0
- simtools/schemas/model_parameters/led_var_photons.schema.yml +34 -0
- simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +41 -0
- simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +43 -0
- simtools/schemas/model_parameters/min_photoelectrons.schema.yml +35 -0
- simtools/schemas/model_parameters/min_photons.schema.yml +32 -0
- simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +36 -0
- simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +64 -0
- simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +64 -0
- simtools/schemas/model_parameters/mirror_class.schema.yml +41 -0
- simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +51 -0
- simtools/schemas/model_parameters/mirror_focal_length.schema.yml +42 -0
- simtools/schemas/model_parameters/mirror_list.schema.yml +38 -0
- simtools/schemas/model_parameters/mirror_offset.schema.yml +41 -0
- simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +39 -0
- simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +61 -0
- simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +40 -0
- simtools/schemas/model_parameters/multiplicity_offset.schema.yml +46 -0
- simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +51 -0
- simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +37 -0
- simtools/schemas/model_parameters/nsb_offaxis.schema.yml +79 -0
- simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +47 -0
- simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +34 -0
- simtools/schemas/model_parameters/nsb_reference_value.schema.yml +33 -0
- simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +35 -0
- simtools/schemas/model_parameters/nsb_skymap.schema.yml +39 -0
- simtools/schemas/model_parameters/nsb_spectrum.schema.yml +50 -0
- simtools/schemas/model_parameters/num_gains.schema.yml +34 -0
- simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +33 -0
- simtools/schemas/model_parameters/optics_properties.schema.yml +31 -0
- simtools/schemas/model_parameters/parabolic_dish.schema.yml +32 -0
- simtools/schemas/model_parameters/pedestal_events.schema.yml +32 -0
- simtools/schemas/model_parameters/photon_delay.schema.yml +38 -0
- simtools/schemas/model_parameters/photons_per_run.schema.yml +33 -0
- simtools/schemas/model_parameters/pixel_cells.schema.yml +35 -0
- simtools/schemas/model_parameters/pixels_parallel.schema.yml +54 -0
- simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +40 -0
- simtools/schemas/model_parameters/pm_average_gain.schema.yml +34 -0
- simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +40 -0
- simtools/schemas/model_parameters/pm_gain_index.schema.yml +36 -0
- simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +41 -0
- simtools/schemas/model_parameters/pm_transit_time.schema.yml +63 -0
- simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +39 -0
- simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +42 -0
- simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +33 -0
- simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +33 -0
- simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +29 -0
- simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +168 -0
- simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +36 -0
- simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +34 -0
- simtools/schemas/model_parameters/qe_variation.schema.yml +43 -0
- simtools/schemas/model_parameters/quantum_efficiency.schema.yml +42 -0
- simtools/schemas/model_parameters/random_focal_length.schema.yml +45 -0
- simtools/schemas/model_parameters/random_generator.schema.yml +36 -0
- simtools/schemas/model_parameters/reference_point_altitude.schema.yml +35 -0
- simtools/schemas/model_parameters/reference_point_latitude.schema.yml +36 -0
- simtools/schemas/model_parameters/reference_point_longitude.schema.yml +36 -0
- simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +34 -0
- simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +34 -0
- simtools/schemas/model_parameters/sampled_output.schema.yml +31 -0
- simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +34 -0
- simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +79 -0
- simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +42 -0
- simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +41 -0
- simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +33 -0
- simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +36 -0
- simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +29 -0
- simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +168 -0
- simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +36 -0
- simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +35 -0
- simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +37 -0
- simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +40 -0
- simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +40 -0
- simtools/schemas/model_parameters/store_photoelectrons.schema.yml +41 -0
- simtools/schemas/model_parameters/tailcut_scale.schema.yml +40 -0
- simtools/schemas/model_parameters/telescope_axis_height.schema.yml +31 -0
- simtools/schemas/model_parameters/telescope_random_angle.schema.yml +35 -0
- simtools/schemas/model_parameters/telescope_random_error.schema.yml +34 -0
- simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +37 -0
- simtools/schemas/model_parameters/telescope_transmission.schema.yml +113 -0
- simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +41 -0
- simtools/schemas/model_parameters/teltrig_min_time.schema.yml +36 -0
- simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +36 -0
- simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +37 -0
- simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +38 -0
- simtools/schemas/model_parameters/transit_time_error.schema.yml +45 -0
- simtools/schemas/model_parameters/transit_time_jitter.schema.yml +36 -0
- simtools/schemas/model_parameters/trigger_current_limit.schema.yml +32 -0
- simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +53 -0
- simtools/schemas/model_parameters/trigger_pixels.schema.yml +40 -0
- simtools/simtel/simtel_config_reader.py +353 -0
- simtools/simtel/simtel_config_writer.py +244 -63
- simtools/simtel/{simtel_events.py → simtel_io_events.py} +26 -25
- simtools/simtel/simtel_io_histogram.py +661 -0
- simtools/simtel/simtel_io_histograms.py +569 -0
- simtools/simtel/simulator_array.py +145 -0
- simtools/simtel/{simtel_runner_camera_efficiency.py → simulator_camera_efficiency.py} +76 -52
- simtools/simtel/simulator_light_emission.py +473 -0
- simtools/simtel/simulator_ray_tracing.py +262 -0
- simtools/simulator.py +220 -446
- simtools/testing/__init__.py +0 -0
- simtools/testing/assertions.py +151 -0
- simtools/testing/configuration.py +226 -0
- simtools/testing/helpers.py +42 -0
- simtools/testing/validate_output.py +240 -0
- simtools/utils/general.py +340 -437
- simtools/utils/geometry.py +12 -12
- simtools/utils/names.py +257 -644
- simtools/utils/value_conversion.py +176 -0
- simtools/version.py +3 -1
- simtools/visualization/legend_handlers.py +135 -152
- simtools/visualization/plot_camera.py +379 -0
- simtools/visualization/visualize.py +346 -167
- gammasimtools-0.6.1.dist-info/METADATA +0 -180
- gammasimtools-0.6.1.dist-info/RECORD +0 -91
- gammasimtools-0.6.1.dist-info/entry_points.txt +0 -23
- simtools/_dev_version/scm_version.py +0 -10
- simtools/applications/db_development_tools/add_new_parameter_to_db.py +0 -81
- simtools/applications/db_development_tools/add_unit_to_parameter_in_db.py +0 -59
- simtools/applications/db_development_tools/mark_non_optics_parameters_non_applicable.py +0 -102
- simtools/applications/get_parameter.py +0 -92
- simtools/applications/make_regular_arrays.py +0 -160
- simtools/applications/produce_array_config.py +0 -136
- simtools/applications/production.py +0 -313
- simtools/applications/sim_showers_for_trigger_rates.py +0 -187
- simtools/applications/tune_psf.py +0 -334
- simtools/corsika/corsika_default_config.py +0 -282
- simtools/corsika/corsika_runner.py +0 -450
- simtools/corsika_simtel/corsika_simtel_runner.py +0 -197
- simtools/db_handler.py +0 -1480
- simtools/ray_tracing.py +0 -525
- simtools/simtel/simtel_histograms.py +0 -414
- simtools/simtel/simtel_runner.py +0 -244
- simtools/simtel/simtel_runner_array.py +0 -293
- simtools/simtel/simtel_runner_ray_tracing.py +0 -277
- {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.2.dist-info}/LICENSE +0 -0
- {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.2.dist-info}/top_level.txt +0 -0
- /simtools/{corsika_simtel → db}/__init__.py +0 -0
|
@@ -0,0 +1,1246 @@
|
|
|
1
|
+
"""Module to handle interaction with DB."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from threading import Lock
|
|
7
|
+
|
|
8
|
+
import gridfs
|
|
9
|
+
from bson.objectid import ObjectId
|
|
10
|
+
from packaging.version import Version
|
|
11
|
+
from pymongo import ASCENDING, MongoClient
|
|
12
|
+
from pymongo.errors import BulkWriteError
|
|
13
|
+
|
|
14
|
+
from simtools.db import db_array_elements, db_from_repo_handler
|
|
15
|
+
from simtools.io_operations import io_handler
|
|
16
|
+
from simtools.utils import names, value_conversion
|
|
17
|
+
|
|
18
|
+
__all__ = ["DatabaseHandler"]
|
|
19
|
+
|
|
20
|
+
logging.getLogger("pymongo").setLevel(logging.WARNING)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# pylint: disable=unsubscriptable-object
|
|
24
|
+
# The above comment is because pylint does not know that DatabaseHandler.db_client is subscriptable
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DatabaseHandler:
|
|
28
|
+
"""
|
|
29
|
+
DatabaseHandler provides the interface to the DB.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
mongo_db_config: dict
|
|
34
|
+
Dictionary with the MongoDB configuration with the following entries:
|
|
35
|
+
"db_server" - DB server address
|
|
36
|
+
"db_api_port" - Port to use
|
|
37
|
+
"db_api_user" - API username
|
|
38
|
+
"db_api_pw" - Password for the API user
|
|
39
|
+
"db_api_authentication_database" - DB with user info (optional, default is "admin")
|
|
40
|
+
"db_simulation_model" - Name of simulation model database
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
DB_CTA_SIMULATION_MODEL_DESCRIPTIONS = "CTA-Simulation-Model-Descriptions"
|
|
44
|
+
# DB collection with updates field names
|
|
45
|
+
DB_DERIVED_VALUES = "Staging-CTA-Simulation-Model-Derived-Values"
|
|
46
|
+
|
|
47
|
+
ALLOWED_FILE_EXTENSIONS = [".dat", ".txt", ".lis", ".cfg", ".yml", ".yaml", ".ecsv"]
|
|
48
|
+
|
|
49
|
+
db_client = None
|
|
50
|
+
site_parameters_cached = {}
|
|
51
|
+
model_parameters_cached = {}
|
|
52
|
+
model_versions_cached = {}
|
|
53
|
+
corsika_configuration_parameters_cached = {}
|
|
54
|
+
|
|
55
|
+
def __init__(self, mongo_db_config=None):
|
|
56
|
+
"""Initialize the DatabaseHandler class."""
|
|
57
|
+
self._logger = logging.getLogger(__name__)
|
|
58
|
+
|
|
59
|
+
self.mongo_db_config = mongo_db_config
|
|
60
|
+
self.io_handler = io_handler.IOHandler()
|
|
61
|
+
self.list_of_collections = {}
|
|
62
|
+
|
|
63
|
+
self._set_up_connection()
|
|
64
|
+
self._find_latest_simulation_model_db()
|
|
65
|
+
|
|
66
|
+
def _set_up_connection(self):
|
|
67
|
+
"""Open the connection to MongoDB."""
|
|
68
|
+
if self.mongo_db_config and DatabaseHandler.db_client is None:
|
|
69
|
+
lock = Lock()
|
|
70
|
+
with lock:
|
|
71
|
+
DatabaseHandler.db_client = self._open_mongo_db()
|
|
72
|
+
|
|
73
|
+
def _open_mongo_db(self):
|
|
74
|
+
"""
|
|
75
|
+
Open a connection to MongoDB and return the client to read/write to the DB with.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
A PyMongo DB client
|
|
80
|
+
|
|
81
|
+
Raises
|
|
82
|
+
------
|
|
83
|
+
KeyError
|
|
84
|
+
If the DB configuration is invalid
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
direct_connection = self.mongo_db_config["db_server"] in (
|
|
88
|
+
"localhost",
|
|
89
|
+
"simtools-mongodb",
|
|
90
|
+
)
|
|
91
|
+
return MongoClient(
|
|
92
|
+
self.mongo_db_config["db_server"],
|
|
93
|
+
port=self.mongo_db_config["db_api_port"],
|
|
94
|
+
username=self.mongo_db_config["db_api_user"],
|
|
95
|
+
password=self.mongo_db_config["db_api_pw"],
|
|
96
|
+
authSource=self.mongo_db_config.get("db_api_authentication_database", "admin"),
|
|
97
|
+
directConnection=direct_connection,
|
|
98
|
+
ssl=not direct_connection,
|
|
99
|
+
tlsallowinvalidhostnames=True,
|
|
100
|
+
tlsallowinvalidcertificates=True,
|
|
101
|
+
)
|
|
102
|
+
except KeyError:
|
|
103
|
+
self._logger.error("Invalid setting of DB configuration")
|
|
104
|
+
raise
|
|
105
|
+
|
|
106
|
+
def _find_latest_simulation_model_db(self):
|
|
107
|
+
"""
|
|
108
|
+
Find the latest released version of the simulation model and update the DB config.
|
|
109
|
+
|
|
110
|
+
This is indicated by adding "LATEST" to the name of the simulation model database
|
|
111
|
+
(field "db_simulation_model" in the database configuration dictionary).
|
|
112
|
+
Only released versions are considered, pre-releases are ignored.
|
|
113
|
+
|
|
114
|
+
Raises
|
|
115
|
+
------
|
|
116
|
+
ValueError
|
|
117
|
+
If the "LATEST" version is requested but no versions are found in the DB.
|
|
118
|
+
|
|
119
|
+
"""
|
|
120
|
+
try:
|
|
121
|
+
if not self.mongo_db_config["db_simulation_model"].endswith("LATEST"):
|
|
122
|
+
return
|
|
123
|
+
except TypeError:
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
prefix = self.mongo_db_config["db_simulation_model"].replace("LATEST", "")
|
|
127
|
+
list_of_db_names = self.db_client.list_database_names()
|
|
128
|
+
filtered_list_of_db_names = [s for s in list_of_db_names if s.startswith(prefix)]
|
|
129
|
+
versioned_strings = []
|
|
130
|
+
version_pattern = re.compile(
|
|
131
|
+
rf"{re.escape(prefix)}v?(\d+)-(\d+)-(\d+)(?:-([a-zA-Z0-9_.]+))?"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
for s in filtered_list_of_db_names:
|
|
135
|
+
match = version_pattern.search(s)
|
|
136
|
+
# A version is considered a pre-release if it contains a '-' character (re group 4)
|
|
137
|
+
if match and match.group(4) is None:
|
|
138
|
+
version_str = match.group(1) + "." + match.group(2) + "." + match.group(3)
|
|
139
|
+
version = Version(version_str)
|
|
140
|
+
versioned_strings.append((s, version))
|
|
141
|
+
|
|
142
|
+
if versioned_strings:
|
|
143
|
+
latest_string, _ = max(versioned_strings, key=lambda x: x[1])
|
|
144
|
+
self.mongo_db_config["db_simulation_model"] = latest_string
|
|
145
|
+
self._logger.info(
|
|
146
|
+
f"Updated the DB simulation model to the latest version {latest_string}"
|
|
147
|
+
)
|
|
148
|
+
else:
|
|
149
|
+
raise ValueError("Found LATEST in the DB name but no matching versions found in DB.")
|
|
150
|
+
|
|
151
|
+
def get_model_parameters(
|
|
152
|
+
self,
|
|
153
|
+
site,
|
|
154
|
+
array_element_name,
|
|
155
|
+
model_version,
|
|
156
|
+
collection="telescope",
|
|
157
|
+
only_applicable=False,
|
|
158
|
+
):
|
|
159
|
+
"""
|
|
160
|
+
Get parameters from MongoDB or simulation model repository for an array element.
|
|
161
|
+
|
|
162
|
+
An array element can be e.g., a telescope or a calibration device.
|
|
163
|
+
Read parameters for design and for the specified array element (if necessary). This allows
|
|
164
|
+
to overwrite design parameters with specific parameters without having to copy
|
|
165
|
+
all model parameters when changing only a few.
|
|
166
|
+
|
|
167
|
+
Parameters
|
|
168
|
+
----------
|
|
169
|
+
site: str
|
|
170
|
+
Site name.
|
|
171
|
+
array_element_name: str
|
|
172
|
+
Name of the array element model (e.g. LSTN-01, MSTS-design)
|
|
173
|
+
model_version: str
|
|
174
|
+
Version of the model.
|
|
175
|
+
collection: str
|
|
176
|
+
collection of array element (e.g. telescopes, calibration_devices)
|
|
177
|
+
only_applicable: bool
|
|
178
|
+
If True, only applicable parameters will be read.
|
|
179
|
+
|
|
180
|
+
Returns
|
|
181
|
+
-------
|
|
182
|
+
dict containing the parameters
|
|
183
|
+
|
|
184
|
+
"""
|
|
185
|
+
_site, _array_element_name, _model_version = self._validate_model_input(
|
|
186
|
+
site, array_element_name, model_version
|
|
187
|
+
)
|
|
188
|
+
array_element_list = db_array_elements.get_array_element_list_for_db_query(
|
|
189
|
+
_array_element_name, self, _model_version, collection
|
|
190
|
+
)
|
|
191
|
+
pars = {}
|
|
192
|
+
for array_element in array_element_list:
|
|
193
|
+
_array_elements_cache_key = self._parameter_cache_key(
|
|
194
|
+
site, array_element, model_version, collection
|
|
195
|
+
)
|
|
196
|
+
try:
|
|
197
|
+
pars.update(DatabaseHandler.model_parameters_cached[_array_elements_cache_key])
|
|
198
|
+
except KeyError:
|
|
199
|
+
pars.update(
|
|
200
|
+
self.read_mongo_db(
|
|
201
|
+
self.mongo_db_config.get("db_simulation_model", None),
|
|
202
|
+
array_element_name=array_element,
|
|
203
|
+
model_version=_model_version,
|
|
204
|
+
collection_name=collection,
|
|
205
|
+
run_location=None,
|
|
206
|
+
write_files=False,
|
|
207
|
+
only_applicable=only_applicable,
|
|
208
|
+
)
|
|
209
|
+
)
|
|
210
|
+
if self.mongo_db_config.get("db_simulation_model_url", None) is not None:
|
|
211
|
+
pars = db_from_repo_handler.update_model_parameters_from_repo(
|
|
212
|
+
parameters=pars,
|
|
213
|
+
site=_site,
|
|
214
|
+
parameter_collection=collection,
|
|
215
|
+
array_element_name=array_element,
|
|
216
|
+
model_version=_model_version,
|
|
217
|
+
db_simulation_model_url=self.mongo_db_config.get("db_simulation_model_url"),
|
|
218
|
+
)
|
|
219
|
+
DatabaseHandler.model_parameters_cached[_array_elements_cache_key] = pars
|
|
220
|
+
|
|
221
|
+
return pars
|
|
222
|
+
|
|
223
|
+
def get_collection(self, db_name, collection_name):
|
|
224
|
+
"""
|
|
225
|
+
Get a collection from the DB.
|
|
226
|
+
|
|
227
|
+
Parameters
|
|
228
|
+
----------
|
|
229
|
+
db_name: str
|
|
230
|
+
Name of the DB.
|
|
231
|
+
collection_name: str
|
|
232
|
+
Name of the collection.
|
|
233
|
+
|
|
234
|
+
Returns
|
|
235
|
+
-------
|
|
236
|
+
pymongo.collection.Collection
|
|
237
|
+
The collection from the DB.
|
|
238
|
+
|
|
239
|
+
"""
|
|
240
|
+
db_name = self._get_db_name(db_name)
|
|
241
|
+
return DatabaseHandler.db_client[db_name][collection_name]
|
|
242
|
+
|
|
243
|
+
def export_file_db(self, db_name, dest, file_name):
|
|
244
|
+
"""
|
|
245
|
+
Get file from the DB and write to disk.
|
|
246
|
+
|
|
247
|
+
Parameters
|
|
248
|
+
----------
|
|
249
|
+
db_name: str
|
|
250
|
+
Name of the DB to search in.
|
|
251
|
+
dest: str or Path
|
|
252
|
+
Location where to write the file to.
|
|
253
|
+
file_name: str
|
|
254
|
+
Name of the file to get.
|
|
255
|
+
|
|
256
|
+
Returns
|
|
257
|
+
-------
|
|
258
|
+
file_id: GridOut._id
|
|
259
|
+
the database ID the file was assigned when it was inserted to the DB.
|
|
260
|
+
|
|
261
|
+
Raises
|
|
262
|
+
------
|
|
263
|
+
FileNotFoundError
|
|
264
|
+
If the desired file is not found.
|
|
265
|
+
|
|
266
|
+
"""
|
|
267
|
+
db_name = self._get_db_name(db_name)
|
|
268
|
+
|
|
269
|
+
self._logger.debug(f"Getting {file_name} from {db_name} and writing it to {dest}")
|
|
270
|
+
file_path_instance = self._get_file_mongo_db(db_name, file_name)
|
|
271
|
+
self._write_file_from_mongo_to_disk(db_name, dest, file_path_instance)
|
|
272
|
+
return file_path_instance._id # pylint: disable=protected-access;
|
|
273
|
+
|
|
274
|
+
def export_model_files(self, parameters, dest):
|
|
275
|
+
"""
|
|
276
|
+
Export all the files in a model from the DB and write them to disk.
|
|
277
|
+
|
|
278
|
+
Parameters
|
|
279
|
+
----------
|
|
280
|
+
parameters: dict
|
|
281
|
+
Dict of model parameters
|
|
282
|
+
dest: str or Path
|
|
283
|
+
Location where to write the files to.
|
|
284
|
+
|
|
285
|
+
Raises
|
|
286
|
+
------
|
|
287
|
+
FileNotFoundError
|
|
288
|
+
if a file in parameters.values is not found
|
|
289
|
+
|
|
290
|
+
"""
|
|
291
|
+
if self.mongo_db_config:
|
|
292
|
+
for info in parameters.values():
|
|
293
|
+
if not info or not info.get("file") or info["value"] is None:
|
|
294
|
+
continue
|
|
295
|
+
if Path(dest).joinpath(info["value"]).exists():
|
|
296
|
+
continue
|
|
297
|
+
file = self._get_file_mongo_db(self._get_db_name(), info["value"])
|
|
298
|
+
self._write_file_from_mongo_to_disk(self._get_db_name(), dest, file)
|
|
299
|
+
if self.mongo_db_config.get("db_simulation_model_url", None) is not None:
|
|
300
|
+
self._logger.warning(
|
|
301
|
+
"Exporting model files from simulation model repository not yet implemented"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
@staticmethod
|
|
305
|
+
def _is_file(value):
|
|
306
|
+
"""Verify if a parameter value is a file name."""
|
|
307
|
+
return any(ext in str(value) for ext in DatabaseHandler.ALLOWED_FILE_EXTENSIONS)
|
|
308
|
+
|
|
309
|
+
def read_mongo_db(
|
|
310
|
+
self,
|
|
311
|
+
db_name,
|
|
312
|
+
array_element_name,
|
|
313
|
+
model_version,
|
|
314
|
+
run_location,
|
|
315
|
+
collection_name,
|
|
316
|
+
write_files=True,
|
|
317
|
+
only_applicable=False,
|
|
318
|
+
):
|
|
319
|
+
"""
|
|
320
|
+
Build and execute query to Read the MongoDB for a specific array element.
|
|
321
|
+
|
|
322
|
+
Also writes the files listed in the parameter values into the sim_telarray run location
|
|
323
|
+
|
|
324
|
+
Parameters
|
|
325
|
+
----------
|
|
326
|
+
db_name: str
|
|
327
|
+
the name of the DB
|
|
328
|
+
array_element_name: str
|
|
329
|
+
Name of the array element model (e.g. MSTN-design ...)
|
|
330
|
+
model_version: str
|
|
331
|
+
Version of the model.
|
|
332
|
+
run_location: Path or str
|
|
333
|
+
The sim_telarray run location to write the tabulated data files into.
|
|
334
|
+
collection_name: str
|
|
335
|
+
The name of the collection to read from.
|
|
336
|
+
write_files: bool
|
|
337
|
+
If true, write the files to the run_location.
|
|
338
|
+
only_applicable: bool
|
|
339
|
+
If True, only applicable parameters will be read.
|
|
340
|
+
|
|
341
|
+
Returns
|
|
342
|
+
-------
|
|
343
|
+
dict containing the parameters
|
|
344
|
+
|
|
345
|
+
Raises
|
|
346
|
+
------
|
|
347
|
+
ValueError
|
|
348
|
+
if query returned zero results.
|
|
349
|
+
|
|
350
|
+
"""
|
|
351
|
+
collection = self.get_collection(db_name, collection_name)
|
|
352
|
+
_parameters = {}
|
|
353
|
+
|
|
354
|
+
query = {
|
|
355
|
+
"instrument": array_element_name,
|
|
356
|
+
"version": self.model_version(model_version, db_name),
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if only_applicable:
|
|
360
|
+
query["applicable"] = True
|
|
361
|
+
if collection.count_documents(query) < 1:
|
|
362
|
+
raise ValueError(
|
|
363
|
+
"The following query returned zero results! Check the input data and rerun.\n",
|
|
364
|
+
query,
|
|
365
|
+
)
|
|
366
|
+
for post in collection.find(query).sort("parameter", ASCENDING):
|
|
367
|
+
par_now = post["parameter"]
|
|
368
|
+
_parameters[par_now] = post
|
|
369
|
+
_parameters[par_now].pop("parameter", None)
|
|
370
|
+
_parameters[par_now].pop("instrument", None)
|
|
371
|
+
_parameters[par_now]["entry_date"] = ObjectId(post["_id"]).generation_time
|
|
372
|
+
if _parameters[par_now]["file"] and write_files:
|
|
373
|
+
file = self._get_file_mongo_db(db_name, _parameters[par_now]["value"])
|
|
374
|
+
self._write_file_from_mongo_to_disk(db_name, run_location, file)
|
|
375
|
+
|
|
376
|
+
return _parameters
|
|
377
|
+
|
|
378
|
+
def get_site_parameters(
|
|
379
|
+
self,
|
|
380
|
+
site,
|
|
381
|
+
model_version,
|
|
382
|
+
only_applicable=False,
|
|
383
|
+
):
|
|
384
|
+
"""
|
|
385
|
+
Get parameters from either MongoDB or simulation model repository for a specific site.
|
|
386
|
+
|
|
387
|
+
Parameters
|
|
388
|
+
----------
|
|
389
|
+
site: str
|
|
390
|
+
Site name.
|
|
391
|
+
model_version: str
|
|
392
|
+
Version of the model.
|
|
393
|
+
only_applicable: bool
|
|
394
|
+
If True, only applicable parameters will be read.
|
|
395
|
+
|
|
396
|
+
Returns
|
|
397
|
+
-------
|
|
398
|
+
dict containing the parameters
|
|
399
|
+
|
|
400
|
+
"""
|
|
401
|
+
_site, _, _model_version = self._validate_model_input(site, None, model_version)
|
|
402
|
+
_db_name = self._get_db_name()
|
|
403
|
+
_site_cache_key = self._parameter_cache_key(site, None, model_version)
|
|
404
|
+
try:
|
|
405
|
+
return DatabaseHandler.site_parameters_cached[_site_cache_key]
|
|
406
|
+
except KeyError:
|
|
407
|
+
pass
|
|
408
|
+
|
|
409
|
+
_pars = self._get_site_parameters_mongo_db(
|
|
410
|
+
_db_name,
|
|
411
|
+
_site,
|
|
412
|
+
_model_version,
|
|
413
|
+
only_applicable,
|
|
414
|
+
)
|
|
415
|
+
# update simulation model using repository
|
|
416
|
+
if self.mongo_db_config.get("db_simulation_model_url", None) is not None:
|
|
417
|
+
_pars = db_from_repo_handler.update_model_parameters_from_repo(
|
|
418
|
+
parameters=_pars,
|
|
419
|
+
site=_site,
|
|
420
|
+
array_element_name=None,
|
|
421
|
+
parameter_collection="site",
|
|
422
|
+
model_version=_model_version,
|
|
423
|
+
db_simulation_model_url=self.mongo_db_config.get("db_simulation_model_url", None),
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
DatabaseHandler.site_parameters_cached[_site_cache_key] = _pars
|
|
427
|
+
return DatabaseHandler.site_parameters_cached[_site_cache_key]
|
|
428
|
+
|
|
429
|
+
def _get_site_parameters_mongo_db(self, db_name, site, model_version, only_applicable=False):
|
|
430
|
+
"""
|
|
431
|
+
Get parameters from MongoDB for a specific site.
|
|
432
|
+
|
|
433
|
+
Parameters
|
|
434
|
+
----------
|
|
435
|
+
db_name: str
|
|
436
|
+
The name of the DB.
|
|
437
|
+
site: str
|
|
438
|
+
Site name.
|
|
439
|
+
model_version: str
|
|
440
|
+
Version of the model.
|
|
441
|
+
only_applicable: bool
|
|
442
|
+
If True, only applicable parameters will be read.
|
|
443
|
+
|
|
444
|
+
Returns
|
|
445
|
+
-------
|
|
446
|
+
dict containing the parameters
|
|
447
|
+
|
|
448
|
+
Raises
|
|
449
|
+
------
|
|
450
|
+
ValueError
|
|
451
|
+
if query returned zero results.
|
|
452
|
+
|
|
453
|
+
"""
|
|
454
|
+
collection = self.get_collection(db_name, "sites")
|
|
455
|
+
_parameters = {}
|
|
456
|
+
|
|
457
|
+
query = {
|
|
458
|
+
"site": site,
|
|
459
|
+
"version": model_version,
|
|
460
|
+
}
|
|
461
|
+
if only_applicable:
|
|
462
|
+
query["applicable"] = True
|
|
463
|
+
if collection.count_documents(query) < 1:
|
|
464
|
+
raise ValueError(
|
|
465
|
+
"The following query returned zero results! Check the input data and rerun.\n",
|
|
466
|
+
query,
|
|
467
|
+
)
|
|
468
|
+
for post in collection.find(query).sort("parameter", ASCENDING):
|
|
469
|
+
par_now = post["parameter"]
|
|
470
|
+
_parameters[par_now] = post
|
|
471
|
+
_parameters[par_now].pop("parameter", None)
|
|
472
|
+
_parameters[par_now].pop("site", None)
|
|
473
|
+
_parameters[par_now]["entry_date"] = ObjectId(post["_id"]).generation_time
|
|
474
|
+
|
|
475
|
+
return _parameters
|
|
476
|
+
|
|
477
|
+
def get_derived_values(self, site, array_element_name, model_version):
|
|
478
|
+
"""
|
|
479
|
+
Get all derived values from the DB for a specific array element.
|
|
480
|
+
|
|
481
|
+
Parameters
|
|
482
|
+
----------
|
|
483
|
+
site: str
|
|
484
|
+
Site name.
|
|
485
|
+
array_element_name: str
|
|
486
|
+
Name of the array element model (e.g. MSTN, SSTS).
|
|
487
|
+
model_version: str
|
|
488
|
+
Version of the model.
|
|
489
|
+
|
|
490
|
+
Returns
|
|
491
|
+
-------
|
|
492
|
+
dict containing the parameters
|
|
493
|
+
|
|
494
|
+
"""
|
|
495
|
+
_, _array_element_name, _model_version = self._validate_model_input(
|
|
496
|
+
site, array_element_name, model_version
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
return self.read_mongo_db(
|
|
500
|
+
DatabaseHandler.DB_DERIVED_VALUES,
|
|
501
|
+
_array_element_name,
|
|
502
|
+
_model_version,
|
|
503
|
+
run_location=None,
|
|
504
|
+
collection_name="derived_values",
|
|
505
|
+
write_files=False,
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
def get_simulation_configuration_parameters(
|
|
509
|
+
self, simulation_software, site, array_element_name, model_version
|
|
510
|
+
):
|
|
511
|
+
"""
|
|
512
|
+
Get simulation configuration parameters from the DB.
|
|
513
|
+
|
|
514
|
+
Parameters
|
|
515
|
+
----------
|
|
516
|
+
simulation_software: str
|
|
517
|
+
Name of the simulation software.
|
|
518
|
+
site: str
|
|
519
|
+
Site name.
|
|
520
|
+
array_element_name: str
|
|
521
|
+
Name of the array element model (e.g. MSTN, SSTS).
|
|
522
|
+
model_version: str
|
|
523
|
+
Version of the model.
|
|
524
|
+
|
|
525
|
+
Returns
|
|
526
|
+
-------
|
|
527
|
+
dict containing the parameters
|
|
528
|
+
|
|
529
|
+
Raises
|
|
530
|
+
------
|
|
531
|
+
ValueError
|
|
532
|
+
if simulation_software is not valid.
|
|
533
|
+
"""
|
|
534
|
+
if simulation_software == "corsika":
|
|
535
|
+
return self.get_corsika_configuration_parameters(model_version)
|
|
536
|
+
if simulation_software == "simtel":
|
|
537
|
+
if site and array_element_name:
|
|
538
|
+
return self.get_model_parameters(
|
|
539
|
+
site, array_element_name, model_version, collection="configuration_sim_telarray"
|
|
540
|
+
)
|
|
541
|
+
return {}
|
|
542
|
+
raise ValueError(f"Unknown simulation software: {simulation_software}")
|
|
543
|
+
|
|
544
|
+
def get_corsika_configuration_parameters(self, model_version):
|
|
545
|
+
"""
|
|
546
|
+
Get CORSIKA configuration parameters from the DB.
|
|
547
|
+
|
|
548
|
+
Parameters
|
|
549
|
+
----------
|
|
550
|
+
model_version : str
|
|
551
|
+
Version of the model.
|
|
552
|
+
|
|
553
|
+
Returns
|
|
554
|
+
-------
|
|
555
|
+
dict
|
|
556
|
+
Configuration parameters for CORSIKA
|
|
557
|
+
"""
|
|
558
|
+
_corsika_cache_key = self._parameter_cache_key(None, None, model_version)
|
|
559
|
+
try:
|
|
560
|
+
return DatabaseHandler.corsika_configuration_parameters_cached[_corsika_cache_key]
|
|
561
|
+
except KeyError:
|
|
562
|
+
pass
|
|
563
|
+
DatabaseHandler.corsika_configuration_parameters_cached[_corsika_cache_key] = (
|
|
564
|
+
self.read_mongo_db(
|
|
565
|
+
db_name=self._get_db_name(),
|
|
566
|
+
array_element_name=None,
|
|
567
|
+
model_version=model_version,
|
|
568
|
+
run_location=None,
|
|
569
|
+
collection_name="configuration_corsika",
|
|
570
|
+
write_files=False,
|
|
571
|
+
)
|
|
572
|
+
)
|
|
573
|
+
return DatabaseHandler.corsika_configuration_parameters_cached[_corsika_cache_key]
|
|
574
|
+
|
|
575
|
+
def _validate_model_input(self, site, array_element_name, model_version):
|
|
576
|
+
"""
|
|
577
|
+
Validate input for model parameter queries.
|
|
578
|
+
|
|
579
|
+
site: str
|
|
580
|
+
Site name.
|
|
581
|
+
array_element_name: str
|
|
582
|
+
Name of the array element model (e.g. LSTN-01, MSTS-design)
|
|
583
|
+
model_version: str
|
|
584
|
+
Version of the model.
|
|
585
|
+
|
|
586
|
+
"""
|
|
587
|
+
return (
|
|
588
|
+
names.validate_site_name(site),
|
|
589
|
+
names.validate_array_element_name(array_element_name) if array_element_name else None,
|
|
590
|
+
self.model_version(model_version),
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
@staticmethod
|
|
594
|
+
def _get_file_mongo_db(db_name, file_name):
|
|
595
|
+
"""
|
|
596
|
+
Extract a file from MongoDB and return GridFS file instance.
|
|
597
|
+
|
|
598
|
+
Parameters
|
|
599
|
+
----------
|
|
600
|
+
db_name: str
|
|
601
|
+
the name of the DB with files of tabulated data
|
|
602
|
+
file_name: str
|
|
603
|
+
The name of the file requested
|
|
604
|
+
|
|
605
|
+
Returns
|
|
606
|
+
-------
|
|
607
|
+
GridOut
|
|
608
|
+
A file instance returned by GridFS find_one
|
|
609
|
+
|
|
610
|
+
Raises
|
|
611
|
+
------
|
|
612
|
+
FileNotFoundError
|
|
613
|
+
If the desired file is not found.
|
|
614
|
+
|
|
615
|
+
"""
|
|
616
|
+
db = DatabaseHandler.db_client[db_name]
|
|
617
|
+
file_system = gridfs.GridFS(db)
|
|
618
|
+
if file_system.exists({"filename": file_name}):
|
|
619
|
+
return file_system.find_one({"filename": file_name})
|
|
620
|
+
|
|
621
|
+
raise FileNotFoundError(f"The file {file_name} does not exist in the database {db_name}")
|
|
622
|
+
|
|
623
|
+
@staticmethod
|
|
624
|
+
def _write_file_from_mongo_to_disk(db_name, path, file):
|
|
625
|
+
"""
|
|
626
|
+
Extract a file from MongoDB and write it to disk.
|
|
627
|
+
|
|
628
|
+
Parameters
|
|
629
|
+
----------
|
|
630
|
+
db_name: str
|
|
631
|
+
the name of the DB with files of tabulated data
|
|
632
|
+
path: str or Path
|
|
633
|
+
The path to write the file to
|
|
634
|
+
file: GridOut
|
|
635
|
+
A file instance returned by GridFS find_one
|
|
636
|
+
"""
|
|
637
|
+
db = DatabaseHandler.db_client[db_name]
|
|
638
|
+
fs_output = gridfs.GridFSBucket(db)
|
|
639
|
+
with open(Path(path).joinpath(file.filename), "wb") as output_file:
|
|
640
|
+
fs_output.download_to_stream_by_name(file.filename, output_file)
|
|
641
|
+
|
|
642
|
+
def copy_array_element(
|
|
643
|
+
self,
|
|
644
|
+
db_name,
|
|
645
|
+
element_to_copy,
|
|
646
|
+
version_to_copy,
|
|
647
|
+
new_array_element_name,
|
|
648
|
+
collection_name="telescopes",
|
|
649
|
+
db_to_copy_to=None,
|
|
650
|
+
collection_to_copy_to=None,
|
|
651
|
+
):
|
|
652
|
+
"""
|
|
653
|
+
Copy a full array element configuration to a new array element name.
|
|
654
|
+
|
|
655
|
+
Only a specific version is copied.
|
|
656
|
+
(This function should be rarely used, probably only during "construction".)
|
|
657
|
+
|
|
658
|
+
Parameters
|
|
659
|
+
----------
|
|
660
|
+
db_name: str
|
|
661
|
+
the name of the DB to copy from
|
|
662
|
+
element_to_copy: str
|
|
663
|
+
The array element to copy
|
|
664
|
+
version_to_copy: str
|
|
665
|
+
The version of the configuration to copy
|
|
666
|
+
new_array_element_name: str
|
|
667
|
+
The name of the new array element
|
|
668
|
+
collection_name: str
|
|
669
|
+
The name of the collection to copy from.
|
|
670
|
+
db_to_copy_to: str
|
|
671
|
+
The name of the DB to copy to.
|
|
672
|
+
collection_to_copy_to: str
|
|
673
|
+
The name of the collection to copy to.
|
|
674
|
+
|
|
675
|
+
Raises
|
|
676
|
+
------
|
|
677
|
+
BulkWriteError
|
|
678
|
+
|
|
679
|
+
"""
|
|
680
|
+
db_name = self._get_db_name(db_name)
|
|
681
|
+
if db_to_copy_to is None:
|
|
682
|
+
db_to_copy_to = db_name
|
|
683
|
+
|
|
684
|
+
if collection_to_copy_to is None:
|
|
685
|
+
collection_to_copy_to = collection_name
|
|
686
|
+
|
|
687
|
+
self._logger.info(
|
|
688
|
+
f"Copying version {version_to_copy} of {element_to_copy} "
|
|
689
|
+
f"to the new array element {new_array_element_name} in the {db_to_copy_to} DB"
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
collection = self.get_collection(db_name, collection_name)
|
|
693
|
+
db_entries = []
|
|
694
|
+
|
|
695
|
+
_version_to_copy = self.model_version(version_to_copy)
|
|
696
|
+
|
|
697
|
+
query = {
|
|
698
|
+
"instrument": element_to_copy,
|
|
699
|
+
"version": _version_to_copy,
|
|
700
|
+
}
|
|
701
|
+
for post in collection.find(query):
|
|
702
|
+
post["instrument"] = new_array_element_name
|
|
703
|
+
post.pop("_id", None)
|
|
704
|
+
db_entries.append(post)
|
|
705
|
+
|
|
706
|
+
self._logger.info(f"Creating new array element {new_array_element_name}")
|
|
707
|
+
collection = self.get_collection(db_to_copy_to, collection_to_copy_to)
|
|
708
|
+
try:
|
|
709
|
+
collection.insert_many(db_entries)
|
|
710
|
+
except BulkWriteError as exc:
|
|
711
|
+
raise BulkWriteError(str(exc.details)) from exc
|
|
712
|
+
|
|
713
|
+
def copy_documents(self, db_name, collection, query, db_to_copy_to, collection_to_copy_to=None):
|
|
714
|
+
"""
|
|
715
|
+
Copy the documents matching to "query" to the DB "db_to_copy_to".
|
|
716
|
+
|
|
717
|
+
The documents are copied to the same collection as in "db_name".
|
|
718
|
+
(This function should be rarely used, probably only during "construction".)
|
|
719
|
+
|
|
720
|
+
Parameters
|
|
721
|
+
----------
|
|
722
|
+
db_name: str
|
|
723
|
+
the name of the DB to copy from
|
|
724
|
+
collection: str
|
|
725
|
+
the name of the collection to copy from
|
|
726
|
+
query: dict
|
|
727
|
+
A dictionary with a query to search for documents to copy.
|
|
728
|
+
For example, the query below would copy all entries of version 6.0.0
|
|
729
|
+
from telescope LSTN-01 to "db_to_copy_to".
|
|
730
|
+
|
|
731
|
+
.. code-block:: python
|
|
732
|
+
|
|
733
|
+
query = {
|
|
734
|
+
"instrument": "LSTN-01",
|
|
735
|
+
"version": "6.0.0",
|
|
736
|
+
}
|
|
737
|
+
db_to_copy_to: str
|
|
738
|
+
The name of the DB to copy to.
|
|
739
|
+
|
|
740
|
+
Raises
|
|
741
|
+
------
|
|
742
|
+
BulkWriteError
|
|
743
|
+
|
|
744
|
+
"""
|
|
745
|
+
db_name = self._get_db_name(db_name)
|
|
746
|
+
|
|
747
|
+
_collection = self.get_collection(db_name, collection)
|
|
748
|
+
if collection_to_copy_to is None:
|
|
749
|
+
collection_to_copy_to = collection
|
|
750
|
+
db_entries = []
|
|
751
|
+
|
|
752
|
+
for post in _collection.find(query):
|
|
753
|
+
post.pop("_id", None)
|
|
754
|
+
db_entries.append(post)
|
|
755
|
+
|
|
756
|
+
self._logger.info(
|
|
757
|
+
f"Copying documents matching the following query {query}\nto {db_to_copy_to}"
|
|
758
|
+
)
|
|
759
|
+
_collection = self.get_collection(db_to_copy_to, collection_to_copy_to)
|
|
760
|
+
try:
|
|
761
|
+
_collection.insert_many(db_entries)
|
|
762
|
+
except BulkWriteError as exc:
|
|
763
|
+
raise BulkWriteError(str(exc.details)) from exc
|
|
764
|
+
|
|
765
|
+
def delete_query(self, db_name, collection, query):
|
|
766
|
+
"""
|
|
767
|
+
Delete all entries from the DB which correspond to the provided query.
|
|
768
|
+
|
|
769
|
+
(This function should be rarely used, if at all.)
|
|
770
|
+
|
|
771
|
+
Parameters
|
|
772
|
+
----------
|
|
773
|
+
db_name: str
|
|
774
|
+
the name of the DB
|
|
775
|
+
collection: str
|
|
776
|
+
the name of the collection to copy from
|
|
777
|
+
query: dict
|
|
778
|
+
A dictionary listing the fields/values to delete.
|
|
779
|
+
For example, the query below would delete the entire version 6.0.0
|
|
780
|
+
from telescope LSTN-01.
|
|
781
|
+
|
|
782
|
+
.. code-block:: python
|
|
783
|
+
|
|
784
|
+
query = {
|
|
785
|
+
"instrument": "LSTN-01",
|
|
786
|
+
"version": "6.0.0",
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
"""
|
|
790
|
+
_collection = self.get_collection(db_name, collection)
|
|
791
|
+
|
|
792
|
+
if "version" in query:
|
|
793
|
+
query["version"] = self.model_version(query["version"])
|
|
794
|
+
|
|
795
|
+
self._logger.info(f"Deleting {_collection.count_documents(query)} entries from {db_name}")
|
|
796
|
+
|
|
797
|
+
_collection.delete_many(query)
|
|
798
|
+
|
|
799
|
+
def update_parameter_field(
|
|
800
|
+
self,
|
|
801
|
+
db_name,
|
|
802
|
+
model_version,
|
|
803
|
+
parameter,
|
|
804
|
+
field,
|
|
805
|
+
new_value,
|
|
806
|
+
array_element_name=None,
|
|
807
|
+
site=None,
|
|
808
|
+
collection_name="telescopes",
|
|
809
|
+
):
|
|
810
|
+
"""
|
|
811
|
+
Update a parameter field value for a specific array element/version.
|
|
812
|
+
|
|
813
|
+
This function only modifies the value of one of the following
|
|
814
|
+
DB entries: Applicable, units, Type, items, minimum, maximum.
|
|
815
|
+
These type of changes should be very rare. However they can
|
|
816
|
+
be done without changing the Object ID of the entry since
|
|
817
|
+
they are generally "harmless".
|
|
818
|
+
|
|
819
|
+
Parameters
|
|
820
|
+
----------
|
|
821
|
+
db_name: str
|
|
822
|
+
the name of the DB
|
|
823
|
+
model_version: str
|
|
824
|
+
Which model version to update
|
|
825
|
+
parameter: str
|
|
826
|
+
Which parameter to update
|
|
827
|
+
field: str
|
|
828
|
+
Field to update (only options are Applicable, units, Type, items, minimum, maximum).
|
|
829
|
+
If the field does not exist, it will be added.
|
|
830
|
+
new_value: type identical to the original field type
|
|
831
|
+
The new value to set to the field given in "field".
|
|
832
|
+
array_element_name: str
|
|
833
|
+
Which array element to update, if None then update a site parameter
|
|
834
|
+
site: str, North or South
|
|
835
|
+
Update a site parameter (the array_element_name argument must be None)
|
|
836
|
+
collection_name: str
|
|
837
|
+
The name of the collection in which to update the parameter.
|
|
838
|
+
|
|
839
|
+
Raises
|
|
840
|
+
------
|
|
841
|
+
ValueError
|
|
842
|
+
if field not in allowed fields
|
|
843
|
+
|
|
844
|
+
"""
|
|
845
|
+
db_name = self._get_db_name(db_name)
|
|
846
|
+
allowed_fields = ["applicable", "unit", "type", "items", "minimum", "maximum"]
|
|
847
|
+
if field not in allowed_fields:
|
|
848
|
+
raise ValueError(f"The field {field} must be one of {', '.join(allowed_fields)}")
|
|
849
|
+
|
|
850
|
+
collection = self.get_collection(db_name, collection_name)
|
|
851
|
+
_model_version = self.model_version(model_version, db_name)
|
|
852
|
+
|
|
853
|
+
query = {
|
|
854
|
+
"version": _model_version,
|
|
855
|
+
"parameter": parameter,
|
|
856
|
+
}
|
|
857
|
+
if array_element_name is not None:
|
|
858
|
+
query["instrument"] = array_element_name
|
|
859
|
+
logger_info = f"instrument {array_element_name}"
|
|
860
|
+
elif site is not None and site in names.site_names():
|
|
861
|
+
query["site"] = site
|
|
862
|
+
logger_info = f"site {site}"
|
|
863
|
+
else:
|
|
864
|
+
raise ValueError("You need to specify an array element or a site.")
|
|
865
|
+
|
|
866
|
+
par_entry = collection.find_one(query)
|
|
867
|
+
if par_entry is None:
|
|
868
|
+
self._logger.warning(
|
|
869
|
+
f"The query {query} did not return any results. I will not make any changes."
|
|
870
|
+
)
|
|
871
|
+
return
|
|
872
|
+
|
|
873
|
+
if field in par_entry:
|
|
874
|
+
old_field_value = par_entry[field]
|
|
875
|
+
|
|
876
|
+
if old_field_value == new_value:
|
|
877
|
+
self._logger.warning(
|
|
878
|
+
f"The value of the field {field} is already {new_value}. No changes necessary"
|
|
879
|
+
)
|
|
880
|
+
return
|
|
881
|
+
|
|
882
|
+
self._logger.info(
|
|
883
|
+
f"For {logger_info}, version {_model_version}, parameter {parameter}, "
|
|
884
|
+
f"replacing field {field} value from {old_field_value} to {new_value}"
|
|
885
|
+
)
|
|
886
|
+
else:
|
|
887
|
+
self._logger.info(
|
|
888
|
+
f"For {logger_info}, version {_model_version}, parameter {parameter}, "
|
|
889
|
+
f"the field {field} does not exist, adding it"
|
|
890
|
+
)
|
|
891
|
+
|
|
892
|
+
query_update = {"$set": {field: new_value}}
|
|
893
|
+
collection.update_one(query, query_update)
|
|
894
|
+
|
|
895
|
+
self._reset_parameter_cache(
|
|
896
|
+
site=(
|
|
897
|
+
site
|
|
898
|
+
if site is not None
|
|
899
|
+
else names.get_site_from_array_element_name(array_element_name)
|
|
900
|
+
),
|
|
901
|
+
array_element_name=array_element_name,
|
|
902
|
+
model_version=_model_version,
|
|
903
|
+
)
|
|
904
|
+
|
|
905
|
+
def add_new_parameter(
|
|
906
|
+
self,
|
|
907
|
+
db_name,
|
|
908
|
+
version,
|
|
909
|
+
parameter,
|
|
910
|
+
value,
|
|
911
|
+
array_element_name=None,
|
|
912
|
+
site=None,
|
|
913
|
+
collection_name="telescopes",
|
|
914
|
+
file_prefix=None,
|
|
915
|
+
**kwargs,
|
|
916
|
+
):
|
|
917
|
+
"""
|
|
918
|
+
Add a parameter value for a specific array element.
|
|
919
|
+
|
|
920
|
+
A new document will be added to the DB,
|
|
921
|
+
with all fields taken from the input parameters.
|
|
922
|
+
|
|
923
|
+
Parameters
|
|
924
|
+
----------
|
|
925
|
+
db_name: str
|
|
926
|
+
the name of the DB
|
|
927
|
+
version: str
|
|
928
|
+
The version of the new parameter value
|
|
929
|
+
parameter: str
|
|
930
|
+
Which parameter to add
|
|
931
|
+
value: can be any type, preferably given in kwargs
|
|
932
|
+
The value to set for the new parameter
|
|
933
|
+
array_element_name: str
|
|
934
|
+
The name of the array element to add a parameter to
|
|
935
|
+
(only used if collection_name is not "sites").
|
|
936
|
+
site: str
|
|
937
|
+
Site name; ignored if collection_name is "telescopes".
|
|
938
|
+
collection_name: str
|
|
939
|
+
The name of the collection to add a parameter to.
|
|
940
|
+
file_prefix: str or Path
|
|
941
|
+
where to find files to upload to the DB
|
|
942
|
+
kwargs: dict
|
|
943
|
+
Any additional fields to add to the parameter
|
|
944
|
+
|
|
945
|
+
Raises
|
|
946
|
+
------
|
|
947
|
+
ValueError
|
|
948
|
+
If key to collection_name is not valid.
|
|
949
|
+
|
|
950
|
+
"""
|
|
951
|
+
db_name = self._get_db_name(db_name)
|
|
952
|
+
collection = self.get_collection(db_name, collection_name)
|
|
953
|
+
|
|
954
|
+
db_entry = {}
|
|
955
|
+
if any(
|
|
956
|
+
key in collection_name
|
|
957
|
+
for key in ["telescopes", "calibration_devices", "configuration_sim_telarray"]
|
|
958
|
+
):
|
|
959
|
+
db_entry["instrument"] = names.validate_array_element_name(array_element_name)
|
|
960
|
+
elif "sites" in collection_name:
|
|
961
|
+
db_entry["instrument"] = names.validate_site_name(site)
|
|
962
|
+
elif "configuration_corsika" in collection_name:
|
|
963
|
+
db_entry["instrument"] = None
|
|
964
|
+
else:
|
|
965
|
+
raise ValueError(f"Cannot add parameter to collection {collection_name}")
|
|
966
|
+
|
|
967
|
+
db_entry["version"] = version
|
|
968
|
+
db_entry["parameter"] = parameter
|
|
969
|
+
if site is not None:
|
|
970
|
+
db_entry["site"] = names.validate_site_name(site)
|
|
971
|
+
|
|
972
|
+
_base_value, _base_unit, _base_type = value_conversion.get_value_unit_type(
|
|
973
|
+
value=value, unit_str=kwargs.get("unit", None)
|
|
974
|
+
)
|
|
975
|
+
db_entry["value"] = _base_value
|
|
976
|
+
if _base_unit is not None:
|
|
977
|
+
db_entry["unit"] = _base_unit
|
|
978
|
+
db_entry["type"] = kwargs["type"] if "type" in kwargs else _base_type
|
|
979
|
+
|
|
980
|
+
files_to_add_to_db = set()
|
|
981
|
+
db_entry["file"] = False
|
|
982
|
+
if self._is_file(value):
|
|
983
|
+
db_entry["file"] = True
|
|
984
|
+
if file_prefix is None:
|
|
985
|
+
raise FileNotFoundError(
|
|
986
|
+
"The location of the file to upload, "
|
|
987
|
+
f"corresponding to the {parameter} parameter, must be provided."
|
|
988
|
+
)
|
|
989
|
+
file_path = Path(file_prefix).joinpath(value)
|
|
990
|
+
files_to_add_to_db.add(f"{file_path}")
|
|
991
|
+
|
|
992
|
+
kwargs.pop("type", None)
|
|
993
|
+
db_entry.update(kwargs)
|
|
994
|
+
|
|
995
|
+
self._logger.info(
|
|
996
|
+
f"Will add the following entry to DB {db_name} and collection {db_name}:\n{db_entry}"
|
|
997
|
+
)
|
|
998
|
+
|
|
999
|
+
collection.insert_one(db_entry)
|
|
1000
|
+
for file_to_insert_now in files_to_add_to_db:
|
|
1001
|
+
self._logger.info(f"Will also add the file {file_to_insert_now} to the DB")
|
|
1002
|
+
self.insert_file_to_db(file_to_insert_now, db_name)
|
|
1003
|
+
|
|
1004
|
+
self._reset_parameter_cache(site, array_element_name, version)
|
|
1005
|
+
|
|
1006
|
+
def _get_db_name(self, db_name=None):
|
|
1007
|
+
"""
|
|
1008
|
+
Return database name. If not provided, return the default database name.
|
|
1009
|
+
|
|
1010
|
+
Parameters
|
|
1011
|
+
----------
|
|
1012
|
+
db_name: str
|
|
1013
|
+
Database name
|
|
1014
|
+
|
|
1015
|
+
Returns
|
|
1016
|
+
-------
|
|
1017
|
+
str
|
|
1018
|
+
Database name
|
|
1019
|
+
"""
|
|
1020
|
+
return self.mongo_db_config["db_simulation_model"] if db_name is None else db_name
|
|
1021
|
+
|
|
1022
|
+
def model_version(self, version, db_name=None):
|
|
1023
|
+
"""
|
|
1024
|
+
Return model version and check that it is valid.
|
|
1025
|
+
|
|
1026
|
+
Queries the database for all available model versions and check if the
|
|
1027
|
+
requested version is valid.
|
|
1028
|
+
|
|
1029
|
+
Parameters
|
|
1030
|
+
----------
|
|
1031
|
+
version : str
|
|
1032
|
+
Model version.
|
|
1033
|
+
db_name : str
|
|
1034
|
+
Database name.
|
|
1035
|
+
|
|
1036
|
+
Returns
|
|
1037
|
+
-------
|
|
1038
|
+
str
|
|
1039
|
+
Model version.
|
|
1040
|
+
|
|
1041
|
+
Raises
|
|
1042
|
+
------
|
|
1043
|
+
ValueError
|
|
1044
|
+
if version not valid.
|
|
1045
|
+
|
|
1046
|
+
"""
|
|
1047
|
+
_all_versions = self.get_all_versions(db_name=db_name)
|
|
1048
|
+
if version in _all_versions:
|
|
1049
|
+
return version
|
|
1050
|
+
if len(_all_versions) == 0:
|
|
1051
|
+
return None
|
|
1052
|
+
|
|
1053
|
+
raise ValueError(
|
|
1054
|
+
f"Invalid model version {version} in DB {self._get_db_name(db_name)} "
|
|
1055
|
+
f"(allowed are {_all_versions})"
|
|
1056
|
+
)
|
|
1057
|
+
|
|
1058
|
+
def insert_file_to_db(self, file_name, db_name=None, **kwargs):
|
|
1059
|
+
"""
|
|
1060
|
+
Insert a file to the DB.
|
|
1061
|
+
|
|
1062
|
+
Parameters
|
|
1063
|
+
----------
|
|
1064
|
+
file_name: str or Path
|
|
1065
|
+
The name of the file to insert (full path).
|
|
1066
|
+
db_name: str
|
|
1067
|
+
the name of the DB
|
|
1068
|
+
**kwargs (optional): keyword arguments for file creation.
|
|
1069
|
+
The full list of arguments can be found in, \
|
|
1070
|
+
https://docs.mongodb.com/manual/core/gridfs/#the-files-collection
|
|
1071
|
+
mostly these are unnecessary though.
|
|
1072
|
+
|
|
1073
|
+
Returns
|
|
1074
|
+
-------
|
|
1075
|
+
file_iD: GridOut._id
|
|
1076
|
+
If the file exists, return its GridOut._id, otherwise insert the file and return its"
|
|
1077
|
+
"newly created DB GridOut._id.
|
|
1078
|
+
|
|
1079
|
+
"""
|
|
1080
|
+
db_name = self._get_db_name(db_name)
|
|
1081
|
+
|
|
1082
|
+
db = DatabaseHandler.db_client[db_name]
|
|
1083
|
+
file_system = gridfs.GridFS(db)
|
|
1084
|
+
|
|
1085
|
+
if "content_type" not in kwargs:
|
|
1086
|
+
kwargs["content_type"] = "ascii/dat"
|
|
1087
|
+
|
|
1088
|
+
if "filename" not in kwargs:
|
|
1089
|
+
kwargs["filename"] = Path(file_name).name
|
|
1090
|
+
|
|
1091
|
+
if file_system.exists({"filename": kwargs["filename"]}):
|
|
1092
|
+
self._logger.warning(
|
|
1093
|
+
f"The file {kwargs['filename']} exists in the DB. Returning its ID"
|
|
1094
|
+
)
|
|
1095
|
+
return file_system.find_one( # pylint: disable=protected-access
|
|
1096
|
+
{"filename": kwargs["filename"]}
|
|
1097
|
+
)._id
|
|
1098
|
+
with open(file_name, "rb") as data_file:
|
|
1099
|
+
return file_system.put(data_file, **kwargs)
|
|
1100
|
+
|
|
1101
|
+
def get_all_versions(
|
|
1102
|
+
self,
|
|
1103
|
+
parameter=None,
|
|
1104
|
+
array_element_name=None,
|
|
1105
|
+
site=None,
|
|
1106
|
+
db_name=None,
|
|
1107
|
+
collection=None,
|
|
1108
|
+
):
|
|
1109
|
+
"""
|
|
1110
|
+
Get all version entries in the DB of collection and/or a specific parameter.
|
|
1111
|
+
|
|
1112
|
+
Parameters
|
|
1113
|
+
----------
|
|
1114
|
+
parameter: str
|
|
1115
|
+
Which parameter to get the versions of
|
|
1116
|
+
array_element_name: str
|
|
1117
|
+
Which array element to get the versions of (in case "collection_name" is not "sites")
|
|
1118
|
+
site: str
|
|
1119
|
+
Site name.
|
|
1120
|
+
db_name: str
|
|
1121
|
+
Database name.
|
|
1122
|
+
collection_name: str
|
|
1123
|
+
The name of the collection in which to update the parameter.
|
|
1124
|
+
|
|
1125
|
+
Returns
|
|
1126
|
+
-------
|
|
1127
|
+
all_versions: list
|
|
1128
|
+
List of all versions found
|
|
1129
|
+
|
|
1130
|
+
Raises
|
|
1131
|
+
------
|
|
1132
|
+
ValueError
|
|
1133
|
+
If key to collection_name is not valid.
|
|
1134
|
+
|
|
1135
|
+
"""
|
|
1136
|
+
db_name = self._get_db_name() if db_name is None else db_name
|
|
1137
|
+
if not db_name:
|
|
1138
|
+
self._logger.warning("No database name defined to determine list of model versions")
|
|
1139
|
+
return []
|
|
1140
|
+
_cache_key = f"model_versions_{db_name}-{collection}"
|
|
1141
|
+
|
|
1142
|
+
query = {}
|
|
1143
|
+
if parameter is not None:
|
|
1144
|
+
query["parameter"] = parameter
|
|
1145
|
+
_cache_key = f"{_cache_key}-{parameter}"
|
|
1146
|
+
if collection in ["telescopes", "calibration_devices"] and array_element_name is not None:
|
|
1147
|
+
query["instrument"] = names.validate_array_element_name(array_element_name)
|
|
1148
|
+
_cache_key = f"{_cache_key}-{query['instrument']}"
|
|
1149
|
+
elif collection == "sites" and site is not None:
|
|
1150
|
+
query["site"] = names.validate_site_name(site)
|
|
1151
|
+
_cache_key = f"{_cache_key}-{query['site']}"
|
|
1152
|
+
|
|
1153
|
+
if _cache_key not in DatabaseHandler.model_versions_cached:
|
|
1154
|
+
all_versions = set()
|
|
1155
|
+
collections_to_query = (
|
|
1156
|
+
[collection] if collection else self.get_collections(db_name, True)
|
|
1157
|
+
)
|
|
1158
|
+
for collection_name in collections_to_query:
|
|
1159
|
+
db_collection = self.get_collection(db_name, collection_name)
|
|
1160
|
+
sorted_posts = db_collection.find(query).sort("version", ASCENDING)
|
|
1161
|
+
all_versions.update(post["version"] for post in sorted_posts)
|
|
1162
|
+
DatabaseHandler.model_versions_cached[_cache_key] = list(all_versions)
|
|
1163
|
+
|
|
1164
|
+
if len(DatabaseHandler.model_versions_cached[_cache_key]) == 0:
|
|
1165
|
+
self._logger.warning(f"The query {query} did not return any results. No versions found")
|
|
1166
|
+
|
|
1167
|
+
return DatabaseHandler.model_versions_cached[_cache_key]
|
|
1168
|
+
|
|
1169
|
+
def _parameter_cache_key(self, site, array_element_name, model_version, collection=None):
|
|
1170
|
+
"""
|
|
1171
|
+
Create a cache key for the parameter cache dictionaries.
|
|
1172
|
+
|
|
1173
|
+
Parameters
|
|
1174
|
+
----------
|
|
1175
|
+
site: str
|
|
1176
|
+
Site name.
|
|
1177
|
+
array_element_name: str
|
|
1178
|
+
Array element name.
|
|
1179
|
+
model_version: str
|
|
1180
|
+
Model version.
|
|
1181
|
+
collection: str
|
|
1182
|
+
DB collection name.
|
|
1183
|
+
|
|
1184
|
+
Returns
|
|
1185
|
+
-------
|
|
1186
|
+
str
|
|
1187
|
+
Cache key.
|
|
1188
|
+
"""
|
|
1189
|
+
parts = []
|
|
1190
|
+
if site:
|
|
1191
|
+
parts.append(site)
|
|
1192
|
+
if array_element_name:
|
|
1193
|
+
parts.append(array_element_name)
|
|
1194
|
+
parts.append(model_version)
|
|
1195
|
+
if collection:
|
|
1196
|
+
parts.append(collection)
|
|
1197
|
+
return "-".join(parts)
|
|
1198
|
+
|
|
1199
|
+
def _reset_parameter_cache(self, site, array_element_name, model_version):
|
|
1200
|
+
"""
|
|
1201
|
+
Reset the cache for the parameters.
|
|
1202
|
+
|
|
1203
|
+
Parameters
|
|
1204
|
+
----------
|
|
1205
|
+
site: str
|
|
1206
|
+
Site name.
|
|
1207
|
+
array_element_name: str
|
|
1208
|
+
Array element name.
|
|
1209
|
+
model_version: str
|
|
1210
|
+
Model version.
|
|
1211
|
+
"""
|
|
1212
|
+
self._logger.debug(f"Resetting cache for {site} {array_element_name} {model_version}")
|
|
1213
|
+
_cache_key = self._parameter_cache_key(site, array_element_name, model_version)
|
|
1214
|
+
DatabaseHandler.site_parameters_cached.pop(_cache_key, None)
|
|
1215
|
+
DatabaseHandler.model_parameters_cached.pop(_cache_key, None)
|
|
1216
|
+
db_array_elements.get_array_elements.cache_clear()
|
|
1217
|
+
|
|
1218
|
+
def get_collections(self, db_name=None, model_collections_only=False):
|
|
1219
|
+
"""
|
|
1220
|
+
List of collections in the DB.
|
|
1221
|
+
|
|
1222
|
+
Parameters
|
|
1223
|
+
----------
|
|
1224
|
+
db_name: str
|
|
1225
|
+
Database name.
|
|
1226
|
+
|
|
1227
|
+
Returns
|
|
1228
|
+
-------
|
|
1229
|
+
list
|
|
1230
|
+
List of collection names
|
|
1231
|
+
model_collections_only: bool
|
|
1232
|
+
If True, only return model collections (i.e. exclude fs.files, fs.chunks, metadata)
|
|
1233
|
+
|
|
1234
|
+
"""
|
|
1235
|
+
db_name = self._get_db_name() if db_name is None else db_name
|
|
1236
|
+
if db_name not in self.list_of_collections:
|
|
1237
|
+
self.list_of_collections[db_name] = DatabaseHandler.db_client[
|
|
1238
|
+
db_name
|
|
1239
|
+
].list_collection_names()
|
|
1240
|
+
if model_collections_only:
|
|
1241
|
+
return [
|
|
1242
|
+
collection
|
|
1243
|
+
for collection in self.list_of_collections[db_name]
|
|
1244
|
+
if not collection.startswith("fs.") and collection != "metadata"
|
|
1245
|
+
]
|
|
1246
|
+
return self.list_of_collections[db_name]
|