|
38 | 38 | validate_yaml_syntax, |
39 | 39 | yaml, |
40 | 40 | ) |
41 | | -from ..v1.core import ( |
42 | | - get_notnull_columns, |
43 | | - get_observable_replacement_id, |
44 | | -) |
45 | 41 | from ..v1.distributions import * |
46 | | -from ..v1.lint import is_scalar_float, is_valid_identifier |
| 42 | +from ..v1.lint import is_valid_identifier |
47 | 43 | from ..v1.math import petab_math_str, sympify_petab |
48 | 44 | from ..v1.models.model import Model, model_factory |
49 | 45 | from ..v1.yaml import get_path_prefix |
|
73 | 69 | "Parameter", |
74 | 70 | "ParameterScale", |
75 | 71 | "ParameterTable", |
76 | | - "flatten_timepoint_specific_output_overrides", |
77 | | - "unflatten_simulation_df", |
78 | | -] |
79 | | - |
80 | | -_POSSIBLE_GROUPVARS_FLATTENED_PROBLEM = [ |
81 | | - C.MODEL_ID, |
82 | | - C.EXPERIMENT_ID, |
83 | | - C.OBSERVABLE_ID, |
84 | | - C.OBSERVABLE_PARAMETERS, |
85 | | - C.NOISE_PARAMETERS, |
86 | 72 | ] |
87 | 73 |
|
88 | 74 | logger = logging.getLogger(__name__) |
@@ -1222,7 +1208,7 @@ def from_yaml( |
1222 | 1208 | from .petab1to2 import petab1to2 |
1223 | 1209 |
|
1224 | 1210 | if format_version[0] == 1 and yaml_file: |
1225 | | - logging.debug( |
| 1211 | + logger.debug( |
1226 | 1212 | "Auto-upgrading problem from PEtab 1.0 to PEtab 2.0" |
1227 | 1213 | ) |
1228 | 1214 | with TemporaryDirectory() as tmpdirname: |
@@ -2364,68 +2350,6 @@ def get_output_parameters( |
2364 | 2350 |
|
2365 | 2351 | return output_parameters |
2366 | 2352 |
|
2367 | | - def has_timepoint_specific_overrides( |
2368 | | - self, |
2369 | | - ignore_scalar_numeric_noise_parameters: bool = False, |
2370 | | - ignore_scalar_numeric_observable_parameters: bool = False, |
2371 | | - ) -> bool: |
2372 | | - """Check if the measurements have timepoint-specific observable or |
2373 | | - noise parameter overrides. |
2374 | | -
|
2375 | | - :param ignore_scalar_numeric_noise_parameters: |
2376 | | - ignore scalar numeric assignments to noiseParameter placeholders |
2377 | | -
|
2378 | | - :param ignore_scalar_numeric_observable_parameters: |
2379 | | - ignore scalar numeric assignments to observableParameter |
2380 | | - placeholders |
2381 | | -
|
2382 | | - :return: True if the problem has timepoint-specific overrides, False |
2383 | | - otherwise. |
2384 | | - """ |
2385 | | - if not self.measurements: |
2386 | | - return False |
2387 | | - |
2388 | | - measurement_df = self.measurement_df |
2389 | | - |
2390 | | - # mask numeric values |
2391 | | - for col, allow_scalar_numeric in [ |
2392 | | - ( |
2393 | | - C.OBSERVABLE_PARAMETERS, |
2394 | | - ignore_scalar_numeric_observable_parameters, |
2395 | | - ), |
2396 | | - (C.NOISE_PARAMETERS, ignore_scalar_numeric_noise_parameters), |
2397 | | - ]: |
2398 | | - if col not in measurement_df: |
2399 | | - continue |
2400 | | - |
2401 | | - measurement_df[col] = measurement_df[col].apply(str) |
2402 | | - |
2403 | | - if allow_scalar_numeric: |
2404 | | - measurement_df.loc[ |
2405 | | - measurement_df[col].apply(is_scalar_float), col |
2406 | | - ] = "" |
2407 | | - |
2408 | | - grouping_cols = get_notnull_columns( |
2409 | | - measurement_df, |
2410 | | - _POSSIBLE_GROUPVARS_FLATTENED_PROBLEM, |
2411 | | - ) |
2412 | | - grouped_df = measurement_df.groupby(grouping_cols, dropna=False) |
2413 | | - |
2414 | | - grouping_cols = get_notnull_columns( |
2415 | | - measurement_df, |
2416 | | - [ |
2417 | | - C.MODEL_ID, |
2418 | | - C.OBSERVABLE_ID, |
2419 | | - C.EXPERIMENT_ID, |
2420 | | - ], |
2421 | | - ) |
2422 | | - grouped_df2 = measurement_df.groupby(grouping_cols) |
2423 | | - |
2424 | | - # data frame has timepoint specific overrides if grouping by noise |
2425 | | - # parameters and observable parameters in addition to observable and |
2426 | | - # experiment id yields more groups |
2427 | | - return len(grouped_df) != len(grouped_df2) |
2428 | | - |
2429 | 2353 |
|
2430 | 2354 | class ModelFile(BaseModel): |
2431 | 2355 | """A file in the PEtab problem configuration.""" |
@@ -2544,160 +2468,3 @@ def format_version_tuple(self) -> tuple[int, int, int, str]: |
2544 | 2468 | """The format version as a tuple of major/minor/patch `int`s and a |
2545 | 2469 | suffix.""" |
2546 | 2470 | return parse_version(self.format_version) |
2547 | | - |
2548 | | - |
2549 | | -def _get_flattened_id_mappings( |
2550 | | - petab_problem: Problem, |
2551 | | -) -> dict[str, str]: |
2552 | | - """Get mapping from flattened to unflattened observable IDs. |
2553 | | -
|
2554 | | - :param petab_problem: |
2555 | | - The unflattened PEtab problem. |
2556 | | -
|
2557 | | - :returns: |
2558 | | - A mapping from flattened ID to original observable ID. |
2559 | | - """ |
2560 | | - groupvars = get_notnull_columns( |
2561 | | - petab_problem.measurement_df, _POSSIBLE_GROUPVARS_FLATTENED_PROBLEM |
2562 | | - ) |
2563 | | - mappings: dict[str, str] = {} |
2564 | | - |
2565 | | - old_observable_ids = {obs.id for obs in petab_problem.observables} |
2566 | | - for groupvar, _ in petab_problem.measurement_df.groupby( |
2567 | | - groupvars, dropna=False |
2568 | | - ): |
2569 | | - observable_id = groupvar[groupvars.index(C.OBSERVABLE_ID)] |
2570 | | - observable_replacement_id = get_observable_replacement_id( |
2571 | | - groupvars, groupvar |
2572 | | - ) |
2573 | | - |
2574 | | - logger.debug(f"Creating synthetic observable {observable_id}") |
2575 | | - if ( |
2576 | | - observable_id != observable_replacement_id |
2577 | | - and observable_replacement_id in old_observable_ids |
2578 | | - ): |
2579 | | - raise RuntimeError( |
2580 | | - "could not create synthetic observables " |
2581 | | - f"since {observable_replacement_id} was " |
2582 | | - "already present in observable table" |
2583 | | - ) |
2584 | | - |
2585 | | - mappings[observable_replacement_id] = observable_id |
2586 | | - |
2587 | | - return mappings |
2588 | | - |
2589 | | - |
2590 | | -def flatten_timepoint_specific_output_overrides( |
2591 | | - petab_problem: Problem, |
2592 | | -) -> None: |
2593 | | - """Flatten timepoint-specific output parameter overrides. |
2594 | | -
|
2595 | | - If the PEtab problem definition has timepoint-specific |
2596 | | - `observableParameters` or `noiseParameters` for the same observable, |
2597 | | - replace those by replicating the respective observable. |
2598 | | -
|
2599 | | - This is a helper function for some tools which may not support such |
2600 | | - timepoint-specific mappings. The observable table and measurement table |
2601 | | - are modified in place. |
2602 | | -
|
2603 | | - :param petab_problem: |
2604 | | - PEtab problem to work on. Modified in place. |
2605 | | - """ |
2606 | | - |
2607 | | - # Update observables |
2608 | | - def create_new_observable(old_id, new_id) -> Observable: |
2609 | | - if old_id not in petab_problem.observable_df.index: |
2610 | | - raise ValueError( |
2611 | | - f"Observable {old_id} not found in observable table." |
2612 | | - ) |
2613 | | - |
2614 | | - # copy original observable and update ID |
2615 | | - observable: Observable = copy.deepcopy(petab_problem[old_id]) |
2616 | | - observable.id = new_id |
2617 | | - |
2618 | | - # update placeholders |
2619 | | - old_obs_placeholders = observable.observable_placeholders |
2620 | | - old_noise_placeholders = observable.noise_placeholders |
2621 | | - suffix = new_id.removeprefix(old_id) |
2622 | | - observable.observable_placeholders = [ |
2623 | | - f"{sym.name}{suffix}" for sym in observable.observable_placeholders |
2624 | | - ] |
2625 | | - observable.noise_placeholders = [ |
2626 | | - f"{sym.name}{suffix}" for sym in observable.noise_placeholders |
2627 | | - ] |
2628 | | - |
2629 | | - # placeholders in formulas |
2630 | | - subs = dict( |
2631 | | - zip( |
2632 | | - old_obs_placeholders, |
2633 | | - observable.observable_placeholders, |
2634 | | - strict=True, |
2635 | | - ) |
2636 | | - ) |
2637 | | - observable.formula = observable.formula.subs(subs) |
2638 | | - subs |= dict( |
2639 | | - zip( |
2640 | | - old_noise_placeholders, |
2641 | | - observable.noise_placeholders, |
2642 | | - strict=True, |
2643 | | - ) |
2644 | | - ) |
2645 | | - observable.noise_formula = observable.noise_formula.subs(subs) |
2646 | | - |
2647 | | - return observable |
2648 | | - |
2649 | | - mappings = _get_flattened_id_mappings(petab_problem) |
2650 | | - |
2651 | | - petab_problem.observable_tables = [ |
2652 | | - ObservableTable( |
2653 | | - [ |
2654 | | - create_new_observable(old_id, new_id) |
2655 | | - for new_id, old_id in mappings.items() |
2656 | | - ] |
2657 | | - ) |
2658 | | - ] |
2659 | | - |
2660 | | - # Update measurements |
2661 | | - groupvars = get_notnull_columns( |
2662 | | - petab_problem.measurement_df, _POSSIBLE_GROUPVARS_FLATTENED_PROBLEM |
2663 | | - ) |
2664 | | - for measurement_table in petab_problem.measurement_tables: |
2665 | | - for measurement in measurement_table.measurements: |
2666 | | - # TODO: inefficient, but ok for a start |
2667 | | - group_vals = ( |
2668 | | - MeasurementTable([measurement]) |
2669 | | - .to_df() |
2670 | | - .iloc[0][groupvars] |
2671 | | - .tolist() |
2672 | | - ) |
2673 | | - new_obs_id = get_observable_replacement_id(groupvars, group_vals) |
2674 | | - measurement.observable_id = new_obs_id |
2675 | | - |
2676 | | - |
2677 | | -def unflatten_simulation_df( |
2678 | | - simulation_df: pd.DataFrame, |
2679 | | - petab_problem: Problem, |
2680 | | -) -> pd.DataFrame: |
2681 | | - """Unflatten simulations from a flattened PEtab problem. |
2682 | | -
|
2683 | | - A flattened PEtab problem is the output of applying |
2684 | | - :func:`flatten_timepoint_specific_output_overrides` to a PEtab problem. |
2685 | | -
|
2686 | | - :param simulation_df: |
2687 | | - The simulation dataframe. A dataframe in the same format as a PEtab |
2688 | | - measurements table, but with the ``measurement`` column switched |
2689 | | - with a ``simulation`` column. |
2690 | | - :param petab_problem: |
2691 | | - The unflattened PEtab problem. |
2692 | | -
|
2693 | | - :returns: |
2694 | | - The simulation dataframe for the unflattened PEtab problem. |
2695 | | - """ |
2696 | | - mappings = _get_flattened_id_mappings(petab_problem) |
2697 | | - original_observable_ids = simulation_df[C.OBSERVABLE_ID].replace(mappings) |
2698 | | - unflattened_simulation_df = simulation_df.assign( |
2699 | | - **{ |
2700 | | - C.OBSERVABLE_ID: original_observable_ids, |
2701 | | - } |
2702 | | - ) |
2703 | | - return unflattened_simulation_df |
0 commit comments