11"""Module for defining various general equations."""
2-
2+ from typing import Callable
3+ import torch
34from .equation import Equation
45from ..operator import grad , div , laplacian
6+ from ..utils import check_consistency
57
68
79class FixedValue (Equation ):
@@ -121,7 +123,7 @@ def __init__(self, value, components=None, d=None):
121123
122124 :param float value: The fixed value to be enforced to the laplacian.
123125 :param list[str] components: The name of the output variables for which
124- the null laplace condition is applied. It should be a subset of the
126+ the fixed laplace condition is applied. It should be a subset of the
125127 output labels. If ``None``, all output variables are considered.
126128 Default is ``None``.
127129 :param list[str] d: The name of the input variables on which the
@@ -146,3 +148,297 @@ def equation(input_, output_):
146148 )
147149
148150 super ().__init__ (equation )
151+
152+
153+ class Laplace (FixedLaplacian ):
154+ """
155+ Equation to enforce a null laplacian for a specific condition.
156+ """
157+
158+ def __init__ (self , components = None , d = None ):
159+ """
160+ Initialization of the :class:`Laplace` class.
161+
162+ :param list[str] components: The name of the output variables for which
163+ the null laplace condition is applied. It should be a subset of the
164+ output labels. If ``None``, all output variables are considered.
165+ Default is ``None``.
166+ :param list[str] d: The name of the input variables on which the
167+ laplacian is computed. It should be a subset of the input labels.
168+ If ``None``, all the input variables are considered.
169+ Default is ``None``.
170+ """
171+ super ().__init__ (0.0 , components = components , d = d )
172+
173+
174+ class AdvectionEquation (Equation ):
175+ r"""
176+ Implementation of the N-dimensional advection equation with constant
177+ velocity parameter. The equation is defined as follows:
178+
179+ .. math::
180+
181+ \frac{\partial u}{\partial t} + c \cdot \nabla u = 0
182+
183+ Here, :math:`c` is the advection velocity parameter.
184+ """
185+
186+ def __init__ (self , c ):
187+ """
188+ Initialization of the :class:`AdvectionEquation`.
189+
190+ :param c: The advection velocity. If a scalar is provided, the same
191+ velocity is applied to all spatial dimensions. If a list is
192+ provided, it must contain one value per spatial dimension.
193+ :type c: float | int | List[float] | List[int]
194+ :raises ValueError: If ``c`` is an empty list.
195+ """
196+ # Check consistency
197+ check_consistency (c , (float , int , list ))
198+ if isinstance (c , list ):
199+ all (check_consistency (ci , (float , int )) for ci in c )
200+ if len (c ) < 1 :
201+ raise ValueError ("'c' cannot be an empty list." )
202+ else :
203+ c = [c ]
204+
205+ # Store advection velocity parameter
206+ self .c = torch .tensor (c ).unsqueeze (0 )
207+
208+ def equation (input_ , output_ ):
209+ """
210+ Implementation of the advection equation.
211+
212+ :param LabelTensor input_: The input data of the problem.
213+ :param LabelTensor output_: The output data of the problem.
214+ :return: The residual of the advection equation.
215+ :rtype: LabelTensor
216+ :raises ValueError: If the ``input_`` labels do not contain the time
217+ variable 't'.
218+ :raises ValueError: If ``c`` is a list and its length is not
219+ consistent with the number of spatial dimensions.
220+ """
221+ # Store labels
222+ input_lbl = input_ .labels
223+ spatial_d = [di for di in input_lbl if di != "t" ]
224+
225+ # Ensure time is passed as input
226+ if "t" not in input_lbl :
227+ raise ValueError (
228+ "The ``input_`` labels must contain the time 't' variable."
229+ )
230+
231+ # Ensure consistency of c length
232+ if len (self .c ) != (len (input_lbl ) - 1 ) and len (self .c ) > 1 :
233+ raise ValueError (
234+ "If 'c' is passed as a list, its length must be equal to "
235+ "the number of spatial dimensions."
236+ )
237+
238+ # Repeat c to ensure consistent shape for advection
239+ self .c = self .c .repeat (output_ .shape [0 ], 1 )
240+ if self .c .shape [1 ] != (len (input_lbl ) - 1 ):
241+ self .c = self .c .repeat (1 , len (input_lbl ) - 1 )
242+
243+ # Add a dimension to c for the following operations
244+ self .c = self .c .unsqueeze (- 1 )
245+
246+ # Compute the time derivative and the spatial gradient
247+ time_der = grad (output_ , input_ , components = None , d = "t" )
248+ grads = grad (output_ = output_ , input_ = input_ , d = spatial_d )
249+
250+ # Reshape and transpose
251+ tmp = grads .reshape (* output_ .shape , len (spatial_d ))
252+ tmp = tmp .transpose (- 1 , - 2 )
253+
254+ # Compute advection term
255+ adv = (tmp * self .c ).sum (dim = tmp .tensor .ndim - 2 )
256+
257+ return time_der + adv
258+
259+ super ().__init__ (equation )
260+
261+
262+ class AllenCahnEquation (Equation ):
263+ r"""
264+ Implementation of the N-dimensional Allen-Cahn equation, defined as follows:
265+
266+ .. math::
267+
268+ \frac{\partial u}{\partial t} - \alpha \Delta u + \beta(u^3 - u) = 0
269+
270+ Here, :math:`\alpha` and :math:`\beta` are parameters of the equation.
271+ """
272+
273+ def __init__ (self , alpha , beta ):
274+ """
275+ Initialization of the :class:`AllenCahnEquation`.
276+
277+ :param alpha: The diffusion coefficient.
278+ :type alpha: float | int
279+ :param beta: The reaction coefficient.
280+ :type beta: float | int
281+ """
282+ check_consistency (alpha , (float , int ))
283+ check_consistency (beta , (float , int ))
284+ self .alpha = alpha
285+ self .beta = beta
286+
287+ def equation (input_ , output_ ):
288+ """
289+ Implementation of the Allen-Cahn equation.
290+
291+ :param LabelTensor input_: The input data of the problem.
292+ :param LabelTensor output_: The output data of the problem.
293+ :return: The residual of the Allen-Cahn equation.
294+ :rtype: LabelTensor
295+ :raises ValueError: If the ``input_`` labels do not contain the time
296+ variable 't'.
297+ """
298+ # Ensure time is passed as input
299+ if "t" not in input_ .labels :
300+ raise ValueError (
301+ "The ``input_`` labels must contain the time 't' variable."
302+ )
303+
304+ # Compute the time derivative and the spatial laplacian
305+ u_t = grad (output_ , input_ , d = ["t" ])
306+ u_xx = laplacian (
307+ output_ , input_ , d = [di for di in input_ .labels if di != "t" ]
308+ )
309+
310+ return u_t - self .alpha * u_xx + self .beta * (output_ ** 3 - output_ )
311+
312+ super ().__init__ (equation )
313+
314+
315+ class DiffusionReactionEquation (Equation ):
316+ r"""
317+ Implementation of the N-dimensional Diffusion-Reaction equation,
318+ defined as follows:
319+
320+ .. math::
321+
322+ \frac{\partial u}{\partial t} - \alpha \Delta u - f = 0
323+
324+ Here, :math:`\alpha` is a parameter of the equation, while :math:`f` is the
325+ reaction term.
326+ """
327+
328+ def __init__ (self , alpha , forcing_term ):
329+ """
330+ Initialization of the :class:`DiffusionReactionEquation`.
331+
332+ :param alpha: The diffusion coefficient.
333+ :type alpha: float | int
334+ :param Callable forcing_term: The forcing field function, taking as
335+ input the points on which evaluation is required.
336+ """
337+ check_consistency (alpha , (float , int ))
338+ check_consistency (forcing_term , (Callable ))
339+ self .alpha = alpha
340+ self .forcing_term = forcing_term
341+
342+ def equation (input_ , output_ ):
343+ """
344+ Implementation of the Diffusion-Reaction equation.
345+
346+ :param LabelTensor input_: The input data of the problem.
347+ :param LabelTensor output_: The output data of the problem.
348+ :return: The residual of the Diffusion-Reaction equation.
349+ :rtype: LabelTensor
350+ :raises ValueError: If the ``input_`` labels do not contain the time
351+ variable 't'.
352+ """
353+ # Ensure time is passed as input
354+ if "t" not in input_ .labels :
355+ raise ValueError (
356+ "The ``input_`` labels must contain the time 't' variable."
357+ )
358+
359+ # Compute the time derivative and the spatial laplacian
360+ u_t = grad (output_ , input_ , d = ["t" ])
361+ u_xx = laplacian (
362+ output_ , input_ , d = [di for di in input_ .labels if di != "t" ]
363+ )
364+
365+ return u_t - self .alpha * u_xx - self .forcing_term (input_ )
366+
367+ super ().__init__ (equation )
368+
369+
370+ class HelmholtzEquation (Equation ):
371+ r"""
372+ Implementation of the Helmholtz equation, defined as follows:
373+
374+ .. math::
375+
376+ \Delta u + k u - f = 0
377+
378+ Here, :math:`k` is a parameter of the equation, while :math:`f` is the
379+ forcing term.
380+ """
381+
382+ def __init__ (self , k , forcing_term ):
383+ """
384+ Initialization of the :class:`HelmholtzEquation` class.
385+
386+ :param k: The parameter of the equation.
387+ :type k: float | int
388+ :param Callable forcing_term: The forcing field function, taking as
389+ input the points on which evaluation is required.
390+ """
391+ check_consistency (k , (int , float ))
392+ check_consistency (forcing_term , (Callable ))
393+ self .k = k
394+ self .forcing_term = forcing_term
395+
396+ def equation (input_ , output_ ):
397+ """
398+ Implementation of the Helmholtz equation.
399+
400+ :param LabelTensor input_: The input data of the problem.
401+ :param LabelTensor output_: The output data of the problem.
402+ :return: The residual of the Helmholtz equation.
403+ :rtype: LabelTensor
404+ """
405+ lap = laplacian (output_ , input_ )
406+ return lap + self .k * output_ - self .forcing_term (input_ )
407+
408+ super ().__init__ (equation )
409+
410+
411+ class PoissonEquation (Equation ):
412+ r"""
413+ Implementation of the Poisson equation, defined as follows:
414+
415+ .. math::
416+
417+ \Delta u - f = 0
418+
419+ Here, :math:`f` is the forcing term.
420+ """
421+
422+ def __init__ (self , forcing_term ):
423+ """
424+ Initialization of the :class:`PoissonEquation` class.
425+
426+ :param Callable forcing_term: The forcing field function, taking as
427+ input the points on which evaluation is required.
428+ """
429+ check_consistency (forcing_term , (Callable ))
430+ self .forcing_term = forcing_term
431+
432+ def equation (input_ , output_ ):
433+ """
434+ Implementation of the Poisson equation.
435+
436+ :param LabelTensor input_: The input data of the problem.
437+ :param LabelTensor output_: The output data of the problem.
438+ :return: The residual of the Poisson equation.
439+ :rtype: LabelTensor
440+ """
441+ lap = laplacian (output_ , input_ )
442+ return lap - self .forcing_term (input_ )
443+
444+ super ().__init__ (equation )
0 commit comments