Skip to content

Support PEtab SciML problems and enable linting#482

Open
m-philipps wants to merge 28 commits into
mainfrom
sciml_lint
Open

Support PEtab SciML problems and enable linting#482
m-philipps wants to merge 28 commits into
mainfrom
sciml_lint

Conversation

@m-philipps

Copy link
Copy Markdown
Collaborator

WIP

@m-philipps m-philipps changed the title Support a PEtab SciML problem and enable linting Support PEtab SciML problems and enable linting May 26, 2026
@codecov-commenter

codecov-commenter commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 68.95161% with 77 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.21%. Comparing base (ae4ea94) to head (87d273c).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
petab/v2/base.py 76.10% 18 Missing and 9 partials ⚠️
petab/v2/core.py 60.00% 19 Missing and 7 partials ⚠️
petab/v2/sciml/core.py 66.03% 16 Missing and 2 partials ⚠️
petab/v2/sciml/lint.py 62.50% 3 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #482      +/-   ##
==========================================
- Coverage   75.29%   75.21%   -0.08%     
==========================================
  Files          62       64       +2     
  Lines        6946     6755     -191     
  Branches     1229     1153      -76     
==========================================
- Hits         5230     5081     -149     
+ Misses       1245     1218      -27     
+ Partials      471      456      -15     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@BSnelling BSnelling marked this pull request as ready for review June 16, 2026 10:41
@BSnelling BSnelling requested a review from a team as a code owner June 16, 2026 10:41

@dilpath dilpath left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Overall it would be good to try to separate as much of the SciML things into separate files or subdirectory if possible. This will help later on when we design a nicer extension interface for libpetab-python, I think. It will also help with maintenance immediately.

Comment thread petab/v2/core.py
Comment thread petab/v2/core.py Outdated
return sum(p.estimate for p in self.parameters)


class Hybridization(BaseModel):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move SciML-specific things to a separate file or subdirectory e.g. sciml/core.py and import them here? Just for organization; might help to keep SciML things as separate as possible. e.g. do not import petab_sciml here, rather only in the separated file.

Nevermind this if it will lead to circular imports etc.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've split out the sciml specific classes and introduced petab/v2/base.py to resolve circular imports. Let me know what you think.

There is still a fair amount of sciml related code left in petab/v2/core.py because the sciml fields have been added to the Problem class. We could consider an inheritance pattern in the future i.e.

class SciMLProblem(Problem):
    ...

IMO that would be worth considering if/when we want to support another PEtab extension that requires more fields in Problem.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot, that was very helpful. And I agree, no need to fully implement now.

Comment thread petab/v2/core.py
config: ProblemConfig = None,
):
from ..v2.lint import default_validation_tasks
from ..v2.lint import default_validation_tasks, sciml_validation_tasks

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this, import from ..v2.sciml.lint for example, for separation.

