Module regpy.vecsps.ngsolve
Finite element vector spaces using NGSolve
This module implements a VectorSpaceBase
instance for NGSolve spaces. This gives the basic
interface to use FES spaces defined in ngsolve
to be used as VectorSpaceBases
in regpy
.
Operators are using such spaces are implemented in the regpy.operators.ngsolve
module. Hilbert spaces
and Functionals defined on such spaces can be found in regpy.hilbert.ngsolve
and regpy.functionals.ngsolve
respectively.
Classes
class NgsBaseVector (vec: ngsolve.la.BaseVector, make_copy: bool | None = False)
-
Expand source code
@dataclass class NgsBaseVector: vec: ngs.la.BaseVector make_copy: Optional[bool] = field(default=False) __array_ufunc__ = None def copy(self): return copy(self) def __post_init__(self): if isinstance(self.vec,ngs.la.BaseVector): if self.make_copy: self.vec = deepcopy(self.vec) pass elif isinstance(self.vec,ngs.la.DynamicVectorExpression): if self.make_copy: self.vec = deepcopy(self.vec.Evaluate()) else: self.vec = self.vec.Evaluate() else: raise TypeError("Could not treat {} type only ngs.la.BaseVector or ngs.la.DynamicVectorExpression".format(type(self.vec))) self.size = self.vec.size self.is_complex = self.vec.is_complex def conj(self): z = self.vec.CreateVector() for i in range(self.size): z[i] = self.vec[i].real - 1j*self.vec[i].imag return NgsBaseVector(z) @property def real(self): z = self.vec.CreateVector() for i in range(self.size): z[i] = self.vec[i].real return NgsBaseVector(z) @property def imag(self): z = self.vec.CreateVector() for i in range(self.size): z[i] = self.vec[i].imag return NgsBaseVector(z) def __iadd__(self,other): assert isinstance(other,NgsBaseVector) and other.size == self.vec.size self.vec.data += other.vec return self def __isub__(self,other): assert isinstance(other,NgsBaseVector) and other.size == self.vec.size self.vec.data -= other.vec return self def __add__(self,other): assert isinstance(other,NgsBaseVector) and other.size == self.vec.size v = self.vec.CreateVector() v.data = self.vec + other.vec return NgsBaseVector(v) def __radd__(self,other): return self + other def __sub__(self,other): return self + (-1*other) def __rsub__(self,other): return (-1*self) + other def __imul__(self,other): assert isinstance(other,float) or isinstance(other,int) self.vec.data *= other return self def __itruediv__(self,other): assert isinstance(other,float) or isinstance(other,int) self.vec.data /= other return self def __mul__(self,other): assert isinstance(other,float) or isinstance(other,int) v = self.vec.CreateVector() v.data = other * self.vec return NgsBaseVector(v) def __rmul__(self,other): return self * other def __truediv__(self,other): assert isinstance(other,float) or isinstance(other,int) v = self.vec.CreateVector() v.data = (1/other)*self.vec return NgsBaseVector(v) def __getitem__(self,i): return self.vec[i] def __setitem__(self,i,val): self.vec[i] = val def __iter__(self): return self.vec def iter_basis(self): v = NgsBaseVector(self.vec.CreateVector()) for i in self.size: v[i] = 1 yield v if self.is_complex: v[i] = 1j yield v v[i] = 0 def __and__(self,x,y): assert isinstance(y,NgsBaseVector) and x.size == y.size return (x_i == y_i for x_i,y_i in zip(x,y)) def __or__(self,x,y): assert isinstance(y,NgsBaseVector) and x.size == y.size return (x_i != y_i for x_i,y_i in zip(x,y)) def __xor__(self,x,y): assert isinstance(y,NgsBaseVector) and x.size == y.size return (x_i != y_i for x_i,y_i in zip(x,y)) def __copy__(self): return deepcopy(self) def __deepcopy__(self, memo): cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): setattr(result, k, deepcopy(v, memo)) return result
NgsBaseVector(vec: ngsolve.la.BaseVector, make_copy: Optional[bool] = False)
Instance variables
var vec : ngsolve.la.BaseVector
-
The type of the None singleton.
var make_copy : bool | None
-
The type of the None singleton.
prop real
-
Expand source code
@property def real(self): z = self.vec.CreateVector() for i in range(self.size): z[i] = self.vec[i].real return NgsBaseVector(z)
prop imag
-
Expand source code
@property def imag(self): z = self.vec.CreateVector() for i in range(self.size): z[i] = self.vec[i].imag return NgsBaseVector(z)
Methods
def copy(self)
-
Expand source code
def copy(self): return copy(self)
def conj(self)
-
Expand source code
def conj(self): z = self.vec.CreateVector() for i in range(self.size): z[i] = self.vec[i].real - 1j*self.vec[i].imag return NgsBaseVector(z)
def iter_basis(self)
-
Expand source code
def iter_basis(self): v = NgsBaseVector(self.vec.CreateVector()) for i in self.size: v[i] = 1 yield v if self.is_complex: v[i] = 1j yield v v[i] = 0
class NgsVectorSpace (fes, bdr=None)
-
Expand source code
class NgsVectorSpace(VectorSpaceBase): """A vector space wrapping an `ngsolve.FESpace`. Parameters ---------- fes : ngsolve.FESpace The wrapped NGSolve vector space. bdr : Boundary of the NGSolve vector space. """ log = classlogger def __init__(self, fes, bdr=None): assert isinstance(fes, ngs.FESpace) self.fes = fes self.bdr = bdr super().__init__(vec_type=NgsBaseVector, shape=(fes.ndof,), complex=fes.is_complex) # Checks if FES is Vector valued and stores the dimension in self.codim from netgen.libngpy._meshing import NgException try: self.codim = len(fes.components) assert self.codim == fes.mesh.dim self._fes_util = ngs.VectorL2(self.fes.mesh, order=0, complex = self.is_complex) except NgException: self.codim = 1 self._fes_util = ngs.L2(self.fes.mesh, order=0, complex = self.is_complex) self._gfu_util = ngs.GridFunction(self._fes_util) self._gfu_fes = ngs.GridFunction(self.fes) self._help_x = NgsBaseVector(self._gfu_fes.vec) def zeros(self): h = self._gfu_fes.vec.CreateVector() h *= 0 return NgsBaseVector(h,make_copy=True) def ones(self): self._gfu_fes.Set(1) return NgsBaseVector(ngs.Projector(self.fes.FreeDofs(), range=True).Project(self._gfu_fes.vec),make_copy=True) def empty(self): h = self._gfu_fes.vec.CreateVector() h *= 0 return NgsBaseVector(h,make_copy=True) def rand(self,random_generator = None): random_generator = random_generator or np.random.random_sample r = random_generator(self._fes_util.ndof) if self.is_complex and not is_complex_dtype(r.dtype): c = np.empty(self._fes_util.ndof, dtype=complex) c.real = r c.imag = random_generator(self._fes_util.ndof) self._gfu_util.vec.FV().NumPy()[:] = c else: self._gfu_util.vec.FV().NumPy()[:] = r self._gfu_fes.Set(self._gfu_util) return NgsBaseVector(ngs.Projector(self.fes.FreeDofs(), range=True).Project(self._gfu_fes.vec),make_copy=True) def poisson(self,x): assert not self.is_complex self._gfu_fes.vec.FV().NumPy[:] = np.random.poisson(x.vec.FV().NumPy()) return NgsBaseVector(ngs.Projector(self.fes.FreeDofs(), range=True).Project(self._gfu_fes.vec),make_copy=True) def __contains__(self,x): if not isinstance(x,NgsBaseVector): return False elif x.size != self.fes.ndof: return False elif x.is_complex: return self.is_complex else: return True def vdot(self, x, y): return ngs.InnerProduct(x.vec,y.vec) def complex_space(self): if self.is_complex: return copy(self) return NgsVectorSpace(type(fes)(fes.mesh,order=fes.globalorder,bdr=self.bdr,complex=True),bdr=self.bdr) def real_space(self): if not self.is_complex: return copy(self) return NgsVectorSpace(type(fes)(fes.mesh,order=fes.globalorder,bdr=self.bdr,complex=False),bdr=self.bdr) def flatten(self, x:NgsBaseVector) -> np.ndarray: if self.is_complex: return np.concatenate([x.vec.FV().NumPy().real,x.vec.FV().NumPy().imag]) else: return x.vec.FV().NumPy().copy() def fromflat(self, vec:np.ndarray) -> NgsBaseVector: if vec.ndim == 1: if self.is_complex and vec.size == self.shape[0] * 2: x = self.zeros() x.vec.FV().NumPy()[:] = vec[:self.shape[0]] + 1j*vec[self.shape[0]] elif vec.size == self.shape[0]: x = self.zeros() x.vec.FV().NumPy()[:] = vec else: raise ValueError("provided vector has non fitting shape.") else: raise ValueError("Provided vector must be one dimensional") return x def __eq__(self, other: object) -> bool: if not isinstance(other,type(self)): return False return self.fes == other.fes def iter_basis(self): r"""Generator iterating over the standard basis of the vector space. For efficiency, the same array is returned in each step, and subsequently modified in-place. If you need the array longer than that, perform a copy. In case of complex a vector space after each each array modified in its place with a real one it returns the same vector with \(1i\) in its place. """ elm = self.zeros() for idx in range(self.shape[0]): elm[idx] = 1 yield elm if self.is_complex: elm[idx] = 1j yield elm elm[idx] = 0 def logical_and(self,x,y): return x & y def logical_or(self,x,y): return x | y def logical_not(self,x): return not x def logical_xor(self,x,y): return x ^ y def is_on_boundary(self,x): if self.bdr is None: return False t = x.vec.CreateVector() t.data = x.vec ngs.Projector(self.fes.FreeDofs(), range=True).Project(t) return np.all(t.FV().NumPy() == 0) def to_gf(self, x): gf = ngs.GridFunction(self.fes) gf.vec.data = x.vec return gf def from_ngs(self, ngs_elem, definedon : ngs.comp.Region|None = None): if isinstance(ngs_elem,ngs.comp.GridFunction): return NgsBaseVector(ngs_elem.vec,make_copy=True) else: self._gfu_fes.Set(ngs_elem,definedon=definedon) return self._help_x.copy()
A vector space wrapping an
ngsolve.FESpace
.Parameters
fes
:ngsolve.FESpace
- The wrapped NGSolve vector space.
bdr
- Boundary of the NGSolve vector space.
Ancestors
Methods
def iter_basis(self)
-
Expand source code
def iter_basis(self): r"""Generator iterating over the standard basis of the vector space. For efficiency, the same array is returned in each step, and subsequently modified in-place. If you need the array longer than that, perform a copy. In case of complex a vector space after each each array modified in its place with a real one it returns the same vector with \(1i\) in its place. """ elm = self.zeros() for idx in range(self.shape[0]): elm[idx] = 1 yield elm if self.is_complex: elm[idx] = 1j yield elm elm[idx] = 0
Generator iterating over the standard basis of the vector space. For efficiency, the same array is returned in each step, and subsequently modified in-place. If you need the array longer than that, perform a copy. In case of complex a vector space after each each array modified in its place with a real one it returns the same vector with 1i in its place.
def is_on_boundary(self, x)
-
Expand source code
def is_on_boundary(self,x): if self.bdr is None: return False t = x.vec.CreateVector() t.data = x.vec ngs.Projector(self.fes.FreeDofs(), range=True).Project(t) return np.all(t.FV().NumPy() == 0)
def to_gf(self, x)
-
Expand source code
def to_gf(self, x): gf = ngs.GridFunction(self.fes) gf.vec.data = x.vec return gf
def from_ngs(self, ngs_elem, definedon: ngsolve.comp.Region | None = None)
-
Expand source code
def from_ngs(self, ngs_elem, definedon : ngs.comp.Region|None = None): if isinstance(ngs_elem,ngs.comp.GridFunction): return NgsBaseVector(ngs_elem.vec,make_copy=True) else: self._gfu_fes.Set(ngs_elem,definedon=definedon) return self._help_x.copy()
Inherited members