Page MenuHomec4science

helmholtz_square_bubble_domain_problem_engine.py
No OneTemporary

File Metadata

Created
Tue, May 7, 07:58

helmholtz_square_bubble_domain_problem_engine.py

# Copyright (C) 2018 by the RROMPy authors
#
# This file is part of RROMPy.
#
# RROMPy is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# RROMPy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
#
import numpy as np
import scipy.sparse as scsp
import fenics as fen
from rrompy.utilities.base.types import (Np1D, ScOp, Tuple, List, FenExpr,
paramVal)
from rrompy.solver.fenics import fenZERO
from .helmholtz_problem_engine import HelmholtzProblemEngine
from rrompy.utilities.base import verbosityDepth
from rrompy.utilities.poly_fitting.polynomial import (
hashDerivativeToIdx as hashD, hashIdxToDerivative as hashI)
from rrompy.solver.fenics import fenics2Sparse, fenics2Vector
__all__ = ['HelmholtzSquareBubbleDomainProblemEngine']
class HelmholtzSquareBubbleDomainProblemEngine(HelmholtzProblemEngine):
"""
Solver for square bubble Helmholtz problems with parametric domain heigth.
- \Delta u - kappa^2 * u = f in \Omega_mu = [0,\pi] x [0,\mu\pi]
u = 0 on \Gamma_mu = \partial\Omega_mu
with exact solution square bubble times plane wave.
"""
def __init__(self, kappa:float, theta:float, n:int, mu0 : paramVal = [1.],
degree_threshold : int = np.inf, verbosity : int = 10,
timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
verbosity = verbosity, timestamp = timestamp)
self.nAs, self.nbs = 3, 20
self.kappa = kappa
self.theta = theta
self.forcingTermMu = np.nan
mesh = fen.RectangleMesh(fen.Point(0, 0), fen.Point(np.pi, np.pi),
3 * n, 3 * n)
self.V = fen.FunctionSpace(mesh, "P", 1)
self.rescalingExp = [1.]
def buildEnergyNormForm(self): # H1
"""
Build sparse matrix (in CSR format) representative of scalar product.
"""
mudxM = np.abs(self.mu0(0, 0)) * (fen.dot(self.u.dx(0), self.v.dx(0))
+ fen.dot(self.u, self.v))
imudy = 1. / np.abs(self.mu0(0, 0)) * fen.dot(self.u.dx(1),
self.v.dx(1))
normMatFen = fen.assemble((mudxM + imudy) * fen.dx)
normMat = fen.as_backend_type(normMatFen).mat()
self.energyNormMatrix = scsp.csr_matrix(normMat.getValuesCSR()[::-1],
shape = normMat.size)
def getForcingTerm(self, mu : paramVal = []) -> Tuple[FenExpr, FenExpr]:
"""Compute forcing term."""
mu = self.checkParameter(mu)
if mu != self.forcingTermMu:
if self.verbosity >= 25:
verbosityDepth("INIT", ("Assembling base expression for "
"forcing term."),
timestamp = self.timestamp)
pi = np.pi
c, s = np.cos(self.theta), np.sin(self.theta)
x, y = fen.SpatialCoordinate(self.V.mesh())[:]
muR, muI = np.real(mu(0, 0)), np.imag(mu(0, 0))
mu2R, mu2I = np.real(mu(0, 0) ** 2.), np.imag(mu(0, 0) ** 2.)
C = 16. / pi ** 4.
bR = C * (2 * (x * (pi - x) + y * (pi - y))
+ (self.kappa * s) ** 2. * (mu2R - 1.)
* x * (pi - x) * y * (pi - y))
bI = C * (2 * self.kappa * (c * (pi - 2 * x) * y * (pi - y)
+ s * x * (pi - x) * (pi - 2 * y))
+ (self.kappa * s) ** 2. * mu2I
* x * (pi - x) * y * (pi - y))
wR = (fen.cos(self.kappa * (c * x + s * muR * y))
* fen.exp(self.kappa * s * muI * y))
wI = (fen.sin(self.kappa * (c * x + s * muR * y))
* fen.exp(self.kappa * s * muI * y))
self.forcingTerm = [bR * wR + bI * wI, bI * wR - bR * wI]
self.forcingTermMu = mu
if self.verbosity >= 25:
verbosityDepth("DEL", "Done assembling base expression.",
timestamp = self.timestamp)
return self.forcingTerm
def getExtraFactorB(self, mu : paramVal = [],
derI : int = 0) -> Tuple[FenExpr, FenExpr]:
"""Compute extra expression in RHS."""
mu = self.checkParameter(mu)
def getPowMinusj(x, power):
powR = x ** power
powI = fenZERO
if power % 2 == 1:
powR, powI = powI, powR
if (power + 3) % 4 < 2:
powR, powI = - powR, - powI
return powR, powI
if self.verbosity >= 25:
verbosityDepth("INIT", ("Assembling auxiliary expression for "
"forcing term derivative."),
timestamp = self.timestamp)
from scipy.special import factorial as fact
y = fen.SpatialCoordinate(self.V.mesh())[1]
powR, powI = [(self.kappa * np.sin(self.theta)) ** derI * k\
for k in getPowMinusj(y, derI)]
mu2R, mu2I = np.real(mu(0, 0) ** 2.), np.imag(mu(0, 0) ** 2.)
exprR = mu2R * powR - mu2I * powI
exprI = mu2I * powR + mu2R * powI
if derI >= 1:
muR, muI = np.real(2. * mu(0, 0)), np.imag(2. * mu(0, 0))
powR, powI = [(self.kappa * np.sin(self.theta)) ** (derI - 1) * k\
* derI for k in getPowMinusj(y, derI - 1)]
exprR += muR * powR - muI * powI
exprI += muI * powR + muR * powI
if derI >= 2:
powR, powI = [(self.kappa * np.sin(self.theta)) ** (derI - 2) * k\
* derI * (derI - 1) for k in getPowMinusj(y, derI - 2)]
exprR += powR
exprI += powI
fac = fact(derI)
if self.verbosity >= 25:
verbosityDepth("DEL", "Done assembling auxiliary expression.",
timestamp = self.timestamp)
return [exprR / fac, exprI / fac]
def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
"""Assemble (derivative of) operator of linear system."""
mu = self.checkParameter(mu)
if not hasattr(der, "__len__"): der = [der] * self.npar
derI = hashD(der)
self.autoSetDS()
if derI <= 0 and self.As[0] is None:
if self.verbosity >= 20:
verbosityDepth("INIT", "Assembling operator term A0.",
timestamp = self.timestamp)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
a0Re = fen.dot(self.u.dx(1), self.v.dx(1)) * fen.dx
self.As[0] = fenics2Sparse(a0Re, {}, DirichletBC0, 1)
if self.verbosity >= 20:
verbosityDepth("DEL", "Done assembling operator term.",
timestamp = self.timestamp)
if derI <= 1 and self.As[1] is None:
self.As[1] = self.checkAInBounds(-1)
if derI <= 2 and self.As[2] is None:
if self.verbosity >= 20:
verbosityDepth("INIT", "Assembling operator term A2.",
timestamp = self.timestamp)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
k2Re, k2Im = np.real(self.omega ** 2), np.imag(self.omega ** 2)
k2n2Re = k2Re * n2Re - k2Im * n2Im
k2n2Im = k2Re * n2Im + k2Im * n2Re
parsRe = self.iterReduceQuadratureDegree(zip([k2n2Re],
["kappaSquaredRefractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([k2n2Im],
["kappaSquaredRefractionIndexSquaredImag"]))
a2Re = (fen.dot(self.u.dx(0), self.v.dx(0))
- k2n2Re * fen.dot(self.u, self.v)) * fen.dx
a2Im = - k2n2Im * fen.dot(self.u, self.v) * fen.dx
self.As[2] = (fenics2Sparse(a2Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a2Im, parsIm, DirichletBC0, 0))
if self.verbosity >= 20:
verbosityDepth("DEL", "Done assembling operator term.",
timestamp = self.timestamp)
return self._assembleA(mu, der, derI)
def b(self, mu : paramVal = [], der : List[int] = 0,
homogeneized : bool = False) -> Np1D:
"""Assemble (derivative of) RHS of linear system."""
mu = self.checkParameter(mu)
if not hasattr(der, "__len__"): der = [der] * self.npar
derI = hashD(der)
nbsTot = self.nbsH if homogeneized else self.nbs
bs = self.bsH if homogeneized else self.bs
if homogeneized and self.mu0 != self.mu0BC:
self.liftDirichletData(self.mu0)
for j in range(derI, nbsTot):
if bs[j] is None:
if self.verbosity >= 20:
verbosityDepth("INIT", ("Assembling forcing term "
"b{}.").format(j),
timestamp = self.timestamp)
if j < self.nbs:
fRe, fIm = self.getForcingTerm(self.mu0)
cRe, cIm = self.getExtraFactorB(self.mu0, j)
cfRe, cfIm = cRe * fRe - cIm * fIm, cRe * fIm + cIm * fRe
else:
cfRe, cfIm = fenZERO, fenZERO
parsRe = self.iterReduceQuadratureDegree(zip([cfRe],
["forcingTermDer{}Real".format(j)]))
parsIm = self.iterReduceQuadratureDegree(zip([cfIm],
["forcingTermDer{}Imag".format(j)]))
L0Re = fen.dot(cfRe, self.v) * fen.dx
L0Im = fen.dot(cfIm, self.v) * fen.dx
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
b = (fenics2Vector(L0Re, parsRe, DirichletBC0, 1)
+ 1.j * fenics2Vector(L0Im, parsIm, DirichletBC0, 1))
if homogeneized:
Ader = self.A(self.mu0, hashI(j, self.npar))
b -= Ader.dot(self.liftedDirichletDatum)
if homogeneized:
self.bsH[j] = b
else:
self.bs[j] = b
if self.verbosity >= 20:
verbosityDepth("DEL", "Done assembling forcing term.",
timestamp = self.timestamp)
return self._assembleb(mu, der, derI, homogeneized, self.mu0)

Event Timeline