Comment thread petab/v2/core.py Outdated
Comment thread petab/v2/core.py Outdated
Comment thread petab/v2/lint.py
Comment on lines +937 to +945
for mapping in problem.mappings:
# petabEntityId is not referenced in any model
for model in problem.models:
if model.has_entity_with_id(mapping.petab_id):
messages.append(
f"`{mapping.petab_id}` is used in the mapping "
"table and referenced directly in the model "
f"`{model.model_id}`."
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec currently says that the petabEntityId can be the same as a modelEntityId, hence the petabEntityIds can appear in the model, right? @dweindl what do you think?

The petabEntityId may be the same as the modelEntityId, but it must not be used to alias an entity that already has a valid PEtab identifier. This restriction is to avoid unnecessary complexity in the PEtab problem files.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is some discussion of this here PEtab-dev/PEtab#669

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added another clause to the conditional here and below to allow the case where petabEntityId == modelEntityId. Please double check that I've understood the nuance correctly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks good

Comment thread petab/v2/lint.py Outdated
Comment thread petab/v2/lint.py
Comment on lines +1026 to +1032
# Add petab ids from mapping table if they are used for aliasing
for mapping in problem.mappings:
if mapping.model_id and mapping.model_id in parameter_ids.keys():
if mapping.petab_id not in invalid:
parameter_ids[mapping.petab_id] = None
# An aliased model id is not a valid parameter id
if mapping.model_id and mapping.model_id in parameter_ids:
del parameter_ids[mapping.model_id]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, I think it's OK to map a model ID to a PEtab ID in the mapping table as long as it's not an alias, i.e. only in the special case where petabEntityId == modelEntityId. I think the reason for this in the spec is for support use of the mapping table for annotation, i.e. via additional user-defined annotation columns.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, if we allow using the mapping table for general annotation of petab entities, which I think we do, then the current implementation would incorrectly consider, e.g., observables to be allowed in the parameter table, wouldn't it?

@BSnelling BSnelling requested a review from dweindl as a code owner June 17, 2026 14:23
@BSnelling BSnelling requested a review from dilpath June 17, 2026 14:33

@dilpath dilpath left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks very much! I would be happy to get @dweindl 's approval before merging, since it touches his v2 code a bit.

Currently I don't think CheckHybridizationTable is properly tested, but fine for now since it's just a placeholder before we implement all SciML checks.

Comment thread petab/v2/core.py Outdated
Comment thread petab/v2/core.py
Comment on lines +1614 to +1634
@property
def hybridizations(self) -> list[Hybridization]:
"""List of hybridizations in the hybridization table(s)."""
return list(
chain.from_iterable(
ht.hybridizations for ht in self.hybridization_tables
)
)

@property
def hybridization_df(self) -> pd.DataFrame | None:
"""Combined SciML hybridization tables as DataFrame."""
return (
HybridizationTable(hybridizations).to_df()
if (hybridizations := self.hybridizations)
else None
)

@hybridization_df.setter
def hybridization_df(self, value: pd.DataFrame):
self.hybridization_tables = [HybridizationTable.from_df(value)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some "Specific to PEtab SciML." comment to all docstrings of methods that are implemented in core PEtab?

BSnelling and others added 2 commits June 17, 2026 16:26
Co-authored-by: Dilan Pathirana <59329744+dilpath@users.noreply.github.com>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer moving all extension subpackages to .ext.{extension_id} to avoid collisions with other petab modules.

Comment thread petab/v2/sciml/core.py

import petab.v2.C as C

from ...v1.math.sympify import sympify_petab

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from ...v1.math.sympify import sympify_petab
from ..math.sympify import sympify_petab

Currently this will import the same, but it's safer in case we separate v1/v2 math processing.

Comment thread petab/v2/base.py
@@ -0,0 +1,225 @@
"""Base classes shared across petab.v2 to avoid circular imports."""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... .core was meant for that already.

Comment thread petab/v2/C.py
#: Extensions key in the YAML file
EXTENSIONS = "extensions"
#: PEtab SciML extension
SCIML = "sciml"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SCIML = "sciml"
EXT_ID_SCIML = "sciml"

Feels safer. We might have extension IDs that collide with existing constants here.

Comment thread petab/v2/core.py
else None
)

neural_networks = None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not super happy with adding all that to Problem. I see some of the changes are to invasive to fully isolate them, but for many things it should be possible.
How about having some Problem.ext.sciml: petab.v2.ext.sciml.SciMlExt, loading all those things in SciMlExt.__init__ and accessing all those entities through problem.ext.sciml.{hybridizations,neural_networks,...}? Too verbose?
This would also circumvent the circular import issues. Those extension classes would only have to imported at the function level, not module level, and we wouldn't have to move things to base.py.

Comment thread petab/v2/lint.py
Comment on lines +810 to +811
model.has_entity_with_id(mapping.petab_id)
and mapping.petab_id != mapping.model_id

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swap conditions - the second one is way cheaper to evaluate.

Comment thread petab/v2/lint.py
Comment on lines +1026 to +1032
# Add petab ids from mapping table if they are used for aliasing
for mapping in problem.mappings:
if mapping.model_id and mapping.model_id in parameter_ids.keys():
if mapping.petab_id not in invalid:
parameter_ids[mapping.petab_id] = None
# An aliased model id is not a valid parameter id
if mapping.model_id and mapping.model_id in parameter_ids:
del parameter_ids[mapping.model_id]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, if we allow using the mapping table for general annotation of petab entities, which I think we do, then the current implementation would incorrectly consider, e.g., observables to be allowed in the parameter table, wouldn't it?

Comment thread tests/v2/test_lint.py
def test_check_mapping_table():
"""Test checks related to the mapping table."""
problem = Problem()
# PySB model from PEtab test suite

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# PySB model from PEtab test suite
# SBML model from PEtab test suite

and not really from the test suite?

Comment thread tests/v2/test_lint.py
"""Test checks related to the mapping table."""
problem = Problem()
# PySB model from PEtab test suite
problem.model = SbmlModel.from_antimony("a.mean = 1")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't create a parameter with ID a.mean, but creates an sbml-distrib construct. Is this intended? If so, please describe the rationale in more detail.
If it's just about creating some model with a petab-incompatible ID, then it would have to be a PySB model. In SBML, we don't have that issue and the mapping table will only ever be used for annotation.

Comment thread pyproject.toml
"scipy"
]
sciml = [
"petab_sciml @ git+https://github.com/PEtab-dev/petab_sciml.git",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both git/github references added here will break PyPI deployment. petab_sciml will have to be installed manually until we can reference a pypi package here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants