Update Laplace class and add unit tests (#645)

This commit is contained in:
Giovanni Canali
2025-09-22 15:05:28 +02:00
committed by GitHub
parent 4a6e73fa54
commit 4e37468460
15 changed files with 673 additions and 157 deletions

View File

@@ -2,42 +2,10 @@
import torch
from ... import Condition
from ...operator import grad
from ...equation import Equation
from ...domain import CartesianDomain
from ...utils import check_consistency
from ...problem import SpatialProblem, TimeDependentProblem
class AdvectionEquation(Equation):
"""
Implementation of the advection equation.
"""
def __init__(self, c):
"""
Initialization of the :class:`AdvectionEquation`.
:param c: The advection velocity parameter.
:type c: float | int
"""
self.c = c
check_consistency(self.c, (float, int))
def equation(input_, output_):
"""
Implementation of the advection equation.
:param LabelTensor input_: Input data of the problem.
:param LabelTensor output_: Output data of the problem.
:return: The residual of the advection equation.
:rtype: LabelTensor
"""
u_x = grad(output_, input_, components=["u"], d=["x"])
u_t = grad(output_, input_, components=["u"], d=["t"])
return u_t + self.c * u_x
super().__init__(equation)
from ...equation import Equation, Advection
from ...utils import check_consistency
from ...domain import CartesianDomain
def initial_condition(input_, output_):
@@ -89,13 +57,10 @@ class AdvectionProblem(SpatialProblem, TimeDependentProblem):
:type c: float | int
"""
super().__init__()
check_consistency(c, (float, int))
self.c = c
check_consistency(self.c, (float, int))
self.conditions["D"] = Condition(
domain="D", equation=AdvectionEquation(self.c)
)
self.conditions["D"] = Condition(domain="D", equation=Advection(self.c))
def solution(self, pts):
"""

View File

@@ -2,32 +2,18 @@
import torch
from ... import Condition
from ...equation import Equation
from ...domain import CartesianDomain
from ...operator import grad, laplacian
from ...problem import SpatialProblem, TimeDependentProblem
def allen_cahn_equation(input_, output_):
"""
Implementation of the Allen Cahn equation.
:param LabelTensor input_: Input data of the problem.
:param LabelTensor output_: Output data of the problem.
:return: The residual of the Allen Cahn equation.
:rtype: LabelTensor
"""
u_t = grad(output_, input_, components=["u"], d=["t"])
u_xx = laplacian(output_, input_, components=["u"], d=["x"])
return u_t - 0.0001 * u_xx + 5 * output_**3 - 5 * output_
from ...equation import Equation, AllenCahn
from ...utils import check_consistency
from ...domain import CartesianDomain
def initial_condition(input_, output_):
"""
Definition of the initial condition of the Allen Cahn problem.
:param LabelTensor input_: Input data of the problem.
:param LabelTensor output_: Output data of the problem.
:param LabelTensor input_: The input data of the problem.
:param LabelTensor output_: The output data of the problem.
:return: The residual of the initial condition.
:rtype: LabelTensor
"""
@@ -64,6 +50,25 @@ class AllenCahnProblem(TimeDependentProblem, SpatialProblem):
}
conditions = {
"D": Condition(domain="D", equation=Equation(allen_cahn_equation)),
"t0": Condition(domain="t0", equation=Equation(initial_condition)),
}
def __init__(self, alpha=1e-4, beta=5):
"""
Initialization of the :class:`AllenCahnProblem`.
:param alpha: The diffusion coefficient.
:type alpha: float | int
:param beta: The reaction coefficient.
:type beta: float | int
"""
super().__init__()
check_consistency(alpha, (float, int))
check_consistency(beta, (float, int))
self.alpha = alpha
self.beta = beta
self.conditions["D"] = Condition(
domain="D",
equation=AllenCahn(alpha=self.alpha, beta=self.beta),
)

View File

