diff --git a/psydac/api/discretization.py b/psydac/api/discretization.py index 0d74f3178..93c46ebad 100644 --- a/psydac/api/discretization.py +++ b/psydac/api/discretization.py @@ -43,27 +43,37 @@ from psydac.linalg.stencil import StencilVectorSpace from psydac.linalg.block import BlockVectorSpace -__all__ = ('discretize', 'discretize_derham', 'reduce_space_degrees', 'discretize_space', 'discretize_domain') - +__all__ = ( + 'discretize', + 'discretize_derham', + 'reduce_space_degrees', + 'discretize_space', + 'discretize_domain' +) #============================================================================== def change_dtype(V, dtype): """ - This function take a FemSpace V and create a new vector_space for it with the data type required. + Given a FemSpace V, change its underlying vector_space (i.e. the space of + its coefficients) so that it matches the required data type. Parameters ---------- - Vh : FemSpace - The FEM space. + The FEM space, which is modified in place. - dtype : Data Type - float or complex + dtype : float or complex + Datatype of the new vector_space. + + Returns + ------- + FemSpace + The same FEM space passed as input, which was modified in place. """ if not V.vector_space.dtype == dtype: if isinstance(V.vector_space, BlockVectorSpace): # Recreate the BlockVectorSpace - new_spaces=[] + new_spaces = [] for v in V.spaces: change_dtype(v, dtype) new_spaces.append(v.vector_space) @@ -84,22 +94,30 @@ def change_dtype(V, dtype): #============================================================================== def discretize_derham(derham, domain_h, get_H1vec_space = False, *args, **kwargs): """ - Create a discrete De Rham sequence by creating the spaces and then initiating DiscreteDerham object. + Create a discrete De Rham sequence from a symbolic one. + + This function creates the discrete spaces from the symbolic ones, and then + creates a DiscreteDerham object from them. Parameters ---------- - derham : sympde.topology.space.Derham - The symbolic Derham sequence + The symbolic Derham sequence. - domain_h : Geometry - Discrete domain where the spaces will be discretized + domain_h : Geometry + Discrete domain where the spaces will be discretized. get_H1vec_space : Bool - True to also get the "Hvec" space discretizing (H1)^n vector fields + True to also get the "Hvec" space discretizing (H1)^n vector fields. **kwargs : list - optional parameters for the space discretization + Optional parameters for the space discretization. + + Returns + ------- + DiscreteDerham + The discrete De Rham sequence containing the discrete spaces, + differential operators and projectors. """ ldim = derham.shape @@ -117,6 +135,7 @@ def discretize_derham(derham, domain_h, get_H1vec_space = False, *args, **kwargs spaces.append(Xh) return DiscreteDerham(mapping, *spaces) + #============================================================================== def reduce_space_degrees(V, Vh, *, basis='B', sequence='DR'): """ @@ -168,7 +187,7 @@ def reduce_space_degrees(V, Vh, *, basis='B', sequence='DR'): The symbolic space. Vh : TensorFemSpace - The tensor product fem space. + The tensor product FEM space. basis: str The basis function of the reduced spaces, it can be either 'B' for @@ -185,7 +204,7 @@ def reduce_space_degrees(V, Vh, *, basis='B', sequence='DR'): Returns ------- Wh : TensorFemSpace, VectorFemSpace - The reduced space + The reduced space. """ multiplicity = Vh.multiplicity @@ -250,7 +269,6 @@ def reduce_space_degrees(V, Vh, *, basis='B', sequence='DR'): return Wh - #============================================================================== # TODO knots def discretize_space(V, domain_h, *, degree=None, multiplicity=None, knots=None, nquads=None, basis='B', sequence='DR'): @@ -259,12 +277,11 @@ def discretize_space(V, domain_h, *, degree=None, multiplicity=None, knots=None, Parameters ---------- - V : - the symbolic space + The symbolic space. domain_h : - the discretized domain + The discretized domain. degree : list | dict The degree of the h1 space in each direction. @@ -306,8 +323,7 @@ def discretize_space(V, domain_h, *, degree=None, multiplicity=None, knots=None, Returns ------- Vh : - represents the discrete fem space - + The discrete FEM space. """ # we have two cases, the case where we have a geometry file, diff --git a/psydac/api/feec.py b/psydac/api/feec.py index 07acc0b4d..a0039b734 100644 --- a/psydac/api/feec.py +++ b/psydac/api/feec.py @@ -9,29 +9,39 @@ from psydac.feec.pull_push import pull_1d_h1, pull_1d_l2 from psydac.feec.pull_push import pull_2d_h1, pull_2d_hcurl, pull_2d_hdiv, pull_2d_l2, pull_2d_h1vec from psydac.feec.pull_push import pull_3d_h1, pull_3d_hcurl, pull_3d_hdiv, pull_3d_l2, pull_3d_h1vec +from psydac.fem.basic import FemSpace from psydac.fem.vector import VectorFemSpace - __all__ = ('DiscreteDerham',) #============================================================================== class DiscreteDerham(BasicDiscrete): - """ Represent the discrete De Rham sequence. - Should be initialized via discretize_derham function in api.discretization.py - + """ A discrete de Rham sequence built over a single-patch geometry. + Parameters ---------- + mapping : Mapping or None + Symbolic mapping from the logical space to the physical space, if any. - mapping : Mapping - The mapping from the logical space to the physical space of the discrete De Rham. - *spaces : list of FemSpace - The discrete spaces of the De Rham sequence + The discrete spaces of the de Rham sequence. + + Notes + ----- + - The basic type Mapping is defined in module sympde.topology.mapping. + A discrete mapping (spline or NURBS) may be attached to it. + + - This constructor should not be called directly, but rather from the + `discretize_derham` function in `psydac.api.discretization`. + + - For the multipatch counterpart of this class please see + `MultipatchDiscreteDerham` in `psydac.feec.multipatch.api`. """ def __init__(self, mapping, *spaces): assert (mapping is None) or isinstance(mapping, Mapping) - + assert all(isinstance(space, FemSpace) for space in spaces) + self.has_vec = isinstance(spaces[-1], VectorFemSpace) if self.has_vec : @@ -86,51 +96,94 @@ def __init__(self, mapping, *spaces): #-------------------------------------------------------------------------- @property def dim(self): + """Dimension of the physical and logical domains, which are assumed to be the same.""" return self._dim @property def V0(self): + """First space of the de Rham sequence : H1 space""" return self._spaces[0] @property def V1(self): + """Second space of the de Rham sequence : + - 1d : L2 space + - 2d : either Hdiv or Hcurl space + - 3d : Hcurl space""" return self._spaces[1] @property def V2(self): + """Third space of the de Rham sequence : + - 2d : L2 space + - 3d : Hdiv space""" return self._spaces[2] @property def V3(self): + """Fourth space of the de Rham sequence : L2 space in 3d""" return self._spaces[3] @property def H1vec(self): + """Vector-valued H1 space built as the Cartesian product of N copies of V0, + where N is the dimension of the (logical) domain.""" assert self.has_vec return self._H1vec @property def spaces(self): + """Spaces of the proper de Rham sequence (excluding Hvec).""" return self._spaces @property def mapping(self): + """The mapping from the logical space to the physical space.""" return self._mapping @property def callable_mapping(self): + """The mapping as a callable.""" return self._callable_mapping @property def derivatives_as_matrices(self): + """Differential operators of the De Rham sequence as LinearOperator objects.""" return tuple(V.diff.matrix for V in self.spaces[:-1]) @property - def derivatives_as_operators(self): + def derivatives(self): + """Differential operators of the De Rham sequence as `DiffOperator` objects. + + Those are objects with `domain` and `codomain` properties that are `FemSpace`, + they act on `FemField` (they take a `FemField` of their `domain` as input and return + a `FemField` of their `codomain`. + """ return tuple(V.diff for V in self.spaces[:-1]) #-------------------------------------------------------------------------- def projectors(self, *, kind='global', nquads=None): + """Projectors mapping callable functions of the physical coordinates to a + corresponding `FemField` object in the De Rham sequence. + + Parameters + ---------- + kind : str + Type of the projection : at the moment, only global is accepted and + returns geometric commuting projectors based on interpolation/histopolation + for the De Rham sequence (GlobalProjector objects). + + nquads : list(int) | tuple(int) + Number of quadrature points along each direction, to be used in Gauss + quadrature rule for computing the (approximated) degrees of freedom. + + Returns + ------- + P0, ..., Pn : callables + Projectors that can be called on any callable function that maps + from the physical space to R (scalar case) or R^d (vector case) and + returns a FemField belonging to the i-th space of the De Rham sequence + """ if not (kind == 'global'): raise NotImplementedError('only global projectors are available')