1515from .. import v2
1616from ..v1 .lint import (
1717 _check_df ,
18+ assert_measured_observables_defined ,
19+ assert_measurements_not_null ,
20+ assert_measurements_numeric ,
1821 assert_model_parameters_in_condition_or_parameter_table ,
1922 assert_no_leading_trailing_whitespace ,
2023 assert_parameter_bounds_are_numeric ,
2326 assert_parameter_prior_parameters_are_valid ,
2427 assert_parameter_prior_type_is_valid ,
2528 assert_parameter_scale_is_valid ,
29+ assert_unique_observable_ids ,
2630 assert_unique_parameter_ids ,
2731 check_ids ,
28- check_measurement_df ,
2932 check_observable_df ,
3033 check_parameter_bounds ,
3134)
32- from ..v1 .measurements import split_parameter_replacement_list
35+ from ..v1 .measurements import (
36+ assert_overrides_match_parameter_count ,
37+ split_parameter_replacement_list ,
38+ )
3339from ..v1 .observables import get_output_parameters , get_placeholders
3440from ..v1 .visualize .lint import validate_visualization_df
3541from ..v2 .C import *
@@ -237,8 +243,51 @@ def run(self, problem: Problem) -> ValidationIssue | None:
237243 if problem .measurement_df is None :
238244 return
239245
246+ df = problem .measurement_df
240247 try :
241- check_measurement_df (problem .measurement_df , problem .observable_df )
248+ _check_df (df , MEASUREMENT_DF_REQUIRED_COLS , "measurement" )
249+
250+ for column_name in MEASUREMENT_DF_REQUIRED_COLS :
251+ if not np .issubdtype (df [column_name ].dtype , np .number ):
252+ assert_no_leading_trailing_whitespace (
253+ df [column_name ].values , column_name
254+ )
255+
256+ for column_name in MEASUREMENT_DF_OPTIONAL_COLS :
257+ if column_name in df and not np .issubdtype (
258+ df [column_name ].dtype , np .number
259+ ):
260+ assert_no_leading_trailing_whitespace (
261+ df [column_name ].values , column_name
262+ )
263+
264+ if problem .observable_df is not None :
265+ assert_measured_observables_defined (df , problem .observable_df )
266+ assert_overrides_match_parameter_count (
267+ df , problem .observable_df
268+ )
269+
270+ if OBSERVABLE_TRANSFORMATION in problem .observable_df :
271+ # Check for positivity of measurements in case of
272+ # log-transformation
273+ assert_unique_observable_ids (problem .observable_df )
274+ # If the above is not checked, in the following loop
275+ # trafo may become a pandas Series
276+ for measurement , obs_id in zip (
277+ df [MEASUREMENT ], df [OBSERVABLE_ID ], strict = True
278+ ):
279+ trafo = problem .observable_df .loc [
280+ obs_id , OBSERVABLE_TRANSFORMATION
281+ ]
282+ if measurement <= 0.0 and trafo in [LOG , LOG10 ]:
283+ raise ValueError (
284+ "Measurements with observable "
285+ f"transformation { trafo } must be "
286+ f"positive, but { measurement } <= 0."
287+ )
288+
289+ assert_measurements_not_null (df )
290+ assert_measurements_numeric (df )
242291 except AssertionError as e :
243292 return ValidationError (str (e ))
244293
@@ -247,46 +296,21 @@ def run(self, problem: Problem) -> ValidationIssue | None:
247296 # condition table should be an error if the measurement table refers
248297 # to conditions
249298
250- # check that measured experiments/conditions exist
299+ # check that measured experiments
251300 # TODO: fully switch to experiment table and remove this:
252- if SIMULATION_CONDITION_ID in problem .measurement_df :
253- if problem .condition_df is None :
254- return
255- used_conditions = set (
256- problem .measurement_df [SIMULATION_CONDITION_ID ].dropna ().values
257- )
258- if PREEQUILIBRATION_CONDITION_ID in problem .measurement_df :
259- used_conditions |= set (
260- problem .measurement_df [PREEQUILIBRATION_CONDITION_ID ]
261- .dropna ()
262- .values
263- )
264- available_conditions = set (
265- problem .condition_df [CONDITION_ID ].unique ()
266- )
267- if missing_conditions := (used_conditions - available_conditions ):
268- return ValidationError (
269- "Measurement table references conditions that "
270- "are not specified in the condition table: "
271- + str (missing_conditions )
272- )
273- elif EXPERIMENT_ID in problem .measurement_df :
274- if problem .experiment_df is None :
275- return
276- used_experiments = set (
277- problem .measurement_df [EXPERIMENT_ID ].values
278- )
279- available_experiments = set (
280- problem .condition_df [CONDITION_ID ].unique ()
301+
302+ if problem .experiment_df is None :
303+ return
304+ used_experiments = set (problem .measurement_df [EXPERIMENT_ID ].values )
305+ available_experiments = set (
306+ problem .condition_df [CONDITION_ID ].unique ()
307+ )
308+ if missing_experiments := (used_experiments - available_experiments ):
309+ raise AssertionError (
310+ "Measurement table references experiments that "
311+ "are not specified in the experiments table: "
312+ + str (missing_experiments )
281313 )
282- if missing_experiments := (
283- used_experiments - available_experiments
284- ):
285- raise AssertionError (
286- "Measurement table references experiments that "
287- "are not specified in the experiments table: "
288- + str (missing_experiments )
289- )
290314
291315
292316class CheckConditionTable (ValidationTask ):
0 commit comments