Skip to content

Core API Reference

The opifex.core package provides the fundamental abstractions and interfaces for the Opifex framework.

Problems

The Problem interface is defined as a Protocol, serving as the unified contract for all scientific machine learning problems.

Problem Protocol

opifex.core.problems.Problem

Bases: Protocol

Unified interface for all Opifex problems.

This protocol defines the minimal interface that all problem types must implement, enabling consistent treatment across the Opifex framework.

get_geometry

get_geometry() -> Geometry | None

Get the problem geometry if applicable.

Source code in opifex/core/problems.py
def get_geometry(self) -> Geometry | None:
    """Get the problem geometry if applicable."""
    ...

get_parameters

get_parameters() -> dict[str, Any]

Get problem-specific parameters.

Source code in opifex/core/problems.py
def get_parameters(self) -> dict[str, Any]:
    """Get problem-specific parameters."""
    ...

validate

validate() -> bool

Validate problem definition consistency.

Source code in opifex/core/problems.py
def validate(self) -> bool:
    """Validate problem definition consistency."""
    ...

PDE Problems

opifex.core.problems.PDEProblem

PDEProblem(geometry: Geometry, equation: Callable, boundary_conditions: dict[str, Any] | list[Any], initial_conditions: dict[str, Any] | list[Any] | None = None, parameters: dict[str, float] | None = None, time_dependent: bool = False)

Bases: ABC

Base class for Partial Differential Equation problems.

This class provides the foundation for defining PDE problems that can be solved using Physics-Informed Neural Networks (PINNs) or Neural Operators.

Source code in opifex/core/problems.py
def __init__(
    self,
    geometry: Geometry,
    equation: Callable,
    boundary_conditions: dict[str, Any] | list[Any],
    initial_conditions: dict[str, Any] | list[Any] | None = None,
    parameters: dict[str, float] | None = None,
    time_dependent: bool = False,
) -> None:
    self.geometry = geometry
    self.equation = equation
    self.boundary_conditions = boundary_conditions
    self.initial_conditions = initial_conditions or {}
    self.parameters = parameters or {}
    self.time_dependent = time_dependent

get_geometry

get_geometry() -> Geometry

Get the problem geometry.

Source code in opifex/core/problems.py
def get_geometry(self) -> Geometry:
    """Get the problem geometry."""
    return self.geometry

get_parameters

get_parameters() -> dict[str, float]

Get PDE parameters.

Source code in opifex/core/problems.py
def get_parameters(self) -> dict[str, float]:
    """Get PDE parameters."""
    return self.parameters

validate

validate() -> bool

Validate PDE problem definition.

Source code in opifex/core/problems.py
def validate(self) -> bool:
    """Validate PDE problem definition."""
    if not isinstance(self.geometry, Geometry):
        return False
    return callable(self.equation)

residual abstractmethod

residual(x: Array, u: Array, u_derivatives: dict[str, Array]) -> Array

Compute PDE residual for physics-informed training.

Source code in opifex/core/problems.py
@abstractmethod
def residual(self, x: Array, u: Array, u_derivatives: dict[str, Array]) -> Array:
    """Compute PDE residual for physics-informed training."""

ODE Problems

opifex.core.problems.ODEProblem

ODEProblem(time_span: tuple[float, float], equation: Callable, initial_conditions: dict[str, float | Array] | None = None, boundary_conditions: dict[str, Any] | None = None, parameters: dict[str, float] | None = None)

Bases: ABC

Base class for Ordinary Differential Equation problems.

Supports both initial value problems (IVPs) and boundary value problems (BVPs).

Source code in opifex/core/problems.py
def __init__(
    self,
    time_span: tuple[float, float],
    equation: Callable,
    initial_conditions: dict[str, float | Array] | None = None,
    boundary_conditions: dict[str, Any] | None = None,
    parameters: dict[str, float] | None = None,
) -> None:
    self.time_span = time_span
    self.equation = equation
    self.initial_conditions = initial_conditions or {}
    self.boundary_conditions = boundary_conditions or {}
    self.parameters = parameters or {}

get_geometry