@@ -2,40 +2,18 @@
import torch
from ... import Condition
from ...domain import CartesianDomain
from ...operator import grad, laplacian
from ...equation import Equation, FixedValue
from ...equation import Equation, FixedValue, DiffusionReaction
from ...problem import SpatialProblem, TimeDependentProblem
def diffusion_reaction(input_, output_):
"""
Implementation of the diffusion-reaction equation.
:param LabelTensor input_: Input data of the problem.
:param LabelTensor output_: Output data of the problem.
:return: The residual of the diffusion-reaction equation.
:rtype: LabelTensor
"""
x = input_.extract("x")
t = input_.extract("t")
u_t = grad(output_, input_, components=["u"], d=["t"])
u_xx = laplacian(output_, input_, components=["u"], d=["x"])
r = torch.exp(-t) * (
1.5 * torch.sin(2 * x)
+ (8 / 3) * torch.sin(3 * x)
+ (15 / 4) * torch.sin(4 * x)
+ (63 / 8) * torch.sin(8 * x)
)
return u_t - u_xx - r
from ...utils import check_consistency
from ...domain import CartesianDomain
def initial_condition(input_, output_):
"""
Definition of the initial condition of the diffusion-reaction problem.
:param LabelTensor input_: Input data of the problem.
:param LabelTensor output_: Output data of the problem.
:param LabelTensor input_: The input data of the problem.
:param LabelTensor output_: The output data of the problem.
:return: The residual of the initial condition.
:rtype: LabelTensor
"""
@@ -76,12 +54,43 @@ class DiffusionReactionProblem(TimeDependentProblem, SpatialProblem):
}
conditions = {
"D": Condition(domain="D", equation=Equation(diffusion_reaction)),
"g1": Condition(domain="g1", equation=FixedValue(0.0)),
"g2": Condition(domain="g2", equation=FixedValue(0.0)),
"t0": Condition(domain="t0", equation=Equation(initial_condition)),
}
def __init__(self, alpha=1e-4):
"""
Initialization of the :class:`DiffusionReactionProblem`.
:param alpha: The diffusion coefficient.
:type alpha: float | int
"""
super().__init__()
check_consistency(alpha, (float, int))
self.alpha = alpha
def forcing_term(input_):
"""
Implementation of the forcing term.
"""
# Extract spatial and temporal variables
spatial_d = [di for di in input_.labels if di != "t"]
x = input_.extract(spatial_d)
t = input_.extract("t")
return torch.exp(-t) * (
1.5 * torch.sin(2 * x)
+ (8 / 3) * torch.sin(3 * x)
+ (15 / 4) * torch.sin(4 * x)
+ (63 / 8) * torch.sin(8 * x)
)
self.conditions["D"] = Condition(
domain="D",
equation=DiffusionReaction(self.alpha, forcing_term),
)
def solution(self, pts):
"""
Implementation of the analytical solution of the diffusion-reaction

View File

@@ -2,46 +2,10 @@
import torch
from ... import Condition
from ...operator import laplacian
from ...equation import FixedValue, Helmholtz
from ...utils import check_consistency
from ...domain import CartesianDomain
from ...problem import SpatialProblem
from ...utils import check_consistency
from ...equation import Equation, FixedValue
class HelmholtzEquation(Equation):
"""
Implementation of the Helmholtz equation.
"""
def __init__(self, alpha):
"""
Initialization of the :class:`HelmholtzEquation` class.
:param alpha: Parameter of the forcing term.
:type alpha: float | int
"""
self.alpha = alpha
check_consistency(alpha, (int, float))
def equation(input_, output_):
"""
Implementation of the Helmholtz equation.
:param LabelTensor input_: Input data of the problem.
:param LabelTensor output_: Output data of the problem.
:return: The residual of the Helmholtz equation.
:rtype: LabelTensor
"""
lap = laplacian(output_, input_, components=["u"], d=["x", "y"])
q = (
(1 - 2 * (self.alpha * torch.pi) ** 2)
* torch.sin(self.alpha * torch.pi * input_.extract("x"))
* torch.sin(self.alpha * torch.pi * input_.extract("y"))
)
return lap + output_ - q
super().__init__(equation)
class HelmholtzProblem(SpatialProblem):
@@ -88,8 +52,19 @@ class HelmholtzProblem(SpatialProblem):
self.alpha = alpha
check_consistency(alpha, (int, float))
def forcing_term(self, input_):
"""
Implementation of the forcing term.
"""
return (
(1 - 2 * (self.alpha * torch.pi) ** 2)
* torch.sin(self.alpha * torch.pi * input_.extract("x"))
* torch.sin(self.alpha * torch.pi * input_.extract("y"))
)
self.conditions["D"] = Condition(
domain="D", equation=HelmholtzEquation(self.alpha)
domain="D",
equation=Helmholtz(self.alpha, forcing_term),
)
def solution(self, pts):

View File

@@ -1,29 +1,25 @@
"""Formulation of the Poisson problem in a square domain."""
import torch
from ... import Condition
from ...operator import laplacian
from ...equation import FixedValue, Poisson
from ...problem import SpatialProblem
from ...domain import CartesianDomain
from ...equation import Equation, FixedValue
from ... import Condition
def laplace_equation(input_, output_):
def forcing_term(input_):
"""
Implementation of the laplace equation.
Implementation of the forcing term of the Poisson problem.
:param LabelTensor input_: Input data of the problem.
:param LabelTensor output_: Output data of the problem.
:return: The residual of the laplace equation.
:param LabelTensor input_: The points where the forcing term is evaluated.
:return: The forcing term of the Poisson problem.
:rtype: LabelTensor
"""
force_term = (
return (
torch.sin(input_.extract(["x"]) * torch.pi)
* torch.sin(input_.extract(["y"]) * torch.pi)
* (2 * torch.pi**2)
)
delta_u = laplacian(output_, input_, components=["u"], d=["x", "y"])
return delta_u - force_term
class Poisson2DSquareProblem(SpatialProblem):
@@ -51,14 +47,14 @@ class Poisson2DSquareProblem(SpatialProblem):
"g2": Condition(domain="g2", equation=FixedValue(0.0)),
"g3": Condition(domain="g3", equation=FixedValue(0.0)),
"g4": Condition(domain="g4", equation=FixedValue(0.0)),
"D": Condition(domain="D", equation=Equation(laplace_equation)),
"D": Condition(domain="D", equation=Poisson(forcing_term=forcing_term)),
}
def solution(self, pts):
"""
Implementation of the analytical solution of the Poisson problem.
:param LabelTensor pts: Points where the solution is evaluated.
:param LabelTensor pts: The points where the solution is evaluated.
:return: The analytical solution of the Poisson problem.
:rtype: LabelTensor
"""