Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce MSTx-NectarCam and MSTx-FlashCam #1362

Merged
merged 40 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
e8b2252
MSTx-FlashCam and MSTx-NectarCam
GernotMaier Feb 11, 2025
850d41c
allow sites as list; allow different design models
GernotMaier Feb 11, 2025
3ed1489
flashcam
GernotMaier Feb 11, 2025
7227e33
design models
GernotMaier Feb 11, 2025
a986c44
MSTx
GernotMaier Feb 11, 2025
afa709f
unit tests
GernotMaier Feb 11, 2025
fa0f15e
unit tests
GernotMaier Feb 11, 2025
73cf0e3
integration tests
GernotMaier Feb 11, 2025
8f514b2
simplification
GernotMaier Feb 11, 2025
6debe5f
consistent tests
GernotMaier Feb 11, 2025
6ff2b4e
remove schema_version from comparison
GernotMaier Feb 11, 2025
04ec96d
MSTx
GernotMaier Feb 11, 2025
eb4236b
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 12, 2025
9457387
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 12, 2025
297146c
unit tests
GernotMaier Feb 13, 2025
8a86306
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 13, 2025
710b339
add flash and nectar cam to allowed pattern
GernotMaier Feb 13, 2025
bfa0d32
print data string
GernotMaier Feb 13, 2025
9303654
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 13, 2025
7490583
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 17, 2025
4d9f1c6
changelog
GernotMaier Feb 17, 2025
72700b5
correct url
GernotMaier Feb 17, 2025
72a5022
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 18, 2025
c9d4efa
Update database versions for tests
GernotMaier Feb 18, 2025
82896c0
code smell
GernotMaier Feb 18, 2025
241e601
Merge branch 'main' into flash-and-nectarcam
tobiaskleiner Feb 18, 2025
1308b46
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 18, 2025
505f68c
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 21, 2025
144d8e5
Merge branch 'linter-fixes' into flash-and-nectarcam
GernotMaier Feb 21, 2025
f263db4
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 21, 2025
ba90153
fix unit test after merge
GernotMaier Feb 21, 2025
b71ad07
improved naming
GernotMaier Feb 21, 2025
54cfa9b
naming
GernotMaier Feb 21, 2025
579fec2
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 21, 2025
d0dc203
minor fix for db upload
GernotMaier Feb 21, 2025
ffe9c4b
fixed integration test configs
GernotMaier Feb 22, 2025
84d7773
fixed model version getter
GernotMaier Feb 22, 2025
adf0f3d
correct output name
GernotMaier Feb 22, 2025
b61217d
Merge branch 'main' into flash-and-nectarcam
GernotMaier Feb 24, 2025
8a8e71a
Merge branch 'main' into flash-and-nectarcam
EshitaJoshi Feb 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env_template
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ SIMTOOLS_DB_SERVER='cta-simpipe-protodb.zeuthen.desy.de' # MongoDB server
SIMTOOLS_DB_API_USER=YOUR_USERNAME # username for MongoDB: ask the responsible person
SIMTOOLS_DB_API_PW=YOUR_PASSWORD # Password for MongoDB: ask the responsible person
SIMTOOLS_DB_API_AUTHENTICATION_DATABASE='admin'
SIMTOOLS_DB_SIMULATION_MODEL='CTAO-Simulation-ModelParameters-v0-3-0'
SIMTOOLS_DB_SIMULATION_MODEL='CTAO-Simulation-ModelParameters-v0-4-0'
SIMTOOLS_SIMTEL_PATH='/workdir/sim_telarray'