get_geometry() -> Geometry | None

ODE problems typically have a time domain, not spatial geometry.

Source code in opifex/core/problems.py
def get_geometry(self) -> Geometry | None:
    """ODE problems typically have a time domain, not spatial geometry."""
    return None

get_time_domain

get_time_domain() -> dict[str, tuple[float, float]]

Get the time domain.

Source code in opifex/core/problems.py
def get_time_domain(self) -> dict[str, tuple[float, float]]:
    """Get the time domain."""
    return {"t": self.time_span}

get_parameters

get_parameters() -> dict[str, float]

Get ODE parameters.

Source code in opifex/core/problems.py
def get_parameters(self) -> dict[str, float]:
    """Get ODE parameters."""
    return self.parameters

validate

validate() -> bool

Validate ODE problem definition.

Source code in opifex/core/problems.py
def validate(self) -> bool:
    """Validate ODE problem definition."""
    if self.time_span[1] <= self.time_span[0]:
        return False
    return callable(self.equation)

rhs abstractmethod

rhs(t: float, y: Array) -> Array

Right-hand side of dy/dt = f(t, y).

Source code in opifex/core/problems.py
@abstractmethod
def rhs(self, t: float, y: Array) -> Array:
    """Right-hand side of dy/dt = f(t, y)."""

Optimization Problems

opifex.core.problems.OptimizationProblem

OptimizationProblem(dimension: int, bounds: list[tuple[float, float]] | None = None, constraints: list[Callable] | None = None, parameters: dict[str, Any] | None = None)

Bases: ABC

Base class for optimization problems.

Supports both constrained and unconstrained optimization, with support for learn-to-optimize (L2O) applications.

Source code in opifex/core/problems.py
def __init__(
    self,
    dimension: int,
    bounds: list[tuple[float, float]] | None = None,
    constraints: list[Callable] | None = None,
    parameters: dict[str, Any] | None = None,
) -> None:
    self.dimension = dimension
    self.bounds = bounds
    self.constraints = constraints or []
    self.parameters = parameters or {}

get_geometry

get_geometry() -> Geometry | None

Optimization problems don't strictly have a geometry.

Source code in opifex/core/problems.py
def get_geometry(self) -> Geometry | None:
    """Optimization problems don't strictly have a geometry."""
    return None

get_domain

get_domain() -> dict[str, Any]

Get optimization domain info.

Source code in opifex/core/problems.py
def get_domain(self) -> dict[str, Any]:
    """Get optimization domain info."""
    return {
        "dimension": self.dimension,
        "bounds": self.bounds,
        "constraints": len(self.constraints),
    }

get_parameters

get_parameters() -> dict[str, Any]

Get optimization parameters.

Source code in opifex/core/problems.py
def get_parameters(self) -> dict[str, Any]:
    """Get optimization parameters."""
    return self.parameters

validate

validate() -> bool

Validate optimization problem.

Source code in opifex/core/problems.py
def validate(self) -> bool:
    """Validate optimization problem."""
    if self.dimension <= 0:
        return False
    return not (self.bounds and len(self.bounds) != self.dimension)

objective abstractmethod

objective(x: Array) -> float

Objective function to minimize.

Source code in opifex/core/problems.py
@abstractmethod
def objective(self, x: Array) -> float:
    """Objective function to minimize."""

gradient

gradient(x: Array) -> Array

Gradient of objective function (if available).

Source code in opifex/core/problems.py
def gradient(self, x: Array) -> Array:
    """Gradient of objective function (if available)."""
    # Use JAX automatic differentiation for gradient computation
    grad_fn = jax.grad(self.objective)
    return grad_fn(x)

hessian

hessian(x: Array) -> Array

Hessian of objective function (if available).

Source code in opifex/core/problems.py
def hessian(self, x: Array) -> Array:
    """Hessian of objective function (if available)."""
    # Use JAX automatic differentiation for hessian computation
    hessian_fn = jax.hessian(self.objective)
    return hessian_fn(x)

Quantum Problems

opifex.core.problems.QuantumProblem

