Calibration Catalog (CalCat)
Besides the standard RESTful APIs for CRUD (+ list/search) operations the CalCat exposes the following special APIs (per model):
Table of contents
- Operation Modes
- Detectors
- Physical Detector Units
- Conditions
- Calibration Constants
- Calibration Constant Versions
- Notes
Operation Modes
get_all_by_detector_type
HTTP Method: GET
HTTP Path: /api/operation_modes/get_all_by_detector_type_id
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
detector_type_id |
integer | QueryString | yes | - | detector_type_id=10 |
Output:
List of operation modes defined for the requested detector type, where flg_available
is set to true
ordered by position
ascending (position is a field in the relation (many to many) between operation modes and detector type).
Internals:
- scope
by_detector_type(detector_type_id)
of theOperationMode
model
Detectors
get_all_by_instrument
HTTP Method: GET
HTTP Path: /api/detectors/get_all_by_instrument
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
instrument_id |
integer | QueryString | yes | - | instrument_id=3 |
Output:
List of detectors belonging to the requested instrument (note that the relation is many to many: an instrument can have many detectors and a detector can belong to more than one instrument).
If the given instrument does not exists (wrong instrument_id
) or exists but it is not associated to any detector, the HTTP response code will be in both cases a 404
.
Internals:
- retrieve instrument by id
- direct use of
has_many through
relation between the Instrument and the Detector models
Physical Detector Units (PDUs)
get_all_by_detector
HTTP Method: GET
HTTP Path: /physical_detector_units/get_all_by_detector
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
detector_id |
integer | QueryString | yes | - | detector_id=10 |
pdu_snapshot_at |
datetime | QueryString | no | - | pdu_snapshot_at=20210526T123000+0200 |
Output:
List of PDUs belonging to the requested detector.
If the pdu_snapshot_at
parameter is passed, the list of PDUs belonging to the detector at the pdu_snapshot_at
moment in time will be returned.
If the given detector does not exists (wrong detector_id
) or exists but does not have any associated PDU (or did not have at the pdu_snapshot_at
moment), the HTTP response code will be in both cases a 404
.
The parameter snapshot_at
(in place of pdu_snapshot_at
) is still accepted for compatibility.
Internals:
- find the detector
-
get_pdus_by_detector(pdu_snapshot_at)
method of the Detector model
Conditions
The following methods are exposed under the Conditions APIs, that is, under the base path: /api/conditions/
get_possible_conditions
A calibration condition is defined as a set of physical conditions each represented by some characteristic (e.g., a physical quantity), called parameter, the value of that characteristic, the physical unit of that value (where applicable), and allowable limits of variation for that value.
Parameters of type text (flg_text == true
) also exist: in such case the limits of variations do not apply; the search on possible conditions for those parameters is limited to values which starts with a certain string.
This API searches for calibration conditions matching a list of parameters whose values are within certain boundaries (or text value starts with a certain string for text type parameters).
HTTP Method: POST | GET
HTTP Path: /api/conditions/get_possible_conditions
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
condition | JSON | Request body | yes | - | read below |
For backward compatibility reasons this API allows the list of parameters and values in a JSON request's body with an HTTP GET request: this is a non standard usage of HTTP protocol.
A typical example of a request body to retrieve conditions using this API is the following:
{"condition":{ "event_at": "20210526T123000+0200", "parameters_conditions_attributes":[ { "parameter_id":"7", "value":"352.0" }, { "parameter_id":"1", "value":"300.0" }, { "parameter_id":"13", "value":"512.0" }, { "parameter_id":"14", "value":"128.0" }, { "parameter_id":"17", "value":"1.1" }, { "parameter_id":"4", "value":"0.0" }, { "parameter_id":"12", "value":"4.99006796365e-313" } ] } }
Note that the key event_at
is optional, while the parameters_conditions_attributes
is mandatory.
The event_at
parameter, if missing, is set as default to the current datetime.
For each of the the parameters_conditions_attributes
:
- the key
parameter_id
is mandatory. - the key
value
is not mandatory and it would be assumed equal to0.0
as default if not present for float type parameters. However, such value will result in an error for logarithmic parameters, while, on the other side, for text type parameters (where theflg_txt
is set totrue
) it would have the effect of not filtering at all, being valid for any value of the parameter in the DB (i.e. every text starts with an empty string).
Note that in the example above all values are passed in the JSON body as strings but, for float parameters (where the flg_txt
is set to false
), the value is automatically converted to float. For float parameters, float or integer values can be passed directly in the JSON.
As an alternative to parameter_id
, the parameter parameter_name
can be used. In such case, the search of the ID will be performed immediately, with exact match of the name (case insensitive, though).
In case a parameter with the requested name is not returned a 404 error will be triggered.
In the example above, for instance, using parameter_name
instead of parameter_id
, will yield the following request body:
{"condition":{ "event_at": "20210526T123000+0200", "parameters_conditions_attributes":[ { "parameter_name":"Memory cells", "value":"352.0" }, { "parameter_name":"Sensor Bias Voltage", "value":"300.0" }, { "parameter_name":"Pixels X", "value":"512.0" }, { "parameter_name":"Pixels Y", "value":"128.0" }, { "parameter_name":"Acquisition rate", "value":"1.1" }, { "parameter_name":"Gain Setting", "value":"0.0" }, { "parameter_name":"Detector UUID", "value":"4.99006796365e-313" } ] } }
Remarks
The python calibration client, due to how the HTTP request's body JSON object is built internally in the client, will inject additional keys in the JSON, like, e.g. lower_deviation_value
, flg_available
and so on: some of those are actually required by other APIs (e.g. when injecting the conditions) but not for this particular API, where those additional keys will be simply ignored.
For the same reason, the python calibration client will inject the values of parameter_id
and value
as strings, despite they should normally be integers (the parameter_id
values) and floats (the value
values): this is also how they are stored in the database. For text parameters (flg_text
set to true
) having value passed as a string is needed, but actually, if a numeric value would be passed instead, this would be automatically converted to a string.
Output:
A list of conditions which respect the parameters within certain boundaries (read further for more details).
Each of the retrieved conditions MUST be identified by the entire set of parameters (conditions are defined also by the number of parameter conditions which identifies them: a subset of parameter conditions, even when matching a condition, would not be sufficient to retrieve it).
The conditions in the list are returned ordered by date of creation the nearest to the optional event_at
parameter.
The criteria to identify the requested calibration conditions are the following:
- the calibration condition is identified by that exact number of parameters
- the calibration condition has the flag
flg_available
set totrue
- for each of the requested parameter conditions:
- the parameter id matches
- if the parameter is of type text (
flg_text == true
)- the stored value in the DB starts with the
value
parameter
- the stored value in the DB starts with the
- if the parameter is not text and not logarithmic (
flg_logarithmic == false
)- as a lower bound, the
value
parameter...- if
cal_min_value
is defined- is greater than
cal_min_value
(stored in the parameter condition)
- is greater than
- if
cal_min_value
is NOT defined (set to NULL) andparameters.def_lower_deviation_value
is defined (parameters.def_lower_deviation_value
is a default for the parameter)- is greater than
value - parameters.def_lower_deviation_value
(wherevalue
refers to the value stored in the parameter condition)
- is greater than
- if both
cal_min_value
andparameters.def_lower_deviation_value
are NOT defined (set to NULL):- in such case any value would match
- if
- as an upper bound, the
value
parameter...- if
cal_max_value
is defined- is less than
cal_max_value
(stored in the parameter condition)
- is less than
- if
cal_max_value
is NOT defined (set to NULL) andparameters.def_upper_deviation_value
is defined (parameters.def_upper_deviation_value
is a default for the parameter)- is less than
value + parameters.def_upper_deviation_value
(wherevalue
refers to the value stored in the parameter condition)
- is less than
- if both
cal_max_value
andparameters.def_upper_deviation_value
are NOT defined (set to NULL):- in such case any value would match
- if
- as a lower bound, the
- if the parameter is logarithmic (
flg_logarithmic == true
)- almost identical considerations apply, except that in case of
cal_min_value
set to NULL (cal_max_value
respectively) the fallbackparameters.def_lower_deviation_value
(parameters.def_upper_deviation_value
respectively) is considered as the exponent of the power in base 10.
- almost identical considerations apply, except that in case of
Important: at the moment of writing this documentation (November 2022) there are almost NO parameter conditions registered in the production database with cal_min_value
or cal_max_value
set to NULL, so, in practice, this API will find those conditions whose parameter conditions have the requested values between cal_min_value
and cal_max_value
.
Internals:
-
conditions_ids = get_expected_conditions(params, false)
:-
get_expected_conditions_int(params, false)
: loop over parameters - for each parameter condition: call
get_match_param_cond_ids(param_cond, false, num_params, filter_condition_ids)
- get the parameter by
parameter_id
- call
ParametersCondition.get_possible_conditions(parameter, parameter_val, num_params, filter_condition_ids)
- apply different rules depending on nature of the parameter (
flg_text
,flg_logarithmic
)ParametersCondition.get_possible_conditions_txt(parameter, value, num_parameters, filter_condition_ids)
ParametersCondition.get_possible_conditions_log(parameter, value, num_parameters, filter_condition_ids)
ParametersCondition.get_possible_conditions_non_log(parameter, value, num_parameters, filter_condition_ids)
- intersection of conditionids is performed at each step, as the `filtercondition_ids` is refined at each step and passed along
- get the parameter by
-
-
possible_conditions_by_closest_created_at(condtions_ids, event_at)
: all intersected conditions are retrieved (by id) and ordered by creation date the nearest to theevent_at
parameter
get_expected_condition
For a definition of what a calibration condition is, please refer to the previous api get_possible_conditions.
HTTP Method: POST | GET
HTTP Path: /api/conditions/get_expected_condition
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
condition | JSON | Request body | yes | - | read below |
As the previous API for backward compatibility reasons this one also allows the list of parameters and values in a JSON request's body with an HTTP GET request.
A typical example of a request body to retrieve conditions using this API is the following:
{ "condition":{ "parameters_conditions_attributes":[ { "parameter_id":"7", "value":"352.0", "lower_deviation_value":"0.0", "upper_deviation_value":"0.0" }, { "parameter_id":"1", "value":"300.0", "lower_deviation_value":"5.0", "upper_deviation_value":"5.0" }, { "parameter_id":"13", "value":"512.0", "lower_deviation_value":"0.0", "upper_deviation_value":"0.0" }, { "parameter_id":"14", "value":"128.0", "lower_deviation_value":"0.0", "upper_deviation_value":"0.0" }, { "parameter_id":"17", "value":"1.1", "lower_deviation_value":"0.0", "upper_deviation_value":"0.0" }, { "parameter_id":"4", "value":"0.0", "lower_deviation_value":"0.0", "upper_deviation_value":"0.0" }, { "parameter_id":"30", "value":"This is a text parameter" }, { "parameter_id":"12", "value":"4.99006796365e-313", "lower_deviation_value":"0.0", "upper_deviation_value":"0.0" } ] } }
Note that in comparison with the previous API this one does not accept an event_at
parameter and additionally, for each parameter condition, all keys (parameter_id
, value
, lower_deviation_value
and upper_deviation_value
) are required, except for text type parameters, where lower_deviation_value
and upper_deviation_value
are not required or, if passed, are simply ignored.
As for the previous API, also in this case parameter_name
can be used in place of parameter_id
, producing the same results in case of non existing parameter with the requested name.
Output:
The most recently created condition which respects the following criteria:
- the calibration condition is identified by that exact number of parameters
- the calibration condition has the flag
flg_available
set to true - for each of the requested parameter conditions
- if parameter is of type float (logarithmic or not):
- exact match between
value
,lower_deviation_value
andupper_deviation_value
requested parameters and database content
- exact match between
- if parameter is of text type:
- exact match of value and database text_value content
- if parameter is of type float (logarithmic or not):
Internals:
-
conditions_ids = get_expected_conditions(params, true)
:-
get_expected_conditions_int(params, true)
: loop over parameters - for each parameter condition: call
get_match_param_cond_ids(param_cond, true, num_params, filter_condition_ids)
- get the parameter by parameter_id
- call
ParametersCondition.get_exact_conditions(parameter.id, parameter_val, parameter_lower_dev_val, parameter_upper_dev_val, num_params, filter_condition_ids)
- intersection of conditionids is performed at each step, as the `filtercondition_ids` is refined at each step and passed along
-
-
existing_conditions(condition_ids)
: returnsCondition.where(id: condition_ids).order(created_at: :desc).first
(so only one: the most recently created condition)
set_expected_conditions
This API is used to create a new condition in the database or return the already existing one which already matches the same set of parameter conditions.
HTTP Method: POST
HTTP Path: /api/conditions/set_possible_conditions
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
condition | JSON | Request body | yes | - | read below |
Similar considerations as for the previous API apply here, the major difference in the input JSON is that additional optional parameters (JSON "keys") can be sent.
In particular, under the main "condition"
key the following additional keys/parameters can also be specified:
-
name
(default: unix timestamp of current datetime) -
flg_available
(default:true
) -
description
(default:NULL
)
And under each of the parameter conditions attributes the following additional keys/parameters can be specified:
-
flg_available
(default:true
) -
description
(default:NULL
)
Again, also in this API parameter_name
can be used in place of parameter_id
.
Output:
The newly created condition (HTTP response status will be 201 Created
in such case) or the condition which already matches perfectly the set of parameter condition as for the criteria of the get_expected_condition
API (HTTP response status will be 200 OK
). Please note: in the latter case the aforementioned optional parameters are simply ignored (the way to update the name
, description
and flg_available
of a condition, if needed, are the standard RESTful APIs)
Internals:
- performs the same operations as the previous API and if any condition is found will return that condition
- if nothing is found call
create_condition_int(condition_params)
which would create the condition and nested attributes (parameters conditions)
Calibration Constants (CCs)
These methods are actually exposed under the Calibrations (aka 'constant types') APIs, that is, under the base path:
/api/calibrations/:id/
get_calibration_constant
HTTP Method: GET
HTTP Path: /api/calibrations/:id/get_calibration_constant
Input parameters
name | type | passed via | required | default | example |
---|---|---|---|---|---|
:id |
integer | Path | yes | - | /1 |
detector_type_id |
integer | QueryString | yes | - | detector_type_id=10 |
condition_id |
integer | QueryString | yes | - | condition_id=20 |
Output:
One single calibration constant matching the criteria (constant_id = :id
, detector type and condition) where the flg_available
is set to true
.
In case multiple calibration constants should match the criteria (same calibration, aka constant type, same detector type and same condition) only the first orderd by creation date descending (i.e., the most recent) is returned.
Internals
- scope
search_calibration_constant
of CalibrationConstant model, returns first record
get_all_calibration_constants
HTTP Method: GET
HTTP Path: /api/calibrations/:id/get_all_calibration_constants
Input parameters
name | type | passed via | required | default | example |
---|---|---|---|---|---|
:id |
integer | Path | yes | - | /1 |
detector_type_id |
integer | QueryString | yes | - | detector_type_id=10 |
condition_ids |
array of integers | QueryString | yes | - | condition_ids=[1,2,3] |
Output:
List of calibration constants matching the criteria (constant_id = :id
, detector type and condition) where the flg_available
is set to true
, ordered by creation date descending.
Internals
- scope
search_calibration_constant
of CalibrationConstant model
Calibration Constant Versions (CCVs)
The following methods (with the exception of the last one) are actually exposed under the Calibration Constants APIs, that is, under the base path:
/api/calibration_constants/:id/
get_version
HTTP Method: GET
HTTP Path: /api/calibration_constants/:id/get_version
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
:id |
integer | Path | yes | - | /1 |
physical_detector_unit_id |
integer | QueryString | yes | - | physical_detector_unit_id=10 |
event_at |
datetime | QueryString | no | current datetime - 1 second¹ | event_at=20210526T123000+0200 |
snapshot_at |
datetime | QueryString | no | - | snapshot_at=20210526T123000+0200 |
Output:
One single Calibration Constant Version matching the criteria (CC and PDU by respective requested ids), with the flag flg_deployed
set to true, where the param event_at
is in the range of validity of the CCV (see "§ Notes / Range of validity of Calibration Constant Versions" for more details).
If the snapshot_at
parameter is passed, the CCVs taken into account would be the ones which had the flag flg_deployed
set to true in the database at the snapshot_at
moment in time.
If more than one CCV should be "valid" at the event_at
moment, the one with the most recent begin_at
would be returned.
(1) The one second difference explained:
CCVs may be defined with end_validity_at
set to NULL
. In such case (see "§ Notes / Range of validity of Calibration Constant Versions" for more details) the end date would be considered the date of now, but with seconds resolution. Since the comparison for the validity is for an end_validity_at
strictly greater than the event_at
, removing one second guarantees we find such CCV.
Internals:
-
cc = CalibrationConstant.find()
: retrieve a single calibration constant -
cc.get_deployed_version
: returns one calibration constant version matching the criteria withevent_at
in the range of validity of the CCV
get_closest_version
HTTP Method: GET
HTTP Path: /api/calibration_constants/:id/get_closest_version
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
:id ² |
integer | Path | yes | - | /1 |
calibration_constant_ids |
array of integers | QueryString | yes | - | calibration_constant_ids=[1,2,3] |
physical_detector_unit_id |
integer | QueryString | yes | - | physical_detector_unit_id=10 |
event_at |
datetime | QueryString | no | current datetime - 1 second¹ | event_at=20210526T123000+0200 |
snapshot_at |
datetime | QueryString | no | - | snapshot_at=20210526T123000+0200 |
(2) Note that the id
parameter is there for compatibility and historical reason. It is actually not used to filter the results but it must correspond to the id of an existing constant: it is advisable to pass the first id of the calibration_constant_ids
list.
Output:
One single Calibration Constant Version matching the criteria (multiple CCs and single PDU by respective requested ids), with the flag flg_deployed
set to true, where the begin_at
is the closest to the event_at
parameter (it may return a CCV which has a validity period in the future of the event_at
).
If the snapshot_at
parameter is passed, the CCVs taken into account would be the ones which had the flag flg_deployed
set to true in the database at the snapshot_at
moment in time.
Internals:
-
get_all_versions_ordered_by_closest(cc_ids, pdu_id, snap, event)
:- find CCs by cc_ids
- loop over the CCs
- collect CCVs ids of those CCs (here
snapshot_at
is taken into account)
- returns one CCV (where
begin_at
is the closest toevent_at
)
get_prior_in_time_version
HTTP Method: GET
HTTP Path: /api/calibration_constants/:id/get_prior_in_time_version
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
:id ² |
integer | Path | yes | - | /1 |
calibration_constant_ids |
array of integers | QueryString | yes | - | calibration_constant_ids=[1,2,3] |
physical_detector_unit_id |
integer | QueryString | yes | - | physical_detector_unit_id=10 |
event_at |
datetime | QueryString | no | current datetime - 1 second¹ | event_at=20210526T123000+0200 |
snapshot_at |
datetime | QueryString | no | - | snapshot_at=20210526T123000+0200 |
(2) Note that the id
parameter is there for compatibility and historical reason. It is actually not used to filter the
results but it must correspond to the id of an existing constant: it is advisable to pass the first id of the calibration_constant_ids
list.
Output:
One single Calibration Constant Version matching the criteria (multiple CCs and single PDU by respective requested ids),
with the flag flg_deployed
set to true, where the begin_at
is the closest to the event_at
parameter BUT BEFORE the event_at
.
If the snapshot_at
parameter is passed, the CCVs taken into account would be the ones which had the flag flg_deployed
set to true in the database at the snapshot_at
moment in time.
Internals:
-
get_prior_in_time_version_render(cc_ids, pdu_id, snap, event)
:- find CCs by cc_ids
- loop over the CCs
- collect CCVs of those CCs (here
snapshot_at
is taken into account) - filter CCVs so that
event_at
is in their range of validity - reorder filtered CCVs by
begin_at
ascending - returns the last CCV of so re-ordered CCVs
get_all_versions
HTTP Method: GET
HTTP Path: /api/calibration_constants/:id/get_all_versions
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
:id ² |
integer | Path | yes | - | /1 |
calibration_constant_ids |
array of integers | QueryString | yes | - | calibration_constant_ids=[1,2,3] |
physical_detector_unit_id |
integer | QueryString | yes | - | physical_detector_unit_id=10 |
event_at |
datetime | QueryString | no | current datetime - 1 second¹ | event_at=20210526T123000+0200 |
snapshot_at |
datetime | QueryString | no | - | snapshot_at=20210526T123000+0200 |
(2) Note that the :id
parameter is there for compatibility and historical reason. It is actually not used to filter the results but it must correspond to the id of an existing constant: it is advisable to pass the first id of the calibration_constant_ids
list.
Output:
List of all Calibration Constant Versions matching the criteria (multiple CCs and single PDU by respective requested ids), with the flag flg_deployed
set to true, ordered by begin_at
closer to event_at
parameter.
If the snapshot_at
parameter is passed, the CCVs taken into account would be the ones having the flg_deployed
set to true in the database at the snapshot_at
moment in time.
Internals:
-
get_all_versions_ordered_by_closest(cc_ids, pdu_id, snap, event)
:- find CCs by cc_ids
- loop over the CCs
- collect CCVs ids of those CCs (here
snapshot_at
is taken into account)
- returns all those CCVs (ordered by
begin_at
closer toevent_at
)
get_closest_version_by_detector
HTTP Method: GET
HTTP Path: /api/calibration_constants/:id/get_closest_version_by_detector
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
:id ² |
integer | Path | yes | - | /1 |
calibration_constant_ids |
array of integers | QueryString | yes | - | calibration_constant_ids=[1,2,3] |
detector_id |
integer | QueryString | yes | - | detector_id=28 |
karabo_da |
string | QueryString | no | - | karabo_da=KARABODA02 |
event_at |
datetime | QueryString | no | current datetime - 1 second¹ | event_at=20210526T123000+0200 |
snapshot_at |
datetime | QueryString | no | - | snapshot_at=20210526T123000+0200 |
(2) Note that the :id
parameter is there for compatibility and historical reason. It is actually not used to filter the results but it must correspond to the id of an existing constant: it is advisable to pass the first id of the calibration_constant_ids
list.
Output:
List of all Calibration Constant Versions (one per PDU) matching the criteria (multiple CCs and PDUs belonging to detector, if karabo_da
is specified will select only one matching PDU), with the flag flg_deployed
set to true, ordered by begin_at
closer to event_at
parameter.
If the snapshot_at
parameter is passed:
- the PDUs taken into account would be the ones belonging to the detector at the
snapshot_at
moment in time - the CCVs taken into account would be the ones having the
flg_deployed
set to true in the database at thesnapshot_at
moment in time
Internals:
- find the detector
- find the PDUs (could be just one if
karabo_da
is specified) -
get_all_versions_by_pdu(cc_ids, pdus, snap, event)
:- loop over the PDUs and append the result of first
get_all_versions_ordered_by_closest(cc_ids, pdu_id, snap, event)
- this is a nested loop (PDUs x CCs, so is pretty inefficient when each CCs is bound to a single PDU!)
- finally returns one CCV per PDU which has the closest
begin_at
toevent_at
- loop over the PDUs and append the result of first
get_by_detector_conditions
Differently from the previous APIs, this one is exposed under the Calibration Constant Versions APIs that is, under the base path: /api/calibration_constant_versions/
This is a non-standard API retrieves the calibration constant versions by detector identifier and by a limited set of parameters conditions which does not include the PDUs' UUID, but assumes that they have been injected with it. This API combines strategies from the previous APIs and assumes a specific situation in the CalCat DB with conditions bound to the PDUs via the UUID parameter (parameter_id = 12).
HTTP Method: POST | GET
HTTP Path: /api/calibration_constant_versions/get_by_detector_conditions
Input parameters:
name | type | passed via | required | default | example |
---|---|---|---|---|---|
detector_identifier |
string | QueryString | yes | - | detector_identifier=SPB_DET_AGIPD1M-1 |
calibration_id |
integer (or list of integers) | QueryString | no | - |
calibration_id=2 (calibration_id=[2,11,13] ) |
karabo_da |
string | QueryString | no | - | karabo_da=AGIPD03 |
parameters_conditions_attributes |
JSON | Request body | yes | - | read below |
event_at |
datetime | QueryString | no | current datetime - 1 second¹ | event_at=20210526T123000+0200 |
pdu_snapshot_at |
datetime | QueryString | no | - | pdu_snapshot_at=20210526T105000+0200 |
begin_at_strategy |
string (either "prior" or "closest") | QueryString | no | closest | begin_at_strategy=prior |
Similarly to other APIs involving the conditions (e.g. get_possible_conditions), for backward compatibility reasons, this one allows the list of parameters and values in a JSON request's body with an HTTP GET request.
A typical example of a request body to retrieve CCVs using this API is the following:
{ "parameters_conditions_attributes":[ { "parameter_id":"7", "value":"352.0" }, { "parameter_id":"1", "value":"300.0" }, { "parameter_id":"13", "value":"512.0" }, { "parameter_id":"14", "value":"128.0" }, { "parameter_id":"17", "value":"1.1" }, { "parameter_id":"4", "value":"0.0" } ] }
Please note that the parameter identified by parameter_id
12 (Detector UUID) MUST NOT be included for this API to work as expected, as the filtering by PDU is internally executed after retrieving from the database all possible conditions which respect the remaining parameters conditions.
As for the get_possible_conditions API, also in this case parameter_name
can be used in place of parameter_id
.
Output:
List of all Calibration Constant Versions (one per PDU) matching the criteria: PDUs belonging to detector specified by detector_identifier
parameter, Calibration (aka constant type) matching the passed parameter (calibration_id
), Calibration Constant matching the specified conditions, with the flag flg_deployed
set to true, ordered (by default) by begin_at
closer to event_at
parameter.
If the pdu_snapshot_at
parameter is passed, the PDUs taken into account would be the ones belonging to the detector at the pdu_snapshot_at
moment in time
The optional begin_at_strategy
parameter can assume the values prior or closest. If omitted, the default strategy is assumed to be closest: the retrieved CCVs are the ones where the begin_at
field is the closest to the event_at
parameter (note that the event_at
parameter is also optional: if empty the current timestamp is assumed).
In case of begin_at_strategy
is set to the value prior the retrieved CCVs are the ones where the begin_at
field is strictly before the event_at
parameter.
If the given detector does not exists (wrong detector_identifier
) or exists but does not have any associated PDU (or did not have at the snapshot_at
moment), the HTTP response code will be in both cases a 404
.
In case the detector and associated PDU exist but no CCVs could be retrieved (either because of non matching conditions or constant type), the HTTP response would be a 200
but the result would consist of an empty list.
Either a single calibration_id
, a list of calibration_id
(s) or an empty calibration_id
are accepted: if multiple ids are passed, then the API will loop over them and retrieve one CCV per PDU per constant type (calibrationid = constant type). If an empty `calibrationid` is passed then the API will loop over all possible constant types.
Internals:
Get the detector:
det = Detector.find_by_identifier(detector_identifier)
Get PDUs at
pdu_snapshot_at
:pdus = det.get_pdus_by_detector(pdu_snapshot_at)
orpdus = [det.get_pdu_by_detector_and_karabo_da(karabo_da, pdu_snapshot_at)].reject { |pdu| pdu.nil? }
(ifkarabo_da
parameter is passed)Get all conditions with no PDU information:
get_expected_conditions_int(parameters_conditions, false, num_params+1)
-
For each PDU:
- For each constanttype (calibrationid):
- find the specific conditions for the PDU among the conditions found at previous step:
ParametersCondition.where(parameter_id: 12, value: pdu.float_uuid).where(condition_id: condition_ids)
- find CCs by
conditions_ids
, PDU.detector_type_id
,calibration_id
(we'll have a CC per PDU):CalibrationConstant.search_calibration_constant
- get the first CCV from list of CCVs ordered by
begin_at
closest atevent_at
:get_all_versions_ordered_by_closest(calibration_constants.collect(&:id), pdu.id, nil, event_at)
- find the specific conditions for the PDU among the conditions found at previous step:
- For each constanttype (calibrationid):
curl request example (single constant_type, all PDUs):
curl -s -X GET -H 'Accept: application/json; version=2' \ -H "X-USER-EMAIL: $user_email" -H "Authorization: Bearer $token" \ -H "Content-type: application/json" \ "https://in.xfel.eu/calibration/api/calibration_constant_versions/get_by_detector_conditions?detector_identifier=SPB_DET_AGIPD1M-1&calibration_id=2" \ -d '{"parameters_conditions_attributes":[{"parameter_id":"7","value":"352.0"},{"parameter_id":"1","value":"300.0"},{"parameter_id":"13","value":"512.0"},{"parameter_id":"14","value":"128.0"},{"parameter_id":"17","value":"1.1"},{"parameter_id":"4","value":"0.0"}]}' \ | jq .
curl request example (multiple constant_types, one PDU):
curl -s -X GET -H 'Accept: application/json; version=2' \ -H "X-USER-EMAIL: $user_email" -H "Authorization: Bearer $token" \ -H "Content-type: application/json" \ "https://in.xfel.eu/calibration/api/calibration_constant_versions/get_by_detector_conditions?detector_identifier=SPB_DET_AGIPD1M-1&karabo_da=AGIPD12&calibration_id=%5B2%2C11%5D" \ -d '{"parameters_conditions_attributes":[{"parameter_id":"7","value":"352.0"},{"parameter_id":"1","value":"300.0"},{"parameter_id":"13","value":"512.0"},{"parameter_id":"14","value":"128.0"},{"parameter_id":"17","value":"1.1"},{"parameter_id":"4","value":"0.0"}]}' \ | jq .
Notes:
Serialization of Calibration Constant Versions (example):
{ "id": 81729, "name": "20210716_162211_sIdx=0", "file_name": "cal.1626452528.8961353.h5", "path_to_file": "xfel/cal/agipd-type/agipd_siv1_agipdv11_m441/", "data_set_name": "/AGIPD_SIV1_AGIPDV11_M441/ThresholdsDark/0", "flg_deployed": true, "flg_good_quality": true, "begin_validity_at": "2021-07-16T17:46:36.000+02:00", "end_validity_at": null, "begin_at": "2021-07-16T17:46:36.000+02:00", "start_idx": 0, "end_idx": 0, "raw_data_location": "proposal:p900214 runs:9 8 7", "report_id": 594, "description": "", "view_url": "http://localhost:3004/dev_calibration/calibration_constant_versions/81729", "calibration_constant": { "id": 11042, "name": "AGIPD-Type_ThresholdsDark_AGIPD DefXphmDHCWAd61WU1/N5h3qA==\n", "flg_auto_approve": true, "flg_available": true, "description": "Per-pixel (per-memory cell) thresholds from dark runs", "detector_type_id": 2, "calibration_id": 11, "condition_id": 3286, "created_at": "2021-07-16T18:22:10.000+02:00" }, "physical_detector_unit": { "id": 106, "physical_name": "AGIPD_SIV1_AGIPDV11_M441", "karabo_da": "AGIPD04", "virtual_device_name": "Q2M1", "uuid": 303002300000, "float_uuid": 1.49703027041e-312, "detector_type_id": 2, "detector_id": 4, "flg_available": true, "description": null } }
Range of validity of Calibration Constant Versions:
Each Calibration Constant Version has the following date fields:
begin_at
begin_validity_at
end_validity_at
At the moment of writing this documentation (first draft: September 2021, last update: May 2024) the field begin_validity_at
is actually NOT used in CalCat.
The validity period of each CCV is normally calculated as the period between begin_at
and end_validity_at
.
However, the end_validity_at
can be NULL
: in such case the validity period of each CCV is calculated as the period between the currently examined CCV begin_at
and the begin_at
of the following CCV (in the list of CCVs belonging to the same PDU and CC ordered by begin_at
). The last CCV in the list, having a NULL
end_validity_at
, would be considered be valid until the current datetime (now), however with the caveat that this calculated datetime has resolution of seconds.