Skip to content

v2.2.0

Choose a tag to compare

@ktangsali ktangsali released this 27 Aug 21:35
a078229

PhysicsNeMo General Release v2.2.0

Added

  • Adds ShardTensor support for GeoTransolver and FLARE models.
  • Adds zarr save/load for Mesh and DomainMesh via tensordict's zarr
    storage backend: physicsnemo.mesh.io.to_zarr / from_zarr, with
    training-appropriate chunking and zstd compression. MeshReader and
    DomainMeshReader transparently read zarr stores alongside
    .pmsh/.pdmsh (opt in via pattern). Requires optional zarr >= 3
    and a tensordict release with the zarr backend.
  • Promotes GeoTransolver out of experimental to
    physicsnemo.models.geotransolver.GeoTransolver, together with the FLARE
    model (physicsnemo.models.flare.FLARE) and the reusable GALE and FLARE
    attention layers (physicsnemo.nn.GALE, physicsnemo.nn.GALEBlock,
    physicsnemo.nn.FLARE). The embedded OOD guard is decoupled from the model.
    Wrap a constructed GeoTransolver with
    physicsnemo.experimental.guardrails.embedded.GuardedGeoTransolver (or
    attach_ood_guard) to enable out-of-distribution guarding. PhysicsNeMo removes
    the guard_config model argument. Legacy import shims keep the pre-move
    physicsnemo.experimental import paths working and emit a
    LegacyFeatureWarning pointing to the new locations.
  • Adds zenith_azimuth_angles and zenith_azimuth_angles_from_timestamp to
    physicsnemo.utils.zenith_angle, returning
    (sin_zenith, cos_zenith, sin_azimuth, cos_azimuth) alongside the existing
    cos_zenith_angle / cos_zenith_angle_from_timestamp helpers. The azimuth
    follows the north-clockwise convention.
  • Adds physicsnemo.nn.shrink_and_perturb_, an in-place shrink-and-perturb
    weight re-initialization for warm-starting from pretrained weights.
  • Adds dimension-generic volume mesh generation for implicit domains to
    physicsnemo.mesh.generate. mesh_implicit_domain meshes
    {x : phi(x) < 0}, clipped to the bounding box (box faces are honored
    as a boundary, so that external-flow "box minus obstacle" domains work
    directly), for any implicit function (signed-distance functions, level
    sets, or neural fields).
  • Adds compile-safe subclassing extension points to domain_parallel.ShardTensor
    (_extra_inner_tensors, __subclass_flatten_context__ / __subclass_unflatten__,
    _stable_inner_sentinel, and a DTensor-style __metadata_guard__), so a subclass can
    carry extra inner tensors and opaque metadata through torch.compile without
    re-implementing the flatten protocol. Base behavior unchanged.
  • Adds ShardTensor._subclass_propagated_attrs: attribute names base __torch_function__
    copies from an op input onto its eager op-result, re-classing it to the subclass. Skipped
    under compile; empty by default.
  • Adds install_aot_plain_tangent_coercion (run on import): rebuilds a plain backward
    cotangent into a ShardTensor when a boundary crosses a Dynamo graph break, instead of
    AOTAutograd raising "guessed its metadata incorrectly". __coerce_same_metadata_as_tangent__
    now also coerces down to a plain tensor at a replicated boundary.
  • Adds domain_parallel.shard_utils.halo_scatter: a torch.compile-safe halo
    scatter-correction primitive for Shard(0) ShardTensors with a borrowed-ghost overlay.
    halo_scatter_correct fuses the fold-to-owner / refresh-ghost exchanges into a self-adjoint
    custom_op (correct forward and backward under aot_eager and inductor), with routing
    passed as a packed graph-input tensor so it survives graph breaks;
    register_halo_scatter_handlers wires it onto scatter_add / index_add. The row
    transport is a pluggable backend (select_halo_backend, PHYSICSNEMO_HALO_BACKEND):
    a portable funcol path and an intra-node symmetric-memory (CUDA-IPC) path.
  • Extends halo_scatter with pack_halo_routing(cap=) fixed-shape routing (for compiled
    dynamic=False runs), an in-place scatter_add_ / index_add_ dispatch handler, and
    node-locality routing in select_halo_backend (single-node uses symm-mem, multi-node falls
    back to funcol).
  • Adds a ShardTensor.grad_dtype property override (returns the local tensor's dtype)
    so a newer-PyTorch grad_dtype read during Dynamo fake conversion doesn't fall back
    to a non-leaf DTensor and break compile. Mirrors the grad_fn / is_leaf / grad
    shields.
  • Adds integrate_moment and Mesh.integrate_moment for measure-weighted
    outer-product moments. Mesh integration APIs now accept nan_policy.
  • Adds per-cell measure weights that are preserved through cell subsampling
    and consumed by mesh integration routines and GLOBE.
  • Adds a global_shape argument to ShardTensor.from_local, enabling the
    no-communication sharding_shapes="chunk" path.
  • Adds exact-boundary quality mesh generation to
    physicsnemo.mesh.tessellation: fill_interior takes a closed
    codimension-one boundary Mesh (2D edge loops today; loops in any order
    and orientation, with holes, multiple components, and nested islands
    resolved automatically) and fills the interior with quality simplices via
    constrained Delaunay triangulation with Ruppert refinement — every input
    vertex is preserved bit-identically, every output triangle meets the
    guaranteed minimum-angle bound, output is a Mesh with provenance
    point_data, deterministic, with optional bound-preserving ODT smoothing.
    The contract is dimension-generic; n = 3 raises NotImplementedError
    pending exact boundary recovery. Also adds polygon_interior_point,
    which returns a point strictly inside a simple polygon.
  • Adds rectilinear_grid_divergence, rectilinear_grid_curl, and
    rectilinear_grid_laplacian to physicsnemo.nn.functional, with Torch and
    fused Warp implementations for periodic, nonuniform rectilinear grids.
  • Adds triangle-surface remeshing with NVIDIA Warp on CPU and CUDA, including
    remesh, Mesh.remesh, topology cleanup, barycentric point-data transfer,
    direct or attached linear-resolution-field control, and advanced tensor-level
    tuning.
  • Adds coverage reporting on PRs — an informational Coverage % check plus a
    ready-to-enable Codecov integration.
  • Adds differentiable mesh morphing: Torch-backed dense displace_points /
    Mesh.displace and Torch/NVIDIA Warp compact sparse-control
    morph_points / Mesh.morph / DomainMesh.morph.
  • Adds differentiable Sobolev mesh deformation through
    sobolev_deform_points and Mesh.sobolev_deform. A matrix-free,
    uniform-mass P1 Helmholtz solve smooths dense per-vertex displacements and
    their adjoints, with optional fixed-point constraints. Torch and CUDA Warp
    backends provide explicit implicit-adjoint differentiation.
  • Adds thin-plate-spline radial-basis deformation through
    radial_basis_function_deform_points,
    Mesh.radial_basis_function_deform, and
    DomainMesh.radial_basis_function_deform. PyTorch performs the differentiable
    coefficient solve. Torch and fused NVIDIA Warp backends evaluate the field.
  • Adds differentiable lattice free-form deformation with Torch and NVIDIA Warp
    backends: dimension-generic free_form_deform_points /
    Mesh.free_form_deform / DomainMesh.free_form_deform with Bernstein
    (classic FFD) and locally supported uniform cubic B-spline bases, plus
    node-interpolating linear, cubic_hermite, and quintic_hermite modes.
  • Adds fixed-topology simplex_strain_energy, simplex_measure_energy,
    total_measure_energy, simplex_inversion_energy,
    closed_surface_volume_energy, and surface_bending_energy to
    physicsnemo.nn.functional, with mesh-aware wrappers in
    physicsnemo.mesh.deformation. Torch supports higher-order derivatives,
    and Warp provides first-order GPU kernels.
  • Adds differentiable nearest-surface shrinkwrap through
    shrinkwrap_points and Mesh.shrinkwrap. Torch provides the reference
    search, NVIDIA Warp accelerates float32 nearest-face queries on CPU and
    CUDA. Both backends replay the selected projection with PyTorch autograd.
    Triangulated examples demonstrate weighted panel conformance and partial
    design-region projection onto a shape-optimization constraint.
  • Adds uniform_grid_divergence, uniform_grid_curl, and
    uniform_grid_laplacian to physicsnemo.nn.functional, with Torch and fused
    Warp implementations for periodic Cartesian grids.
  • Adds the experimental Strata weather-emulation models —
    physicsnemo.experimental.models.strata.Strata and StrataTransformer3D — plus
    the continuous / stereographic RoPE helpers build_rope_cos_sin_1d_continuous,
    build_axial_rope_cos_sin_2d_continuous, stereographic_projection, and
    spherical_centroid in physicsnemo.experimental.nn.
  • Adds Point-Transformer local vector-attention blocks to physicsnemo.nn.
  • Adds an is_causal option to TimmSelfAttention in physicsnemo.nn for
    causal self-attention.
  • FSDP2 checkpoint support: full save/load round-trip for
    torch.distributed.fsdp v2 models, including DTensor edge cases,
    cross-mesh reloads, and optimizer state loading.
  • Migrated the StormCast example from DDP + Domain Parallel to FSDP2 +
    Domain Parallel. StormCast previously used FullyShardedDataParallel
    with ShardingStrategy.NO_SHARD (equivalent to DDP) alongside domain
    parallelism; it now uses the FSDP2 fully_shard API, producing 2D-mesh
    DTensor parameters when use_shard_tensor is enabled.
  • Adds tensor-returning Mesh.gradient, Mesh.divergence, Mesh.curl, and
    Mesh.laplacian convenience methods to physicsnemo.mesh, mirroring
    Mesh.integrate (each returns a tensor and accepts a data key or a raw
    tensor, with a data_source="points"|"cells" kwarg selecting vertex or
    cell-centered fields). This gives the discrete differential operators a
    consistent, discoverable surface on Mesh; previously divergence/curl/
    laplacian were reachable only as free functions in physicsnemo.mesh.calculus.
    Adds compute_divergence_cells_lsq and compute_curl_cells_lsq free
    functions (cell-centered LSQ analogues); DEC operators and the cotangent
    Laplacian remain vertex-only and raise NotImplementedError for cell data.
  • Adds farthest_point_sampling to physicsnemo.nn.functional, a greedy
    farthest-point sampling (FPS) functional for point clouds.
  • Adds FourierPositionalEmbedding to physicsnemo.nn, a deterministic
    axis-wise (NeRF-style) Fourier positional embedding for continuous
    coordinates with no learnable parameters.
  • Adds radiation transport example (examples/nuclear_engineering/radiation_transport)
  • Adds agent skills structure, and initial skill for 'discoverability'.
  • Adds the experimental AeroJEPA model
    (physicsnemo.experimental.models.aerojepa.AeroJEPA), a joint-embedding
    predictive architecture for 3D aerodynamic fields composing context and
    target encoders, a query-token field decoder, and a JEPA predictor head,
    together with its SIGReg, token-latent, and reconstruction loss family.
    The generic point-cloud tokenizer and the batch/mask/k-NN helpers are added
    under physicsnemo.experimental.nn; the local point-transformer attention
    blocks it composes come from physicsnemo.nn.
  • Adds the AeroJEPA SuperWing tutorial recipe
    (examples/cfd/external_aerodynamics/aerojepa), an end-to-end Hydra-driven
    workflow covering dataset download, normalization, JEPA training, chunked
    inference, field-error plots, and CL/CD post-processing.
  • Adds xDeepONet to experimental models
    (physicsnemo.experimental.models.xdeeponet.DeepONet). A single
    dimension-generic (2D/3D) DeepONet that accepts a spatial or MLP branch,
    an optional trunk, and an optional second branch as nn.Module inputs
    (dependency injection). Six forward-call conventions cover trunked,
    trunkless, packed/auto-padded, and xFNO-style time-axis-extend modes.
    Supports multi-channel output, multiple decoder types (MLP, Conv,
    temporal projection), composable Fourier / UNet / Conv spatial branches
    (SpatialBranch), and coordinate features.
  • Adds FNO4DWrapper to the xdeeponet package: a thin wrapper around the
    library physicsnemo.models.fno.FNO (dimension=4) that adds
    autoregressive time-axis extension over (B, X, Y, Z, T, C) inputs (predict
    a K-step forecast horizon via target_times). Use
    physicsnemo.models.fno.FNO(dimension=4) directly when the time-axis
    extension is not needed. 3D FNO / Conv-FNO / U-FNO operators are expressed
    as DeepONet(trunk=None, dimension=3) with a Fourier/UNet/Conv
    SpatialBranch.
  • Adds Sin elementwise sine activation to physicsnemo.nn, registered
    in ACT2FN so it can be looked up by name (get_activation("sin")).
  • Adds active-learning recipe for external-aerodynamics surrogates
    (examples/cfd/external_aerodynamics/active_learning_aero/). Iteratively
    fine-tunes a GP-augmented GeoTransolver onto an out-of-distribution
    target class by scoring unlabeled candidates with a joint UQ signal
    (GP-vs-integrated-drag disagreement + GP posterior std) and selecting
    the top-k per round. Built on the physicsnemo.active_learning
    protocols and physicsnemo.experimental.uq.VariationalGPHead, with a
    layered structure (generic AL driver / GP-UQ recipe / aero adapter)
    designed for reuse on other UQ-based regression problems.
  • Adds FieldVariationalGPHead to physicsnemo.experimental.uq, a pointwise
    independent multitask variational GP head for per-point, multi-channel field
    uncertainty. It is the field sibling of VariationalGPHead (which pools a
    geometry to one embedding and predicts a scalar): it keeps the point dimension
    and returns one Gaussian posterior per point per channel, so a single forward
    pass yields the field prediction, the total predictive variance and the
    epistemic-only variance — no ensembling or MC-Dropout. Backbone-agnostic (it
    consumes only a (..., input_dim) feature tensor), with an optional DKL MLP,
    a Matérn ARD kernel (5/2 by default), float64 GP internals, an l2_radial feature
    normalization that preserves the radial out-of-distribution cue, and an
    optional heteroscedastic observation-noise MLP. Includes a surface field-GP
    training recipe for GeoTransolver
    (examples/cfd/external_aerodynamics/transformer_models/src/train_field_gp.py).
  • Adds a return_point_features forward flag to
    physicsnemo.models.geotransolver.GeoTransolver, which additionally returns
    the per-point latents computed just before the output projection. These are
    the features a pointwise head such as FieldVariationalGPHead consumes.
  • Adds LatentNoveltyQueryStrategy to the active-learning aero recipe,
    a third acquisition strategy that ranks unlabeled samples by their
    average kNN cosine distance in the encoder's learned geometry latent
    — reusing the same OODGuard
    (physicsnemo.experimental.guardrails.embedded) that flags
    out-of-distribution inputs at inference time. The guard is calibrated
    on the currently labeled set each round; round 1 falls back to
    class-balanced random because the calibration buffer is empty. New
    public OODGuard.score_geometry() method exposes the raw per-sample
    geometry-latent kNN distance as a continuous score for downstream
    consumers (e.g. AL acquisition) without the boolean thresholding /
    warning emission of OODGuard.check().
  • Adds rotary position embedding (RoPE) modules to phyiscsnemo.nn and
    integrates support for 2D RoPE in the neighborhood attention backend
    of DiT layers.
  • Adds support for RoPE, dynamic invalid-region masking, and a new
    ConvDetokenizer in phyiscsnemo.models.DiT. Invalid regions are supplied
    per forward call via the invalid_mask argument of DiT.forward (a
    per-sample, batch-variable pixel mask, domain-parallel safe), replacing
    flagged tokens with a learned mask token.
  • Adds an inference script (src/infer.py + conf/infer.yaml) to the
    Unified External Aero Recipe
    (examples/cfd/external_aerodynamics/unified_external_aero_recipe),
    with integrated aerodynamic force/moment coefficients (src/forces.py:
    CD/CL/CS/CMR/CMP/CMY). The script is model/dataset-agnostic, writes one
    native .pdmsh DomainMesh per sample (carrying physical-unit
    pred_<field> / true_<field>), reports training-space metrics
    (matching the training/validation loop), and reuses the trainer's
    dataloader / collate / metric tooling (refactored into datasets.py
    and utils.py).
  • Adds physicsnemo.mesh.spatial.signed_distance_field, a Mesh-typed
    wrapper over the Warp-backed physicsnemo.nn.functional.signed_distance_field
    op (CPU and CUDA), returning (sdf, hit_points, hit_faces) per query. The
    sign comes from Warp's angle-weighted pseudo-normal (robust at
    sharp/non-convex edges) or, with use_sign_winding_number=True, its
    generalized winding number (robust on non-watertight meshes).
    (Near-)degenerate faces, which the Warp mesh query would otherwise skip,
    are repaired into equivalent thin-but-valid triangles before the query.
    Supersedes and removes the private datapipes implementation
    (physicsnemo.datapipes.transforms._sdf_torch / _sdf_triton); the public
    datapipes SDF transform delegates here.
  • Added an iterable style dataset to physicsnemo datapipes, for on-the-fly gpu simulations.
  • DPS guidance now supports non-uniform guidance strength: the std_y and
    gamma arguments of physicsnemo.diffusion.guidance.ModelConsistencyDPSGuidance
    / DataConsistencyDPSGuidance and their
    physicsnemo.diffusion.multi_diffusion counterparts accept tensors as well as
    floats. A tensor assigns a different measurement-noise level / SDA scaling to
    each observation component, e.g. per-channel ((1, C, 1, 1)) or pointwise
    (full observation shape). Passing floats keeps the previous uniform
    behavior unchanged.
  • Adds relative_mse and relative_l2 (target-normalized regression errors,
    relative_l2 = sqrt(relative_mse)) to physicsnemo.metrics.general
    (relative_error.py), with optional element weights and dim-based
    reduction matching general.mse.
  • physicsnemo.metrics.general.mse mse/rmse gain an optional weights
    argument for a masked/weighted mean (backward-compatible; weights=None
    reproduces the prior unweighted result).
  • Adds a kinetic Monte Carlo (KMC) surrogate example
    (examples/kinetic_monte_carlo): a probabilistic autoregressive surrogate
    (ParticleGeoTransolver) that emulates a KMC event stream, predicting the
    next event (the new particle's features and inter-event delay) from the
    current particle population, an optional background mesh, and the simulation
    time. Independent rollouts form an ensemble for uncertainty quantification.

Changed

  • Splits the monolithic physicsnemo.diffusion.noise_schedulers.noise_schedulers
    and physicsnemo.diffusion.samplers.solvers modules into one module per class,
    named after the schedule or solver it defines, with the NoiseScheduler and
    Solver protocols in a base.py of their respective sub-package.
    Implementations are unchanged and every class is still re-exported from
    physicsnemo.diffusion.noise_schedulers and physicsnemo.diffusion.samplers,
    so the public import paths stay the same. The two old module paths remain as
    deprecated shims that re-export the same classes and raise a
    DeprecationWarning on import, so existing code keeps working. Import from
    physicsnemo.diffusion.noise_schedulers and physicsnemo.diffusion.samplers
    instead.
  • physicsnemo.nn.functional.signed_distance_field now returns a 3-tuple
    (sdf, hit_points, hit_faces)hit_faces is the int64 index of the
    triangle holding each closest point. Queries with no triangle within
    max_dist now return NaN distance/hit point and a -1 face index
    (previously the out-of-band results were undefined: the kernel read from
    an uninitialized face index). Mesh-index range validation on CUDA inputs is
    now a device-side assert instead of a host-synchronizing check, so the op
    is safe on a sync-free prefetch stream; the eager ValueError is kept on
    CPU.
  • Optimizes the production container build by consolidating related filesystem
    operations, using BuildKit bind and cache mounts, and separating custom,
    declared, and project dependency installation. Reduces total physicsnemo layers
    by around 78%.
  • GeoTransolver.forward's return_embedding_states and return_point_features
    are now keyword-only. They share a return signature, so a positional True did
    not say which was meant. Callers already passing them by keyword are unaffected.
  • ShardTensor.redistribute now computes receive shapes analytically when
    sharding shapes are known, skipping the shape-negotiation all_to_all
    collective (falls back to the collective only when shapes are unavailable).
  • PhysicsNeMo-Mesh tensor-valued gradients now consistently use the documented
    derivative-first layout (entity, spatial_dimension, *value_shape) across
    LSQ, intrinsic LSQ, and DEC. Earlier LSQ releases returned
    (entity, *value_shape, spatial_dimension) instead; migrate a stored legacy
    gradient with legacy_gradient.movedim(-1, 1). Divergence and curl values
    are unchanged.
  • xDeepONet SpatialBranch
    (physicsnemo.experimental.models.xdeeponet.SpatialBranch) now supports
    mixed-precision (AMP/autocast) training: FFT-based spectral convolutions are
    evaluated in float32 internally (cuFFT lacks complex-half support) while the
    rest of the branch uses autocast. This is a no-op under full precision, so
    fp32 outputs are unchanged. Also fixes a stale module docstring that
    referenced removed trunk/MLP-branch builder helpers.
  • physicsnemo.mesh.remeshing.remesh now raises NotImplementedError for
    non-2D-in-3D inputs (the remeshing implementation is surface-only) instead
    of failing confusingly downstream, and its docstring reflects that
    restriction.
  • physicsnemo.mesh.spatial: BVH.from_mesh and ClusterTree.from_points now
    share a single morton-LBVH node-topology builder (spatial/_lbvh.py),
    removing ~80 lines of duplicated build logic; construction output is
    byte-identical. BVH.from_mesh now defaults to leaf_size=1 (was 8),
    matching ClusterTree.from_points and measured to be more performant across
    platforms (smaller leaves yield fewer candidate cells per query). Containment /
    nearest-cell query results are unchanged. Adds the first direct unit tests for
    ClusterTree (construction invariants, aggregates, dual-tree cover).
  • physicsnemo.mesh performance: eliminated host-device syncs on hot paths.
    Cached topological adjacencies now store the Adjacency object directly instead
    of reconstructing it (which re-ran its syncing __post_init__ validation) on every
    lookup — making cached adjacency lookups ~120x faster on GPU (~335us → ~3us for a
    10k-point sphere); the BVH leaf-hit expansion drops two per-traversal-level syncs;
    and the Laplacian smoother reuses its per-iteration buffers in place instead of
    reallocating them.
  • physicsnemo.mesh.Mesh.slice_cells now accepts None/Ellipsis (keep all
    cells, return self), matching its type hint and slice_points;
    gaussian_curvature_cells reuses the cached gaussian_curvature_vertices
    property instead of recomputing it.
  • physicsnemo.mesh.Mesh convenience methods now directly reuse shared
    canonical functions, removing duplicate implementation bodies and docstrings.
    This includes geometric, deformation (including radial-basis-function
    deformation), calculus, topology, visualization, and validation operations.
  • physicsnemo.mesh: draw and validate are now the canonical standalone
    names matching Mesh.draw and Mesh.validate. The draw_mesh and
    validate_mesh remain as pending-deprecation compatibility names.
    Mesh.validate and DomainMesh.validate share the canonical validation
    option order, preserve the historical positional tolerance argument, and
    expose the new check_self_intersection option as keyword-only.
  • physicsnemo.mesh: validate(check_self_intersection=True) now raises
    NotImplementedError (the check is unimplemented) instead of silently returning a
    None sentinel that masquerades as "no self-intersections found".
  • physicsnemo.mesh quality metrics now use a normalized
    aspect ratio of longest edge to minimum altitude. The metric is dimensionless and
    scale-invariant for simplices of every manifold dimension, and a regular
    simplex now has aspect_ratio=1 and quality_score=1. This intentionally
    corrects the previous erroneous aspect-ratio and quality-score values.
  • Mesh.quality_metrics and Mesh.statistics again use explicit property
    getters so their class-facing documentation describes argument-free property
    access. Configurable statistics tolerance remains available through the
    standalone compute_mesh_statistics function.
  • Performance improvements in the diffusion module: reduced peak memory of
    DPS-guided diffusion sampling most notably for multi-diffusion at large
    domains. A guided sample() loop run under torch.no_grad() now detaches the
    state between solver steps, so the guidance autograd graph is no longer
    accumulated across the sampling trajectory (sampled outputs are unchanged;
    use torch.no_grad(), not torch.inference_mode()). Also expands CI test
    coverage and adds an API documentation page for
    physicsnemo.diffusion.multi_diffusion.
  • Performance improvements in IO prefetching and GPU preprocessing in physicsnemo datapipes.
  • ⚠️ BC-impact (DPS guidance): a custom norm callback passed to
    physicsnemo.diffusion.guidance.ModelConsistencyDPSGuidance /
    DataConsistencyDPSGuidance (and their physicsnemo.diffusion.multi_diffusion
    counterparts) must now return an elementwise loss (same shape as its
    inputs) instead of a per-batch-element reduced scalar of shape (B,).
    Migration: drop the reduction from your norm, e.g. return
    (y_pred - y_true).abs().pow(2) rather than
    (y_pred - y_true).pow(2).reshape(B, -1).sum(dim=1). For
    DataConsistencyDPSGuidance (and its multi_diffusion counterpart) the
    norm callback now also receives the unmasked (x_0, y) and the mask is
    applied to its output (mask * norm(x_0, y)), where it previously received
    the pre-masked (mask * x_0, mask * y); the two agree for the built-in Lp
    norms, but a custom norm that relies on unobserved entries being zeroed
    before the call may differ. The integer norm selector (e.g. norm=2) is
    unaffected.
  • Mesh.transform and compute_cotan_weights_fem now use the non-checking
    torch.linalg.inv_ex / solve_ex solvers, and build their index tensors on
    device. The checked solvers read a status code back to the host on every call,
    which synchronizes on CUDA; removing that and the index-tensor uploads takes
    Mesh.transform on a cached codimension-one mesh from three host
    synchronizations to one, and compute_cotan_weights_fem from six to three. As
    a consequence,
    Mesh.transform(..., assume_invertible=True) no longer raises when the matrix
    is in fact singular: it propagates NaN caches instead, as its docstring now
    documents. The default assume_invertible=None still tests the determinant
    and is unaffected.
  • physicsnemo.experimental.uq.VariationalGPHead now takes n_train as a
    required keyword-only argument, along with every argument after input_dim.
    It was annotated optional while the constructor raised on None, so callers
    that already pass it by keyword are unaffected. It also gains matern_nu,
    which was previously hardcoded to 2.5 (still the default).

Deprecated

  • physicsnemo.mesh.calculus.integrate_cell_data and integrate_point_data
    are deprecated in favor of integrate(..., data_source="cells"|"points").
    Compatibility wrappers remain available for this release and emit
    LegacyFeatureWarning.

Fixed

  • MeshReader / DomainMeshReader sample discovery no longer uses
    pathlib.Path.glob, which can silently drop entries under filesystem
    metadata-server load (Lustre), causing training to proceed on a subset
    of the dataset.
  • Unified external aerodynamics volume datasets now preserve in-file boundaries
    by default, so GLOBE can resolve boundaries.vehicle during collation.
    Point-based volume model templates explicitly opt into the existing
    boundary-dropping reader optimization.
  • compute_cotan_weights_fem, and the calculus, curvature, and smoothing
    routines built on it such as Mesh.laplacian, no longer fail on degenerate
    cells in float32. The Gram-matrix regularization is now scale-free, so it also
    covers cells with no extent — including the null cells that Mesh.pad and
    Mesh.pad_to_next_power insert — and flat cells at large coordinate values,
    both of which previously raised a singular-matrix _LinAlgError from
    torch.linalg.inv. Weights for non-degenerate cells are unchanged bit for bit.
  • Multinomial index sampling now uses one shared weighted_multinomial
    functional across datapipes, DoMINO, and remeshing. Its core API follows
    torch.multinomial, adds allocation-free integer input for uniform
    populations, and supports sampling with or without replacement. Exact
    sampling without replacement uses torch.randperm or a chunked exponential
    race, with an explicit low-memory Poisson-gap approximation for uniform
    sampling. This removes the torch.multinomial 2^24 category limit for
    sampling without replacement, consolidates duplicated Poisson index
    samplers, and fixes incorrect chunk-local indices and biased per-chunk quotas
    in DoMINO.
  • Unified external aerodynamics recipe: the aggregate metrics reported for
    vector fields under the bare field name (e.g. wss_l2, likewise _l1 /
    _mae) were computed on per-point vector magnitudes, so direction errors
    were invisible — a prediction with the correct magnitude but wrong direction
    at every point scored 0. The bare-name aggregate is now computed over all
    components jointly (whole-field relative norms, Frobenius for l2). The
    broken magnitude-only aggregate is not retained under a separate key.
    Per-component metrics (wss_x_l2, ...) were always direction-sensitive and
    are unchanged, and training/checkpoints are unaffected (the training
    objective goes through LossCalculator, not this metric path) — only
    reported aggregate vector metrics were misleading.
  • Unified external aerodynamics recipe: model templates can now carry
    known-good training overrides (train.yaml's _self_ merges before the
    model template; all existing templates resolve identically). The GLOBE
    example now uses the recipe's default compile and learning-rate
    settings — both measured equivalent or better than the previously
    documented overrides on the DrivAerML surface case — and no longer sets
    training.field_weights={pressure: 1.0, wss: 100.0}, which was redundant
    with NormalizeMeshFields normalization and starved the pressure field
    of gradient signal (~2x worse converged pressure L2 at equal WSS L2).
  • ShardTensor now survives torch.compile / AOTAutograd for tensor-subclass
    users: __tensor_unflatten__ no longer forces requires_grad on the
    reconstructed inner (matching DTensor, so the inner/wrapper flags cannot
    disagree and trip assert_metadata_eq under a Dynamo graph-break re-fake),
    and __coerce_same_metadata_as_tangent__ is subclass-friendly — it accepts a
    subclass's nested flatten context, treats empty and None sharding-shape maps
    as equal, and rebuilds a differing ShardTensor-subclass tangent via that
    type's own __tensor_unflatten__ instead of returning None (the plain-tensor
    / DTensor cross-type None convention is preserved).
  • ShardTensor.to_local() (and op-result forwards feeding it) is now
    differentiable under torch.compile / AOTAutograd. Previously the compiled
    backward was silently dropped (zero / missing gradient): ShardTensor's
    __torch_function__ eager fallback converts to DTensor through
    autograd.Functions that AOTAutograd traces through, severing the primal's
    gradient connection during the joint trace. Under tracing, unpatched ops now
    pass through to __torch_dispatch__ (mirroring DTensor, which defines no
    __torch_function__), keeping the graph differentiable while eager behavior
    and registered shard patches are unchanged.
  • Datapipe contiguous-block subsampling now wraps cyclically, giving boundary
    and interior elements equal inclusion probability.
  • Cell-subsampled GLOBE inputs now retain their effective integration measure,
    preventing area-weighted outputs and gradients from collapsing.
  • physicsnemo.mesh.io.from_pyvista(..., force_copy=True) now copies attached
    point, cell, and global data as well as geometry. The matching new
    to_pyvista(..., force_copy=True) option prevents exported PyVista geometry
    and data from mutating the source Mesh through shared CPU storage.
  • physicsnemo.mesh.sampling.sample_data_at_points now handles integer and
    boolean fields by returning float64, so NaN sentinels and non-integral
    interpolation or multi-cell means are representable (subject to the usual
    float64 precision limits). Point-data interpolation now promotes field and
    geometry dtypes consistently, and accumulation uses fewer full-sized
    temporaries and CUDA host synchronizations.
  • physicsnemo.mesh.projections.extrude now produces a conforming (crack-free)
    simplicial complex for multi-cell inputs. Each prism was previously tessellated
    using the per-cell local vertex order, so adjacent cells that listed a shared
    edge's endpoints in different orders split the shared quad face along opposite
    diagonals; the resulting non-manifold volume leaked interior crack faces into
    get_boundary_mesh (boundary edges shared by 4 faces — e.g. an extruded L-shape
    or any multi-column grid, which also broke repair.fix_orientation). Parent-cell
    vertices are now sorted into a global order before tessellation (the
    Freudenthal-Kuhn subdivision), a no-op for already-sorted inputs.
  • physicsnemo.mesh.generate.marching_cubes now accepts bfloat16 fields by
    converting them to float32 before crossing the NumPy boundary.
  • physicsnemo.mesh.projections.extrude now returns consistently oriented cells
    for full-dimensional (codimension-0) output.
  • physicsnemo.mesh.remeshing.remesh now preserves the input mesh's device and
    floating dtype instead of dropping them to CPU/float32.
  • physicsnemo.mesh.io.to_pyvista now preserves supported dtypes for attached
    point, cell, and global data instead of narrowing every array to float32.
    Reduced-precision floating-point values are promoted only as needed for VTK.
  • physicsnemo.mesh.io.from_pyvista and to_pyvista now preserve float64
    point coordinates instead of unconditionally narrowing geometry to float32,
    which could collapse small features on meshes with large coordinate offsets.
    Existing float32 geometry remains float32.
  • physicsnemo.mesh: Mesh.to(<float dtype>) and DomainMesh.to(<float dtype>)
    raised TypeError: cells must have an int-like dtype because the cast was applied
    to the integer cells tensor. A floating/complex dtype is now applied only to
    floating tensors; the integer cells (and any integer data) are preserved. Device
    moves are unchanged.
  • physicsnemo.mesh: fixed several silent-wrong-result bugs — slice_cells
    carried stale point-level and non-local (gaussian_curvature) caches onto the
    sliced mesh; the intrinsic LSQ gradient returned all-zeros for codimension >= 2
    manifolds (now estimates the tangent space via local PCA); smooth_laplacian
    returned stale geometry caches after its in-place point update; transform
    propagated an incorrect point-normals cache under anisotropic/shear maps; and the
    derived-mesh methods (compute_point_derivatives, compute_cell_derivatives,
    cell_data_to_point_data, point_data_to_cell_data) aliased the source mesh's
    mutable _cache.
  • physicsnemo.mesh.spatial.ClusterTree.compute_source_aggregates now
    normalizes with its call-time area weights instead of the weights used when
    constructing the tree, preserving correct aggregates when weights change.
  • physicsnemo.mesh: fixed crash / data-integrity bugs — project(...) with
    transform_point_data/transform_cell_data=True mutated the input mesh in
    place; visualization and to_pyvista crashed on autograd-tracked tensors (now
    detached before .numpy()); and integer/bool data crashed (safe_eps on an
    integer dtype) or truncated via integer division during facet/scatter
    aggregation (now computed in a floating dtype).
  • physicsnemo.mesh Morton-code quantization now handles empty inputs, tiny
    extents, half-precision coordinates, and one-dimensional endpoints correctly.
  • physicsnemo.mesh: fixed Loop subdivision pulling open boundaries inward (now
    applies the boundary/crease mask); subdivision zero-filling integer/bool
    point_data at new edge vertices (now inherits a parent label);
    non-deterministic orientation flips and over-counted component sizes in
    repair.fix_orientation; random point sampling drawing barycentric weights in
    float32 for float64 meshes; and Mesh.merge not validating point_data /
    global_data key consistency.
  • Fixed DefaultTrainingLoop reading DistributedManager.device at the class
    level (a property descriptor) instead of DistributedManager().device, which
    left the loop's device set to a property object under an initialized
    DistributedManager (physicsnemo/active_learning/loop.py).
  • Replaced three plain-string regex / docstring literals containing invalid
    escape sequences with raw-string equivalents
    (physicsnemo/utils/logging/launch.py,
    physicsnemo/metrics/general/calibration.py,
    physicsnemo/metrics/general/crps.py); these were SyntaxWarnings today
    and become SyntaxErrors in Python 3.16.
  • Various test cleanups to remove self-inflicted warnings in CI output:
    disabled pytest collection for TestModelA/TestModelB helpers in
    test/core/test_registry.py via __test__ = False; migrated
    test/nn/module/test_interpolation.py to call the non-deprecated
    grid_to_point_interpolation and added a dedicated test for the
    deprecation alias; scoped a lr_scheduler.step()-before-optimizer.step()
    UserWarning filter to a single test in
    test/optim/test_combined_optimizer.py; guarded the
    DistributedManager.initialize() calls in test/utils/test_checkpoint.py
    with is_initialized(); and suppressed the import-time
    ExperimentalFeatureWarning in test/datapipes/healda/test_features.py
    via warnings.catch_warnings().
  • Fixed physicsnemo.utils.get_checkpoint_dir returning paths with \
    separators on Windows (e.g. .\checkpoints_model), which was inconsistent
    with the /-based paths used elsewhere in the checkpoint utilities and
    broke the test_get_checkpoint_dir CI test on Windows. The function now
    always joins with /, working uniformly for local paths and fsspec
    URIs (msc://, etc.) across operating systems.

Dependencies

  • Raises the minimum TensorDict version to tensordict[zarr]>=0.14.0,
    restoring the stable tensordict distribution while retaining Zarr support
    and upstream bug fixes.
  • Removes pyacvd from the mesh-extras optional dependencies. Remeshing now
    uses NVIDIA Warp.
  • Updates the minimum supported warp-lang version to 1.14.0.

Contributors

We’re grateful to everyone who contributed code, fixes, documentation, reviews, and ideas to PhysicsNeMo v2.2.0. Your contributions help us continuously improve PhysicsNeMo for the entire community!

A special shout-out to our contributors, in no particular order:

@aayushg55, @fallintoplace, @fgiral000, @jleinonen, @ScSteffen, @wdyab, @zyhu-hu

Thank you ❤️ — we truly appreciate your contributions and hope to see more from you in the future!