QuantumProblem(molecular_system: MolecularSystem, method: str = 'neural_dft', convergence_threshold: float = 1e-08, max_iterations: int = 100, parameters: dict[str, Any] | None = None)

Bases: ABC

Base class for quantum mechanical problems.

This class provides the foundation for quantum mechanical calculations, including electronic structure, molecular dynamics, and quantum chemistry.

Source code in opifex/core/problems.py
def __init__(
    self,
    molecular_system: MolecularSystem,
    method: str = "neural_dft",
    convergence_threshold: float = 1e-8,
    max_iterations: int = 100,
    parameters: dict[str, Any] | None = None,
) -> None:
    self.molecular_system = molecular_system
    self.method = method
    self.convergence_threshold = convergence_threshold
    self.max_iterations = max_iterations
    self.parameters = parameters or {}

get_geometry

get_geometry() -> None

Quantum problems use MolecularSystem, which could expose geometry later.

Source code in opifex/core/problems.py
def get_geometry(self) -> None:
    """Quantum problems use MolecularSystem, which could expose geometry later."""
    # TODO: Adapter for MolecularSystem to Geometry?
    return

get_domain

get_domain() -> dict[str, Any]

Get quantum mechanical domain.

Source code in opifex/core/problems.py
def get_domain(self) -> dict[str, Any]:
    """Get quantum mechanical domain."""
    return {
        "n_atoms": self.molecular_system.n_atoms,
        "n_electrons": self.molecular_system.n_electrons,
        "charge": self.molecular_system.charge,
        "multiplicity": self.molecular_system.multiplicity,
        "is_periodic": self.molecular_system.is_periodic,
    }

get_parameters

get_parameters() -> dict[str, Any]

Get quantum mechanical parameters.

Source code in opifex/core/problems.py
def get_parameters(self) -> dict[str, Any]:
    """Get quantum mechanical parameters."""
    return {
        "method": self.method,
        "convergence_threshold": self.convergence_threshold,
        "max_iterations": self.max_iterations,
        **self.parameters,
    }

validate

validate() -> bool

Validate quantum problem definition.

Source code in opifex/core/problems.py
def validate(self) -> bool:
    """Validate quantum problem definition."""
    if self.molecular_system.n_atoms <= 0:
        return False
    if self.molecular_system.n_electrons <= 0:
        return False
    return not self.convergence_threshold <= 0

compute_energy abstractmethod

compute_energy(density: Array | None = None) -> float | Array

Compute total energy.

Source code in opifex/core/problems.py
@abstractmethod
def compute_energy(self, density: Array | None = None) -> float | Array:
    """Compute total energy."""

compute_forces abstractmethod

compute_forces(density: Array | None = None) -> Array

Compute forces on nuclei.

Source code in opifex/core/problems.py
@abstractmethod
def compute_forces(self, density: Array | None = None) -> Array:
    """Compute forces on nuclei."""

opifex.core.problems.ElectronicStructureProblem

ElectronicStructureProblem(molecular_system: MolecularSystem, functional_type: str = 'neural_xc', scf_method: str = 'neural_scf', grid_level: int = 3, neural_functional_path: str | None = None, boundary_conditions: list[Any] | None = None, constraints: list[Any] | None = None, **kwargs)

Bases: QuantumProblem

Electronic structure calculation problem for Neural DFT.

This class specifically handles electronic structure calculations using neural density functional theory, including neural exchange-correlation functionals and ML-accelerated SCF methods.

Source code in opifex/core/problems.py
def __init__(
    self,
    molecular_system: MolecularSystem,
    functional_type: str = "neural_xc",
    scf_method: str = "neural_scf",
    grid_level: int = 3,
    neural_functional_path: str | None = None,
    boundary_conditions: list[Any] | None = None,
    constraints: list[Any] | None = None,
    **kwargs,
) -> None:
    super().__init__(molecular_system, method="neural_dft", **kwargs)
    self.functional_type = functional_type
    self.scf_method = scf_method
    self.grid_level = grid_level
    self.neural_functional_path = neural_functional_path
    self.boundary_conditions = boundary_conditions or []
    self.constraints = constraints or []

    # Neural DFT specific parameters
    self.parameters.update(
        {
            "functional_type": functional_type,
            "scf_method": scf_method,
            "grid_level": grid_level,
            "target_accuracy": 1e-3,  # kcal/mol (chemical accuracy)
            "use_symmetry": True,
            "precision": "float64",  # Higher precision for quantum calculations
        }
    )

