Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ physicsnemo/core/ @coreyjadams @CharlelieLrt @ktangsali
# Reusable neural network building blocks
physicsnemo/nn/ @loliverhennigh

# Symbolic PDE residual computation (PhysicsInformer)
physicsnemo/sym/ @ktangsali

# Functional operations (KNN, radius search, SDF)
physicsnemo/nn/functional/ @loliverhennigh
physicsnemo/nn/functional/knn/ @coreyjadams @peterdsharpe @loliverhennigh
Expand Down
13 changes: 13 additions & 0 deletions .importlinter
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ containers=
layers =
experimental
active_learning : diffusion
sym
models : datapipes : metrics : domain_parallel : optim
mesh
nn
Expand Down Expand Up @@ -104,6 +105,18 @@ layers =
noise_schedulers
utils

[importlinter:contract:physicsnemo-sym]
name = Control Internal Dependencies in PhysicsNeMo sym
type = layers
containers=
physicsnemo.sym
layers =
eq
graph
computation
utils
constants

[importlinter:contract:physicsnemo-external-imports]
name = Prevent Non-listed external imports in physicsnemo
type = forbidden_import
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`uniform_grid_gradient`, `rectilinear_grid_gradient`,
`spectral_grid_gradient`, `meshless_fd_derivatives`, `mesh_lsq_gradient`,
and `mesh_green_gauss_gradient`.
- Adds `physicsnemo.sym` module for symbolic PDE residual computation
(`PhysicsInformer`). Users define PDEs via SymPy and select a gradient method
(`autodiff`, `finite_difference`, `spectral`, `meshless_finite_difference`,
`least_squares`); spatial derivatives are computed automatically using the
`nn.functional.derivatives` functionals.
- Added geometry functionals in `physicsnemo.nn.functional` for
`mesh_poisson_disk_sample`, `mesh_to_voxel_fraction`, and
`signed_distance_field`.
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ RUN if [ "$TARGETPLATFORM" = "linux/amd64" ] && [ "$NATTEN_AMD64_WHEEL" != "unkn
RUN uv pip install --no-build-isolation "torch_sparse"

# All pyproject extras (no dev); installs physicsnemo non-editable
RUN cd /physicsnemo && uv pip install ".[cu13,utils-extras,mesh-extras,datapipes-extras,gnns]"
RUN cd /physicsnemo && uv pip install ".[cu13,utils-extras,mesh-extras,datapipes-extras,gnns,sym]"

# Cleanup builder stage
RUN rm -rf /physicsnemo/
Expand Down
17 changes: 17 additions & 0 deletions docs/api/physicsnemo.sym.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
PhysicsNeMo Sym
===============

Symbolic PDE residual computation for physics-informed training.

.. autoclass:: physicsnemo.sym.eq.pde.PDE
:members:
:show-inheritance:

.. autoclass:: physicsnemo.sym.eq.phy_informer.PhysicsInformer
:members:
:show-inheritance:

.. autoclass:: physicsnemo.sym.eq.gradients.GradientCalculator
:members:

.. autofunction:: physicsnemo.sym.eq.gradients.compute_connectivity_tensor
50 changes: 50 additions & 0 deletions physicsnemo/sym/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# SPDX-FileCopyrightText: Copyright (c) 2023 - 2026 NVIDIA CORPORATION & AFFILIATES.
# SPDX-FileCopyrightText: All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""PhysicsNeMo Sym: symbolic PDE residual computation.
Comment thread
ktangsali marked this conversation as resolved.
Example
-------
>>> from sympy import Symbol, Function
>>> from physicsnemo.sym.eq.pde import PDE
>>> from physicsnemo.sym.eq.phy_informer import PhysicsInformer
>>>
>>> class Poisson(PDE):
... def __init__(self):
... self.dim = 2
... x, y = Symbol("x"), Symbol("y")
... u = Function("u")(x, y)
... self.equations = {"poisson": u.diff(x, 2) + u.diff(y, 2)}
...
>>> pde = Poisson()
>>> pi = PhysicsInformer(["poisson"], pde, grad_method="autodiff")
>>> sorted(pi.required_inputs)
['coordinates', 'u']
"""

from physicsnemo.sym.eq.gradients import (
GradientCalculator,
compute_connectivity_tensor,
)
from physicsnemo.sym.eq.pde import PDE
from physicsnemo.sym.eq.phy_informer import PhysicsInformer

__all__ = [
"GradientCalculator",
"PDE",
"PhysicsInformer",
"compute_connectivity_tensor",
]
101 changes: 101 additions & 0 deletions physicsnemo/sym/computation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# SPDX-FileCopyrightText: Copyright (c) 2023 - 2026 NVIDIA CORPORATION & AFFILIATES.
# SPDX-FileCopyrightText: All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Lightweight replacement for Sym's Node — wraps a callable with string-based I/O metadata."""

from __future__ import annotations

from physicsnemo.sym.constants import diff_str


class Computation:
Comment thread
ktangsali marked this conversation as resolved.
"""A named unit in the computational graph.

Parameters
----------
inputs : list[str]
Non-derivative input names (e.g. ``["u", "v", "p"]``).
outputs : list[str]
Output names produced by this computation.
evaluate : callable
A callable (typically ``torch.nn.Module``) mapping
``Dict[str, Tensor] → Dict[str, Tensor]``.
name : str
Human-readable label for debugging.
"""

def __init__(
self,
inputs: list[str],
outputs: list[str],
evaluate,
name: str = "Computation",
):
if isinstance(inputs, str):
inputs = [inputs]
all_inputs = [str(x) for x in inputs]
self._inputs = [x for x in all_inputs if diff_str not in x]
self._derivatives = [x for x in all_inputs if diff_str in x]
self._outputs = [str(x) for x in outputs]
self.evaluate = evaluate
self._name = name

@classmethod
def from_sympy(cls, eq, out_name, freeze_terms=None, detach_names=None):
"""Build a Computation from a SymPy expression."""
from physicsnemo.sym.utils.sympy.torch_printer import (
SympyToTorch,
_subs_derivatives,
)

if freeze_terms is None:
freeze_terms = []
if detach_names is None:
detach_names = []

sub_eq = _subs_derivatives(eq)
evaluate = SympyToTorch(sub_eq, out_name, freeze_terms, detach_names)
inputs = list(evaluate.keys)
outputs = [out_name]
return cls(inputs, outputs, evaluate, name="Sympy Computation: " + out_name)

@property
def name(self) -> str:
"""Human-readable label for this computation."""
return self._name

@property
def outputs(self) -> list[str]:
"""Output names produced by this computation."""
return self._outputs

@property
def inputs(self) -> list[str]:
"""Non-derivative input names."""
return self._inputs

@property
def derivatives(self) -> list[str]:
"""Derivative input names (contain ``__``)."""
return self._derivatives

def __str__(self) -> str:
return (
f"computation: {self.name}\n"
f" inputs: {self.inputs}\n"
f" derivatives: {self.derivatives}\n"
f" outputs: {self.outputs}"
)
29 changes: 29 additions & 0 deletions physicsnemo/sym/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# SPDX-FileCopyrightText: Copyright (c) 2023 - 2026 NVIDIA CORPORATION & AFFILIATES.
# SPDX-FileCopyrightText: All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np
import torch

diff_str: str = "__"
Comment thread
ktangsali marked this conversation as resolved.


def diff(y: str, x: str, degree: int = 1) -> str:
"""Build a derivative name string: ``diff('u', 'x')`` → ``'u__x'``."""
return diff_str.join([y] + degree * [x])


tf_dt = torch.float32
np_dt = np.float32
29 changes: 29 additions & 0 deletions physicsnemo/sym/eq/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# SPDX-FileCopyrightText: Copyright (c) 2023 - 2026 NVIDIA CORPORATION & AFFILIATES.
# SPDX-FileCopyrightText: All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from physicsnemo.sym.eq.gradients import (
GradientCalculator,
compute_connectivity_tensor,
)
from physicsnemo.sym.eq.pde import PDE
from physicsnemo.sym.eq.phy_informer import PhysicsInformer

__all__ = [
"GradientCalculator",
"PDE",
"PhysicsInformer",
"compute_connectivity_tensor",
]
Loading
Loading