@@ -363,6 +363,87 @@ def test_petab1to2_reparametrize_priors(
363363 np .testing .assert_allclose (v2_pdf , v1_pdf , rtol = 1e-12 )
364364
365365
366+ @pytest .mark .filterwarnings (
367+ "ignore:.*Parameter scales are not supported in PEtab v2.*:UserWarning"
368+ )
369+ def test_petab1to2_reparametrize_llh (tmp_path ):
370+ """Test that reparametrizing overrides and parameters used in formulas
371+ preserves the likelihood, for both bases."""
372+
373+ def par (par_id , scale , nominal_value ):
374+ return {
375+ v1 .C .PARAMETER_ID : par_id ,
376+ v1 .C .PARAMETER_SCALE : scale ,
377+ v1 .C .LOWER_BOUND : 1e-3 ,
378+ v1 .C .UPPER_BOUND : 1e3 ,
379+ v1 .C .NOMINAL_VALUE : nominal_value ,
380+ v1 .C .ESTIMATE : 1 ,
381+ v1 .C .OBJECTIVE_PRIOR_TYPE : v1 .C .PARAMETER_SCALE_NORMAL ,
382+ v1 .C .OBJECTIVE_PRIOR_PARAMETERS : "0;1" ,
383+ }
384+
385+ yaml_file = _write_v1_problem (
386+ tmp_path ,
387+ observables = [
388+ {
389+ v1 .C .OBSERVABLE_ID : "obs_B" ,
390+ v1 .C .OBSERVABLE_FORMULA : "observableParameter1_obs_B * B "
391+ "+ offset" ,
392+ v1 .C .NOISE_FORMULA : "noiseParameter1_obs_B" ,
393+ }
394+ ],
395+ measurements = [
396+ {
397+ v1 .C .OBSERVABLE_ID : "obs_B" ,
398+ v1 .C .SIMULATION_CONDITION_ID : "c0" ,
399+ v1 .C .TIME : float (t ),
400+ v1 .C .MEASUREMENT : 0.3 + t ,
401+ v1 .C .OBSERVABLE_PARAMETERS : obs_par ,
402+ v1 .C .NOISE_PARAMETERS : noise_par ,
403+ }
404+ for t , (obs_par , noise_par ) in enumerate (
405+ [("s1" , "sd" ), ("s2" , "0.2" ), ("4" , "sd" )]
406+ )
407+ ],
408+ parameters = [
409+ _K1 ,
410+ par ("s1" , v1 .C .LOG10 , 3.0 ),
411+ par ("s2" , v1 .C .LOG10 , 0.7 ),
412+ par ("sd" , v1 .C .LOG , 0.25 ),
413+ par ("offset" , v1 .C .LOG10 , 0.13 ),
414+ ],
415+ )
416+ v1_problem = v1 .Problem .from_yaml (yaml_file )
417+ v2_problem = petab1to2 (yaml_file , reparametrize = "priors" )
418+ assert [p .id for p in v2_problem .parameters ] == [
419+ "k1" ,
420+ "log10_s1" ,
421+ "log10_s2" ,
422+ "log_sd" ,
423+ "log10_offset" ,
424+ ]
425+
426+ def simulate (measurement_df ):
427+ return measurement_df .rename (
428+ columns = {v1 .C .MEASUREMENT : v1 .C .SIMULATION }
429+ ).assign (** {v1 .C .SIMULATION : [0.5 , 0.6 , 0.7 ]})
430+
431+ llh_v1 = calculate_llh_v1 (
432+ v1_problem .measurement_df ,
433+ simulate (v1_problem .measurement_df ),
434+ v1_problem .observable_df ,
435+ v1_problem .parameter_df ,
436+ )
437+ llh_v2 = calculate_llh_v2 (
438+ v2_problem .measurement_df ,
439+ simulate (v2_problem .measurement_df ),
440+ v2_problem .observable_df ,
441+ v2_problem .parameter_df ,
442+ )
443+ assert np .isfinite (llh_v1 )
444+ assert llh_v2 == pytest .approx (llh_v1 , rel = 1e-12 )
445+
446+
366447@pytest .mark .filterwarnings (
367448 "ignore:.*Parameter scales are not supported in PEtab v2.*:UserWarning" ,
368449 "ignore:Initialisation priors.*:UserWarning" ,
@@ -568,10 +649,11 @@ def test_petab1to2_reparametrize_overrides_unresolvable(tmp_path):
568649 ],
569650 overrides = ["s1" , "s2" ],
570651 )
571- with pytest .raises (
572- NotImplementedError , match = r"not reparametrized: `s2' \("
573- ):
652+ with pytest .raises (NotImplementedError ) as excinfo :
574653 petab1to2 (yaml_file , reparametrize = "priors" )
654+ msg = str (excinfo .value )
655+ assert "Use `reparametrize='none'`" in msg
656+ assert "not reparametrized: `s2'\n " in msg
575657
576658
577659@pytest .mark .filterwarnings (
@@ -618,11 +700,19 @@ def test_petab1to2_reparametrize_output_parameter(tmp_path):
618700 assert problem ["obs_B" ].formula == sympify_petab ("10^log10_scaling * B" )
619701
620702
621- def test_petab1to2_reparametrize_warnings_and_errors (tmp_path ):
703+ @pytest .mark .parametrize (
704+ "prior_type" ,
705+ [
706+ v1 .C .PARAMETER_SCALE_NORMAL ,
707+ v1 .C .PARAMETER_SCALE_LAPLACE ,
708+ v1 .C .PARAMETER_SCALE_UNIFORM ,
709+ ],
710+ )
711+ def test_petab1to2_reparametrize_warnings_and_errors (tmp_path , prior_type ):
622712 k1 = _K1 | {
623713 v1 .C .PARAMETER_SCALE : v1 .C .LOG10 ,
624- v1 .C .OBJECTIVE_PRIOR_TYPE : v1 . C . PARAMETER_SCALE_NORMAL ,
625- v1 .C .OBJECTIVE_PRIOR_PARAMETERS : "0 ;1" ,
714+ v1 .C .OBJECTIVE_PRIOR_TYPE : prior_type ,
715+ v1 .C .OBJECTIVE_PRIOR_PARAMETERS : "-1 ;1" ,
626716 }
627717 yaml_file = _write_v1_problem (
628718 tmp_path ,
@@ -1034,8 +1124,15 @@ def test_petab1to2_validate(tmp_path):
10341124@pytest .mark .filterwarnings (
10351125 "ignore:.*Parameter-scale priors of log-scaled parameters.*:UserWarning"
10361126)
1127+ @pytest .mark .filterwarnings (
1128+ "ignore:Log-scaled parameters .* were not reparametrized.*:UserWarning"
1129+ )
1130+ @pytest .mark .filterwarnings (
1131+ "ignore:Parameter .* has no positive nominal value.*:UserWarning"
1132+ )
1133+ @pytest .mark .parametrize ("reparametrize" , ["none" , "all" ])
10371134@parametrize_or_skip
1038- def test_benchmark_collection (problem_id ):
1135+ def test_benchmark_collection (problem_id , reparametrize ):
10391136 """Test that we can upgrade all benchmark collection models."""
10401137 logging .basicConfig (level = logging .DEBUG )
10411138
@@ -1045,8 +1142,10 @@ def test_benchmark_collection(problem_id):
10451142
10461143 yaml_path = benchmark_models_petab .get_problem_yaml_path (problem_id )
10471144 try :
1048- problem = petab1to2 (yaml_path )
1145+ problem = petab1to2 (yaml_path , reparametrize = reparametrize )
10491146 except NotImplementedError as e :
1147+ if "could not be reparametrized" in str (e ):
1148+ raise
10501149 pytest .skip (str (e ))
10511150 assert isinstance (problem , Problem )
10521151 assert len (problem .measurements )
0 commit comments