scf_solver property

scf_solver: SCFSolver

The restricted Kohn-Sham SCF solver backing this problem.

Built lazily (and cached) from the problem's :class:MolecularSystem and the requested functional, then reused for the energy and the analytic forces so both come from one self-consistent solve.

get_parameters

get_parameters() -> dict[str, Any]

Get Neural DFT specific parameters.

Source code in opifex/core/problems.py
def get_parameters(self) -> dict[str, Any]:
    """Get Neural DFT specific parameters."""
    base_params = super().get_parameters()
    base_params.update(
        {
            "functional_type": self.functional_type,
            "scf_method": self.scf_method,
            "grid_level": self.grid_level,
            "neural_functional_path": self.neural_functional_path,
        }
    )
    return base_params

validate

validate() -> bool

Validate Neural DFT problem definition.

Source code in opifex/core/problems.py
def validate(self) -> bool:
    """Validate Neural DFT problem definition."""
    if not super().validate():
        return False

    # Neural DFT specific validation
    valid_functionals = ["neural_xc", "dm21", "hybrid_neural", "pbe_neural"]
    if self.functional_type not in valid_functionals:
        return False

    valid_scf_methods = ["neural_scf", "traditional_scf", "hybrid_scf"]
    if self.scf_method not in valid_scf_methods:
        return False

    return not (self.grid_level < 1 or self.grid_level > 5)

compute_energy

compute_energy(density: Array | None = None) -> float | Array

Compute the converged Kohn-Sham total energy of the system.

Delegates to :meth:_energy_from_positions -- the same differentiable routine that :meth:compute_forces differentiates -- so the energy and the forces are mutually consistent (F = -dE/dR) and the public quantum API is jit / grad / vmap compatible. A concrete Python float is returned in eager execution; under JAX transforms the traced array is returned instead (calling float() on a tracer raises a TypeError subclass, which selects the array branch).

Parameters:

Name Type Description Default
density Array | None

Ignored. The restricted Kohn-Sham SCF solves for the self-consistent density itself; the argument is retained only for interface parity with :class:QuantumProblem.

None

Returns:

Type Description
float | Array

Total Kohn-Sham energy in Hartree.

Source code in opifex/core/problems.py
def compute_energy(self, density: Array | None = None) -> float | Array:
    """Compute the converged Kohn-Sham total energy of the system.

    Delegates to :meth:`_energy_from_positions` -- the same differentiable
    routine that :meth:`compute_forces` differentiates -- so the energy and
    the forces are mutually consistent (``F = -dE/dR``) and the public
    quantum API is ``jit`` / ``grad`` / ``vmap`` compatible. A concrete
    Python ``float`` is returned in eager execution; under JAX transforms
    the traced array is returned instead (calling ``float()`` on a tracer
    raises a ``TypeError`` subclass, which selects the array branch).

    Args:
        density: Ignored. The restricted Kohn-Sham SCF solves for the
            self-consistent density itself; the argument is retained only
            for interface parity with :class:`QuantumProblem`.

    Returns:
        Total Kohn-Sham energy in Hartree.
    """
    energy = self._energy_from_positions(self.molecular_system.positions, density)
    try:
        return float(energy)
    except (TypeError, ValueError):
        # Under jit/grad/vmap ``energy`` is a tracer; return it for AD.
        return energy

compute_forces

compute_forces(density: Array | None = None) -> Array

Analytic nuclear forces :math:F = -\partial E/\partial R.

The exact implicit-differentiation forces of the converged Kohn-Sham energy (:meth:~opifex.neural.quantum.dft.SCFSolver.compute_forces).

Parameters:

Name Type Description Default
density Array | None

