Skip to content

Pydantic#130

Open
ax3l wants to merge 1 commit intopicmi-standard:masterfrom
ax3l:topic-pydantic
Open

Pydantic#130
ax3l wants to merge 1 commit intopicmi-standard:masterfrom
ax3l:topic-pydantic

Conversation

@ax3l
Copy link
Copy Markdown
Member

@ax3l ax3l commented Nov 1, 2025

Use a declarative approach to PICMI. Ensure construction & assignment to parameters both trigger validations. Ensure easier extensibility in downstream codes. Enable serialization, so people can easily query their PICMI options, e.g., in post-processing. Close #94

  • vibe code a draft, iterate and amend
  • ensure docs build well: old & new
  • confirm it works with WarpX, doc extensions work
  • confirm it works with FBPIC
  • confirm it works with UCLA team (QuickPIC, QPAD?)
  • confirm it works with PIConGPU team

@ax3l ax3l added the enhancement New feature or request label Nov 1, 2025
@ax3l ax3l force-pushed the topic-pydantic branch 10 times, most recently from b045351 to 7be5b0e Compare November 1, 2025 06:06
Prompt + 5-10 follow-ups:

> PICMI, which is used as a standard interface in WarpX, is very hard to extend, maintain and develop.
>
> I would like you to use modern Python 3.10+ and Pydantic 2+ to redesign it, focusing on typing support for checks and very easy extensibility for extra attributes in downstream codes like WarpX.
>
> First, read all of PICMI in terms of docs and implementation.
>
> Then, working one class at a time refactor it for using pydantic.
>
> Make sure the user-facing API stays exactly the same in terms of named classes, attributes per class, and docstrings.
>
> Godspeed.
@@ -0,0 +1,13 @@
Interactions
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Moved a bit around, see #131

constants
applied_field
diagnostics
interactions
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Moved a bit around, see #131

Comment thread PICMI_Python/base.py


class _DocumentedMetaClass(type):
class _DocumentedMetaClass(ModelMetaclass):
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think we should be able to remove all the logic we needed to extend the documentation strings of classes:
Now, all our docs are in the individual fields of a class and the general string of a PICMI class should be able to stay the same in downstream code.

Comment thread PICMI_Python/base.py
Comment on lines +76 to +80
Base class for all PICMI classes using Pydantic for validation and extensibility.