# The dashboards to monitor the MongoDB instance are in (accessible only from within DESY)
Expand Down
1 change: 1 addition & 0 deletions docs/changes/1362.model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Introduce MSTx-NectarCam and MSTx-FlashCam design models for MSTs (allow both sites).
6 changes: 3 additions & 3 deletions src/simtools/applications/validate_file_using_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ def validate_data_file(args_dict, logger):
data_file=args_dict["file_name"],
check_exact_data_type=args_dict["require_exact_data_type"],
)
data_validator.validate_and_transform(is_model_parameter=True)
if args_dict["data_type"].lower() == "model_parameter":
data_validator.validate_parameter_and_file_name()
data_validator.validate_and_transform(
is_model_parameter=(args_dict["data_type"].lower() == "model_parameter")
)

logger.info(f"Successful validation of data file {args_dict['file_name']}")

Expand Down
8 changes: 6 additions & 2 deletions src/simtools/data_model/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,13 @@ def validate_dict_using_schema(data, schema_file=None, json_schema=None):
try:
jsonschema.validate(data, schema=json_schema, format_checker=format_checkers.format_checker)
except jsonschema.exceptions.ValidationError as exc:
_logger.error(f"Validation failed using schema: {json_schema}")
_logger.error(f"Validation failed using schema: {json_schema} for data: {data}")
raise exc
if data.get("meta_schema_url") and not gen.url_exists(data["meta_schema_url"]):
if (
isinstance(data, dict)
and data.get("meta_schema_url")
and not gen.url_exists(data["meta_schema_url"])
):
raise FileNotFoundError(f"Meta schema URL does not exist: {data['meta_schema_url']}")

_logger.debug(f"Successful validation of data using schema ({json_schema.get('name')})")
Expand Down
72 changes: 62 additions & 10 deletions src/simtools/data_model/validate_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

import simtools.utils.general as gen
from simtools.data_model import schema
from simtools.utils import value_conversion
from simtools.utils import names, value_conversion

__all__ = ["DataValidator"]