Ignored (the SCF solves for the density); see :meth:compute_energy.

None

Returns:

Type Description
Array

Forces on nuclei in Hartree/Bohr [Shape: (n_atoms, 3)].

Source code in opifex/core/problems.py
def compute_forces(self, density: Array | None = None) -> Array:
    r"""Analytic nuclear forces :math:`F = -\partial E/\partial R`.

    The exact implicit-differentiation forces of the converged Kohn-Sham
    energy (:meth:`~opifex.neural.quantum.dft.SCFSolver.compute_forces`).

    Args:
        density: Ignored (the SCF solves for the density); see
            :meth:`compute_energy`.

    Returns:
        Forces on nuclei in Hartree/Bohr [Shape: (n_atoms, 3)].
    """
    del density  # The SCF solves for the self-consistent density.
    return self.scf_solver.compute_forces(self.molecular_system.positions)

setup_neural_functional

setup_neural_functional() -> dict[str, Any]

Setup neural exchange-correlation functional.

Source code in opifex/core/problems.py
def setup_neural_functional(self) -> dict[str, Any]:
    """Setup neural exchange-correlation functional."""
    return {
        "functional_type": self.functional_type,
        "neural_path": self.neural_functional_path,
        "grid_level": self.grid_level,
        "symmetry_constraints": True,
    }

setup_scf_cycle

setup_scf_cycle() -> dict[str, Any]

Setup Self-Consistent Field cycle parameters.

Source code in opifex/core/problems.py
def setup_scf_cycle(self) -> dict[str, Any]:
    """Setup Self-Consistent Field cycle parameters."""
    return {
        "method": self.scf_method,
        "convergence_threshold": self.convergence_threshold,
        "max_iterations": self.max_iterations,
        "mixing_parameter": 0.7,
        "acceleration": "pulay" if self.scf_method == "traditional_scf" else "neural",
    }

Factory Functions

Create a PDE problem instance.

Create an ODE problem instance.

Create an optimization problem instance.

Create an electronic-structure (Kohn-Sham DFT) problem instance.

The returned :class:ElectronicStructureProblem computes its energy and analytic forces through the real restricted Kohn-Sham SCF solver (:class:~opifex.neural.quantum.dft.SCFSolver); functional_type selects the exchange-correlation functional (pbe_* requests use the PBE GGA, all others use the LDA).

Boundary Conditions

Base Classes

Bases: ABC

Abstract base class for boundary conditions.

Parameters:

Name Type Description Default
boundary str

Boundary identifier (e.g., "left", "right", "top", "bottom")

required
time_dependent bool

Whether condition varies with time

False
spatial_dependent bool

Whether condition varies with spatial position

True

validate abstractmethod

validate() -> bool

Validate boundary condition specification.

evaluate abstractmethod

evaluate(x: Array, t: float = 0.0) -> Array

Evaluate boundary condition at given position and time.

apply

apply(params: Array, x: Array | None = None, t: float = 0.0, weight: float = 1.0, **kwargs: Any) -> Array

Apply this boundary condition to a parameter array.

The default is the identity: boundary conditions that do not mask the raw parameter vector (e.g. :class:WavefunctionBC) leave it unchanged. DirichletBC/NeumannBC/RobinBC override this to constrain the relevant entries.

Parameters:

Name Type Description Default
params Array

Parameter array to constrain.

required
x Array | None

Optional spatial coordinates for function evaluation.

None
t float

Time for time-dependent conditions.

0.0
weight float

Scaling applied by overriding conditions.

1.0
**kwargs Any

Accepted for a uniform call signature across conditions.

{}

Returns:

Type Description
Array

The (possibly constrained) parameter array.

Initial condition specification for time-dependent problems.

Parameters:

Name Type Description Default
value float | Callable[[Array], Array]

Constant value or function defining initial condition

required
dimension int

Dimension of the solution field

1
derivative_order int

Order of time derivative (0=position, 1=velocity, etc.)

0
name str | None

Optional name for the initial condition

None

validate

validate() -> bool

Validate initial condition specification.

evaluate

evaluate(x: Array) -> Array