This class allows code-specific extensions (e.g., warpx_* kwargs) via Pydantic's
extra fields mechanism while maintaining type safety for standard attributes.
"""
Copy link
Copy Markdown
Member Author

@ax3l ax3l Nov 1, 2025

Choose a reason for hiding this comment

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

Not sure if all this mechanism is still needed. I would simply derive in downstream code from a PICMI class and extend it with more fields...

from .particles import PICMI_Species, PICMI_MultiSpecies

# Type aliases using Python 3.10+ union syntax
PICMI_Grid = (
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Unused imports from refactoring.

We need to install pre-commits & ruff in PICMI to clean this repo up.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These type aliases are actually very useful to have. We have them in our implementation as well. But why would you have PICMI_Grid in diagnostics.py?

Comment thread PICMI_Python/particles.py
Comment on lines +532 to +544
# Extract user-defined keywords from extra fields
if self.model_extra:
self.user_defined_kw = {}
keys_to_remove = []

# Check density expression
for k, v in self.model_extra.items():
if re.search(rf'\b{k}\b', self.density_expression):
self.user_defined_kw[k] = v
keys_to_remove.append(k)
# Check momentum expressions
elif self.momentum_expressions[0] is not None and re.search(rf'\b{k}\b', self.momentum_expressions[0]):
self.user_defined_kw[k] = v
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

See above. Don´t think this is still needed, we can derive in downstream codes and add new fields with their own validators/types.

Comment thread PICMI_Python/particles.py
Comment on lines +611 to +619
# Validate lengths
if not (lenx == maxlen or lenx == 1):
raise ValueError("Length of x doesn't match len of others")
if not (leny == maxlen or leny == 1):
raise ValueError("Length of y doesn't match len of others")
if not (lenz == maxlen or lenz == 1):
raise ValueError("Length of z doesn't match len of others")
if not (lenux == maxlen or lenux == 1):
raise ValueError("Length of ux doesn't match len of others")
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Remove this -- can be checked by type.

Copy link
Copy Markdown
Contributor

@chillenzer chillenzer left a comment

Choose a reason for hiding this comment

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

Hi,

Hope you're all having a splendid start into 2026!

I'm the new lead developer on PIConGPU's PICMI support. PIConGPU's currently investing quite a bit into its PICMI support and the general direction of this PR suits us very well! We'd be interested in collaborating more closely on the evolution of PICMI, particularly as we have some capacity to do so at the moment. Would you care for a more detailed chat on this via VC?

My two pennies worth of comments you'll find below (just skimmed through, not a full review by far!). On the matter of tearing down infrastructure like _DocumentedMetaClass and _ClassWithInit, I'd agree that this is likely something that Pydantic can easily do for us and that removing them would make implementing PICMI for a particular code more "pythonic" and less based on custom conventions.

Hoping to hear from you soon!

Best,
Julian

Comment thread PICMI_Python/base.py

codename = None
from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, model_validator
from pydantic._internal._model_construction import ModelMetaclass
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks dangerous!

from .particles import PICMI_Species, PICMI_MultiSpecies

# Type aliases using Python 3.10+ union syntax
PICMI_Grid = (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These type aliases are actually very useful to have. We have them in our implementation as well. But why would you have PICMI_Grid in diagnostics.py?

self.name = name

self.handle_init(kw)
grid: "PICMI_Cartesian1DGrid | PICMI_Cartesian2DGrid | PICMI_Cartesian3DGrid | PICMI_CylindricalGrid" = Field(description="Grid object for the diagnostic")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is probably where PICMI_Grid was supposed to be used. More instances below.

Comment thread PICMI_Python/fields.py
Comment on lines +21 to +24
PICMI_Grid = (
"PICMI_Cartesian1DGrid | PICMI_Cartesian2DGrid | "
"PICMI_Cartesian3DGrid | PICMI_CylindricalGrid"
)
Copy link
Copy Markdown
Contributor

@chillenzer chillenzer Jan 9, 2026

Choose a reason for hiding this comment

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

I'm typically inclined to arrange things to avoid forward references. What's the argument for not starting with the grids and defining this alias after all grids are defined?

Comment thread PICMI_Python/fields.py
self.handle_init(kw)
methods_list: list[str] = ['FFT', 'Multigrid']

grid: "PICMI_Cartesian1DGrid | PICMI_Cartesian2DGrid | PICMI_Cartesian3DGrid | PICMI_CylindricalGrid" = Field(description="Grid instance. Grid object for the diagnostic")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We'd probably want to use the alias defined above.

from .interactions import PICMI_FieldIonization

# Type unions for PICMI objects using Python 3.10+ union syntax
# (Note: Not used in type hints anymore, but kept for backwards compatibility)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why?

@ax3l
Copy link
Copy Markdown
Member Author

ax3l commented Jan 9, 2026

Hi @chillenzer ,

Happy New Year!

I am out of office today, but happy to meet in the coming week(s)!

I only marked it in the PR commit so far, but this draft is just an initial vibe code without a lot of manual improvements yet. So don't spend too much time reviewing it just yet pls :)

Yes, let us coordinate and improve the in implementation to be more modern and pedantic!

@ax3l ax3l mentioned this pull request Jan 28, 2026
8 tasks
@ax3l
Copy link
Copy Markdown
Member Author

ax3l commented Jan 28, 2026

@chillenzer do you like to take this branch, pull it in your fork, open a new PR from it?
That way we both can push to it.

@chillenzer chillenzer mentioned this pull request Feb 17, 2026
6 tasks
@ax3l
Copy link
Copy Markdown
Member Author

ax3l commented Feb 18, 2026

Continued in #133

@ax3l ax3l closed this Feb 18, 2026
@ax3l
Copy link
Copy Markdown
Member Author

ax3l commented Feb 18, 2026

@chillenzer oh wait, are you sure #133 was built on this branch? #133 has way less lines changed so far.

@ax3l ax3l reopened this Feb 18, 2026
@chillenzer
Copy link
Copy Markdown
Contributor

chillenzer commented Feb 18, 2026

Your observation is correct: #133 starts from scratch and copies and adjusts snippets from #130 that I can verify with the PIConGPU test suite. So, eventually #133 will take precedence but we're far from there yet.

@ax3l ax3l added the breaking: codes breaks implementations (codes) using PICMI label Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking: codes breaks implementations (codes) using PICMI enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Modernize Models & Validation with Pydantic

2 participants