Expand Down Expand Up @@ -79,19 +79,24 @@ def validate_and_transform(self, is_model_parameter=False, lists_as_strings=Fals

"""
if self.data_file_name:
self.validate_data_file()
self.validate_data_file(is_model_parameter)
if isinstance(self.data_dict, dict):
return self._validate_data_dict(is_model_parameter, lists_as_strings)
if isinstance(self.data_table, Table):
return self._validate_data_table()
self._logger.error("No data or data table to validate")
raise TypeError

def validate_data_file(self):
def validate_data_file(self, is_model_parameter=None):
"""
Open data file and read data from file.

Doing this successfully is understood as file validation.

Parameters
----------
is_model_parameter: bool
This is a model parameter file.
"""
try:
if Path(self.data_file_name).suffix in (".yml", ".yaml", ".json"):
Expand All @@ -102,14 +107,30 @@ def validate_data_file(self):
self._logger.info(f"Validating tabled data from: {self.data_file_name}")
except (AttributeError, TypeError):
pass
if is_model_parameter:
self.validate_parameter_and_file_name()

def validate_parameter_and_file_name(self):
"""Validate that file name and key 'parameter_name' in data dict are the same."""
if not str(Path(self.data_file_name).stem).startswith(self.data_dict.get("parameter")):
raise ValueError(
f"Parameter name in data dict {self.data_dict.get('parameter')} and "
f"file name {Path(self.data_file_name).stem} do not match."
)
"""
Validate model parameter file name.

Expect that the following convention is used:

- file name starts with the parameter name
- file name ends with parameter version string

"""
file_stem = Path(self.data_file_name).stem
param = self.data_dict.get("parameter")
param_version = self.data_dict.get("parameter_version")
if not file_stem.startswith(param):
raise ValueError(f"Mismatch: parameter '{param}' vs. file '{file_stem}'.")

if param_version and not file_stem.endswith(param_version):
raise ValueError(f"Mismatch: version '{param_version}' vs. file '{file_stem}'.")

if param_version is None:
self._logger.warning(f"File '{file_stem}' has no parameter version defined.")

@staticmethod
def validate_model_parameter(par_dict):
Expand Down Expand Up @@ -170,7 +191,17 @@ def _validate_data_dict(self, is_model_parameter=False, lists_as_strings=False):
else:
self.data_dict["value"], self.data_dict["unit"] = value_as_list, unit_as_list

self._check_version_string(self.data_dict.get("version"))
if self.data_dict.get("instrument"):
if self.data_dict["instrument"] == self.data_dict["site"]: # site parameters
names.validate_site_name(self.data_dict["site"])
else:
names.validate_array_element_name(self.data_dict["instrument"])
self._check_site_and_array_element_consistency(
self.data_dict.get("instrument"), self.data_dict.get("site")
)

for version_string in ("version", "parameter_version", "model_version"):
self._check_version_string(self.data_dict.get(version_string))

if lists_as_strings:
self._convert_results_to_model_format()
Expand Down Expand Up @@ -814,3 +845,24 @@ def _check_version_string(self, version):
if not re.match(semver_regex, version):
raise ValueError(f"Invalid version string '{version}'")
self._logger.debug(f"Valid version string '{version}'")

def _check_site_and_array_element_consistency(self, instrument, site):
"""
Check that site and array element names are consistent.

An example for an inconsistency is 'LSTN' at site 'South'
"""
if not all([instrument, site]) or "OBS" in instrument:
return

def to_sorted_list(value):
"""Return value as sorted list."""
return [value] if isinstance(value, str) else sorted(value)

instrument_site = to_sorted_list(names.get_site_from_array_element_name(instrument))
site = to_sorted_list(site)

if instrument_site != site:
raise ValueError(
f"Site '{site}' and instrument site '{instrument_site}' are inconsistent."
)
6 changes: 3 additions & 3 deletions src/simtools/db/db_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def get_model_parameters(
site: str
Site name.
array_element_name: str
Name of the array element model (e.g. LSTN-01, MSTS-design, ILLN-01).
Name of the array element model (e.g. LSTN-01, MSTx-FlashCam, ILLN-01).
model_version: str, list
Version(s) of the model.
collection: str
Expand Down Expand Up @@ -475,7 +475,7 @@ def get_model_versions(self, collection_name="telescopes"):
"""
collection = self.get_collection(self._get_db_name(), "production_tables")
return sorted(
[post["model_version"] for post in collection.find({"collection": collection_name})]
{post["model_version"] for post in collection.find({"collection": collection_name})}
)

def get_array_elements(self, model_version, collection="telescopes"):
Expand Down Expand Up @@ -871,6 +871,6 @@ def _get_array_element_list(self, array_element_name, site, production_table, co
]
except KeyError:
return [
f"{names.get_array_element_type_from_name(array_element_name)}-design",
names.guess_design_model_from_name(array_element_name),
array_element_name,
]
2 changes: 1 addition & 1 deletion src/simtools/layout/array_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ def _set_telescope_auxiliary_parameters(self, telescope, telescope_name=None):
tel_model = self._get_telescope_model(telescope_name)
except ValueError:
tel_model = self._get_telescope_model(
names.get_array_element_type_from_name(telescope_name) + "-design",
names.guess_design_model_from_name(telescope_name),
)

for para in ("telescope_axis_height", "telescope_sphere_radius"):
Expand Down
6 changes: 6 additions & 0 deletions src/simtools/schemas/array_elements.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ data:
observatory: "CTAO"
site: "South"
description: "Mid-sized Schwarzschild-Couder telescope"
MSTx:
collection: "telescopes"
observatory: "CTAO"
site: ["North", "South"]
design_types: ["design", "test", "FlashCam", "NectarCam"]
description: "Mid-sized telescope"
ILLN:
collection: "calibration_devices"
observatory: "CTAO"
Expand Down
96 changes: 96 additions & 0 deletions src/simtools/schemas/model_parameter.metaschema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,102 @@
$schema: http://json-schema.org/draft-06/schema#
$ref: '#/definitions/SimtoolsModelParameters'
title: SimPipe DB Model Parameter Metaschema
description: |
YAML representation of db model parameter metaschema
(based on simulation model DB).
version: 0.3.0
name: modelparameter.metaschema
type: object
additionalProperties: false

definitions:
SimtoolsModelParameters:
description: ""
type: object
properties:
_id:
type: string
description: "DB unique identifier."
entry_date:
type: string
description: "Value entry date."
file:
type: boolean
description: "This parameter is a file."
instrument:
type:
- string
- "null"
description: "Associated instrument."
site:
anyOf:
- type: string
enum:
- North
- South
- type: "null"
- type: array
items:
type: string
enum:
- North
- South
description: "Associated CTAO site."
type:
type: string
description: "Data type"
enum:
- boolean
- dict
- double
- file
- float64
- int
- int64
- string
- uint
- uint32
- uint64
unit:
anyOf:
- type: string
- type: "null"
description: "Unit of the parameter."
value:
anyOf:
- type: boolean
- type: number
- type: string
- type: "null"
- type: array
description: "Value of the parameter."
parameter_version:
anyOf:
- type: string
description: "Parameter version."
schema_version:
anyOf:
- type: string
description: "Metaschema version."
unique_id:
anyOf:
- type: string
- type: "null"
description: "Unique ID of parameter definition."
required:
- file
- instrument
- parameter_version
- schema_version
- site
- type
- unit
- value
...
---
$schema: http://json-schema.org/draft-06/schema#
$ref: '#/definitions/SimtoolsModelParameters'
title: SimPipe DB Model Parameter Metaschema
description: |
YAML representation of db model parameter metaschema
(based on simulation model DB).
Expand Down
2 changes: 1 addition & 1 deletion src/simtools/schemas/production_tables.schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ definitions:
pattern: '^\d+\.\d+\.\d+$'
propertyNames:
description: Allowed parameter name patterns.
pattern: '^([A-Za-z](ST|LL)[N,S,x]-\d{2,3}|[A-Za-z](ST|LL)[N,S,x]-design|OBS-(North|South)|Dummy-Telescope)$'
pattern: '^([A-Za-z](ST|LL)[N,S,x]-\d{2,3}|[A-Za-z](ST|LL)[N,S,x]-(design|FlashCam|NectarCam)|OBS-(North|South)|Dummy-Telescope)$'
design_model:
type: object
description: Design models.
Expand Down
11 changes: 9 additions & 2 deletions src/simtools/testing/validate_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ def compare_json_or_yaml_files(file1, file2, tolerance=1.0e-2):
Compare two json or yaml files.

Take into account float comparison for sim_telarray string-embedded floats.
Allow differences in 'schema_version' field.

Parameters
----------
Expand All @@ -159,6 +160,8 @@ def compare_json_or_yaml_files(file1, file2, tolerance=1.0e-2):
"""
data1 = gen.collect_data_from_file(file1)
data2 = gen.collect_data_from_file(file2)
data1.pop("schema_version", None)
data2.pop("schema_version", None)

_logger.debug(f"Comparing json/yaml files: {file1} and {file2}")

Expand All @@ -181,7 +184,7 @@ def compare_json_or_yaml_files(file1, file2, tolerance=1.0e-2):
return _comparison


def _compare_value_from_parameter_dict(data1, data2, tolerance):
def _compare_value_from_parameter_dict(data1, data2, tolerance=1.0e-5):
"""Compare value fields given in different formats."""

def _as_list(value):
Expand All @@ -193,7 +196,11 @@ def _as_list(value):

_logger.info(f"Comparing values: {data1} and {data2} (tolerance: {tolerance})")

return np.allclose(_as_list(data1), _as_list(data2), rtol=tolerance)
_as_list_1 = _as_list(data1)
_as_list_2 = _as_list(data2)
if isinstance(_as_list_1, str):
return _as_list_1 == _as_list_2
return np.allclose(_as_list_1, _as_list_2, rtol=tolerance)


def compare_ecsv_files(file1, file2, tolerance=1.0e-5, test_columns=None):
Expand Down
Loading