Evaluate initial condition at given position.

Bases: ABC

Abstract base class for constraints.

Parameters:

Name Type Description Default
constraint_type str

Type of constraint

required
tolerance float

Tolerance for constraint satisfaction

1e-08

validate abstractmethod

validate() -> bool

Validate constraint specification.

Classical Boundary Conditions

Bases: BoundaryCondition

Dirichlet boundary condition: u = g on boundary.

Parameters:

Name Type Description Default
boundary str

Boundary identifier

required
value float | Callable[..., Array]

Constant value or function g(x) or g(x, t) for boundary

required
time_dependent bool

Whether condition varies with time

False

validate

validate() -> bool

Validate Dirichlet boundary condition.

evaluate

evaluate(x: Array, t: float = 0.0) -> Array

Evaluate Dirichlet condition at given position and time.

apply

apply(params: Array, x: Array | None = None, t: float = 0.0, weight: float = 1.0, **kwargs: Any) -> Array

Apply Dirichlet boundary condition to parameters.

This method bridges the OOP boundary specification with the functional boundary application system, allowing BC objects to apply themselves.

Parameters:

Name Type Description Default
params Array

Parameter array to constrain

required
x Array | None

Optional spatial coordinates for function evaluation

None
t float

Time for time-dependent conditions

0.0
weight float

Constraint weight (0-1, default 1.0)

1.0
**kwargs Any

Additional arguments (left_boundary, right_boundary)

{}

Returns:

Type Description
Array

Parameters with Dirichlet boundary condition applied

Examples:

>>> bc = DirichletBC(boundary="left", value=0.0)
>>> params = jnp.array([1.0, 2.0, 3.0, 4.0, 5.0])
>>> constrained = bc.apply(params)
>>> # Only left boundary modified: constrained[0] == 0.0

Bases: BoundaryCondition

Neumann boundary condition: du/dn = g on boundary.

Parameters:

Name Type Description Default
boundary str

Boundary identifier

required
value float | Callable[..., Array]

Constant value or function g(x) or g(x, t) for normal derivative

required
time_dependent bool

Whether condition varies with time

False

validate

validate() -> bool

Validate Neumann boundary condition.

evaluate

evaluate(x: Array, t: float = 0.0) -> Array

Evaluate Neumann condition at given position and time.

apply

apply(params: Array, x: Array | None = None, t: float = 0.0, weight: float = 1.0, **kwargs: Any) -> Array

Apply Neumann boundary condition to parameters.

This method bridges the OOP boundary specification with the functional boundary application system, allowing BC objects to apply themselves.

Parameters:

Name Type Description Default
params Array

Parameter array to constrain

required
x Array | None

Optional spatial coordinates (unused for Neumann, kept for interface consistency)

None
t float

Time for time-dependent conditions (unused for Neumann, kept for interface consistency)

0.0
weight float

Constraint weight (0-1, default 1.0)

1.0

Returns:

Type Description
Array

Parameters with Neumann boundary condition applied (zero derivative)

Examples:

>>> bc = NeumannBC(boundary="wall", value=0.0)
>>> params = jnp.array([10.0, 2.0, 3.0, 4.0, 20.0])
>>> constrained = bc.apply(params)
>>> # constrained[0] == params[1], constrained[-1] == params[-2]

Bases: BoundaryCondition

Robin (mixed) boundary condition: alpha*u + beta*du/dn = gamma on boundary.

Parameters:

Name Type Description Default
boundary str

Boundary identifier

required
alpha float | Callable[..., float]

Coefficient for u term

required
beta float | Callable[..., float]

Coefficient for du/dn term

required
gamma float | Callable[..., Array]

Right-hand side function

required
time_dependent bool

Whether condition varies with time

False

validate

validate() -> bool

Validate Robin boundary condition.

evaluate

evaluate(x: Array, t: float = 0.0) -> Array

Evaluate Robin condition coefficients and RHS at given position and time.

apply

apply(params: Array, x: Array | None = None, t: float = 0.0, weight: float = 1.0, **kwargs: Any) -> Array

Apply Robin boundary condition to parameters.

This method bridges the OOP boundary specification with the functional boundary application system, allowing BC objects to apply themselves.

Robin condition: alpha*u + beta*du/dn = gamma on boundary

Parameters:

Name Type Description Default
params Array

Parameter array to constrain

required
x Array | None

Optional spatial coordinates for function evaluation

None
t float

Time for time-dependent conditions

0.0
weight float

Constraint weight (0-1, default 1.0)

1.0

Returns:

Type Description
Array

Parameters with Robin boundary condition applied

Examples:

>>> bc = RobinBC(boundary="left", alpha=1.0, beta=0.0, gamma=0.0)
>>> params = jnp.array([1.0, 2.0, 3.0, 4.0, 5.0])
>>> constrained = bc.apply(params)
>>> # Behaves like Dirichlet when beta=0

Quantum Boundary Conditions & Constraints

Bases: BoundaryCondition

Quantum mechanical wavefunction boundary conditions.

Parameters:

Name Type Description Default
condition_type str

Type of wavefunction condition ("vanishing", "normalization", "periodic", "boundary")

required
boundary str

Boundary identifier for spatial boundaries

'all'
value complex | None

Value for boundary conditions (real values auto-converted to complex)

None
norm_value float | None

Normalization value for wavefunction

None

validate

validate() -> bool

Validate wavefunction boundary condition.

evaluate

evaluate(x: Array, t: float = 0.0) -> Array

Evaluate wavefunction boundary condition.

Bases: Constraint

Electronic density constraints for quantum systems.

Parameters:

Name Type Description Default
constraint_type str

Type of constraint ("conservation", "positivity", "particle_number")

required
n_electrons int | None

Number of electrons for particle number conservation

None
tolerance float

Tolerance for constraint satisfaction

1e-08
enforcement_method str

Method for constraint enforcement

'lagrange'

validate

validate() -> bool

Validate density constraint.

Bases: Constraint

Molecular symmetry constraints for quantum systems.

Parameters:

Name Type Description Default
point_group str | None

Point group symmetry (e.g., "C2v", "D2h")

None
operations Sequence[str] | None

List of symmetry operations

None
symmetry_type str

Type of symmetry ("point_group", "translational")

'point_group'
lattice_vectors Array | None

Lattice vectors for periodic systems

None
enforce_in_loss bool

Whether to enforce symmetry in loss function

True

validate

validate() -> bool

Validate symmetry constraint.

Collections

Collection and management of boundary conditions.

Parameters:

Name Type Description Default
boundary_conditions Sequence[BoundaryCondition]

List of boundary conditions

required

validate

validate() -> bool

Validate all boundary conditions in collection.

get_boundary_condition

get_boundary_condition(boundary: str) -> BoundaryCondition | None

Get boundary condition for specific boundary.

get_by_type

get_by_type(condition_type: str) -> list[BoundaryCondition]

Get all boundary conditions of specific type.

add_condition

add_condition(condition: BoundaryCondition) -> None

Add a new boundary condition.

remove_condition

remove_condition(boundary: str) -> bool

Remove boundary condition for specific boundary.

apply_all

apply_all(params: Array, x: Array | None = None, t: float = 0.0, weight: float = 1.0) -> Array

Apply all boundary conditions in collection to parameters.

This method sequentially applies each boundary condition in the collection, allowing multiple BCs to be enforced together.

Parameters:

Name Type Description Default
params Array

Parameter array to constrain

required
x Array | None

Optional spatial coordinates for function evaluation

None
t float

Time for time-dependent conditions

0.0
weight float

Global constraint weight applied to all BCs (0-1, default 1.0)

1.0

Returns:

Type Description
Array

Parameters with all boundary conditions applied

Examples:

>>> bc1 = DirichletBC(boundary="left", value=0.0)
>>> bc2 = NeumannBC(boundary="right", value=0.0)
>>> collection = BoundaryConditionCollection([bc1, bc2])
>>> params = jnp.array([1.0, 2.0, 3.0, 4.0, 5.0])
>>> constrained = collection.apply_all(params)