Page MenuHomec4science

generic_approximant.py
No OneTemporary

File Metadata

Created
Sat, Apr 27, 12:29

generic_approximant.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/>.
#
from abc import abstractmethod
import numpy as np
from copy import copy
from rrompy.sampling.base.sampling_engine_base import SamplingEngineBase
from rrompy.utilities.base.types import Np1D, DictAny, HFEng, sampleEng, strLst
from rrompy.utilities.base import purgeDict, verbosityDepth
__all__ = ['GenericApproximant']
class GenericApproximant:
"""
ABSTRACT
ROM approximant computation for parametric problems.
Args:
HFEngine: HF problem solver.
mu0(optional): Default parameter. Defaults to 0.
approxParameters(optional): Dictionary containing values for main
parameters of approximant. Recognized keys are:
- 'POD': whether to compute POD of snapshots; defaults to True.
Defaults to empty dict.
homogeneized: Whether to homogeneize Dirichlet BCs. Defaults to False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
homogeneized: Whether to homogeneize Dirichlet BCs.
approxParameters: Dictionary containing values for main parameters of
approximant. Recognized keys are in parameterList.
parameterList: Recognized keys of approximant parameters:
- 'POD': whether to compute POD of snapshots.
verbosity: Verbosity level.
POD: Whether to compute POD of snapshots.
samplingEngine: Sampling engine.
uHF: High fidelity solution with wavenumber lastSolvedHF as numpy
complex vector.
lastSolvedHF: Wavenumber corresponding to last computed high fidelity
solution.
uApp: Last evaluated approximant as numpy complex vector.
lastApproxParameters: List of parameters corresponding to last
computed approximant.
"""
def __init__(self, HFEngine:HFEng, mu0 : complex = 0,
approxParameters : DictAny = {}, homogeneized : bool = False,
verbosity : int = 10):
self._preInit()
self.verbosity = verbosity
if self.verbosity >= 10:
verbosityDepth("INIT", ("Initializing approximant engine of "
"type {}.").format(self.name()))
self.HFEngine = HFEngine
self._HFEngine0 = copy(HFEngine)
self._addParametersToList(["POD"])
self.mu0 = mu0
self.homogeneized = homogeneized
self.approxParameters = approxParameters
self._postInit()
def _preInit(self):
if not hasattr(self, "depth"): self.depth = 0
else: self.depth += 1
def _addParametersToList(self, what:strLst):
if not hasattr(self, "parameterList"):
self.parameterList = []
self.parameterList += what
def _postInit(self):
if self.depth == 0:
if self.verbosity >= 10:
verbosityDepth("DEL", "Done initializing.\n")
del self.depth
else: self.depth -= 1
def name(self) -> str:
return self.__class__.__name__
def __str__(self) -> str:
return self.name()
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
def setupSampling(self, SamplingEngine : sampleEng = SamplingEngineBase):
"""Setup sampling engine."""
self.samplingEngine = SamplingEngine(self.HFEngine,
verbosity = self.verbosity)
@property
def approxParameters(self):
"""Value of approximant parameters."""
return self._approxParameters
@approxParameters.setter
def approxParameters(self, approxParams):
if not hasattr(self, "approxParameters"):
self._approxParameters = {}
approxParameters = purgeDict(approxParams, self.parameterList,
dictname = self.name() + ".approxParameters",
baselevel = 1)
keyList = list(approxParameters.keys())
if "POD" in keyList:
self.POD = approxParameters["POD"]
elif hasattr(self, "POD"):
self.POD = self.POD
else:
self.POD = True
@property
def POD(self):
"""Value of POD."""
return self._POD
@POD.setter
def POD(self, POD):
if hasattr(self, "POD"): PODold = self.POD
else: PODold = -1
self._POD = POD
self._approxParameters["POD"] = self.POD
if PODold != self.POD:
self.setupSampling()
self.resetSamples()
@property
def homogeneized(self):
"""Value of homogeneized."""
return self._homogeneized
@homogeneized.setter
def homogeneized(self, homogeneized):
if not hasattr(self, "_homogeneized"):
self._homogeneized = None
if homogeneized != self.homogeneized:
self._homogeneized = homogeneized
self.resetSamples()
def solveHF(self, mu : complex = None):
"""
Find high fidelity solution with original parameters and arbitrary
parameter.
Args:
mu: Target parameter.
"""
if mu is None: mu = self.mu0
if (not hasattr(self, "lastSolvedHF")
or not np.isclose(self.lastSolvedHF, mu)):
self.uHF = self.samplingEngine.solveLS(mu,
homogeneized = self.homogeneized)
self.lastSolvedHF = mu
def resetSamples(self):
"""Reset samples."""
if hasattr(self, "samplingEngine"):
self.samplingEngine.resetHistory()
else:
self.setupSampling()
def plotSamples(self, name : str = "u", save : str = None,
what : strLst = 'all', saveFormat : str = "eps",
saveDPI : int = 100, **figspecs):
"""
Do some nice plots of the samples.
Args:
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
self.samplingEngine.plotSamples(name = name, save = save, what = what,
saveFormat = saveFormat,
saveDPI = saveDPI,
**figspecs)
@abstractmethod
def setupApprox(self):
"""
Setup approximant. (ABSTRACT)
Any specialization should include something like
self.computeDerivatives()
if not self.checkComputedApprox():
...
self.lastApproxParameters = copy(self.approxParameters)
"""
pass
def checkComputedApprox(self) -> bool:
"""
Check if setup of new approximant is not needed.
Returns:
True if new setup is not needed. False otherwise.
"""
return (hasattr(self, "lastApproxParameters")
and self.approxParameters == self.lastApproxParameters)
@abstractmethod
def evalApproxReduced(self, mu:complex):
"""
Evaluate reduced representation of approximant at arbitrary parameter.
(ABSTRACT)
Any specialization should include something like
self.setupApprox()
self.uAppReduced = ...
Args:
mu: Target parameter.
"""
pass
@abstractmethod
def evalApprox(self, mu:complex):
"""
Evaluate approximant at arbitrary parameter. (ABSTRACT)
Any specialization should include something like
self.evalApproxReduced(mu)
self.uApp = ...
Args:
mu: Target parameter.
"""
pass
def getHF(self, mu:complex, homogeneized : bool = False) -> Np1D:
"""
Get HF solution at arbitrary parameter.
Args:
mu: Target parameter.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
Returns:
HFsolution.
"""
self.solveHF(mu)
if self.homogeneized and not homogeneized:
return self.uHF + self.HFEngine.liftDirichletData(mu)
if not self.homogeneized and homogeneized:
return self.uHF - self.HFEngine.liftDirichletData(mu)
return self.uHF
def getRHS(self, mu:complex, homogeneized : bool = False) -> Np1D:
"""
Get linear system RHS at arbitrary parameter.
Args:
mu: Target parameter.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
Returns:
Linear system RHS.
"""
return self.HFEngine.residual(None, mu, homogeneized = homogeneized)
def getAppReduced(self, mu:complex) -> Np1D:
"""
Get approximant at arbitrary parameter.
Args:
mu: Target parameter.
Returns:
Reduced approximant.
"""
self.evalApproxReduced(mu)
return self.uAppReduced
def getApp(self, mu:complex, homogeneized : bool = False) -> Np1D:
"""
Get approximant at arbitrary parameter.
Args:
mu: Target parameter.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
Returns:
Approximant.
"""
self.evalApprox(mu)
if self.homogeneized and not homogeneized:
return self.uApp + self.HFEngine.liftDirichletData(mu)
if not self.homogeneized and homogeneized:
return self.uApp - self.HFEngine.liftDirichletData(mu)
return self.uApp
def getRes(self, mu:complex, homogeneized : bool = False) -> Np1D:
"""
Get residual at arbitrary parameter.
Args:
mu: Target parameter.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
Returns:
Approximant residual.
"""
return self.HFEngine.residual(self.getApp(mu, homogeneized), mu,
homogeneized = homogeneized)
def getErr(self, mu:complex, homogeneized : bool = False) -> Np1D:
"""
Get error at arbitrary parameter.
Args:
mu: Target parameter.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
Returns:
Approximant error.
"""
return self.getApp(mu, homogeneized) - self.getHF(mu, homogeneized)
@abstractmethod
def getPoles(self) -> Np1D:
"""
Obtain approximant poles.
Returns:
Numpy complex vector of poles.
"""
pass
def normHF(self, mu:complex, homogeneized : bool = False) -> float:
"""
Compute norm of HF solution at arbitrary parameter.
Args:
mu: Target parameter.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
Returns:
Target norm of HFsolution.
"""
return self.HFEngine.norm(self.getHF(mu, homogeneized))
def normRHS(self, mu:complex, homogeneized : bool = False) -> Np1D:
"""
Compute norm of linear system RHS at arbitrary parameter.
Args:
mu: Target parameter.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
Returns:
Norm of linear system RHS.
"""
return self.HFEngine.norm(self.getRHS(mu, homogeneized))
def normApp(self, mu:complex, homogeneized : bool = False) -> float:
"""
Compute norm of approximant at arbitrary parameter.
Args:
mu: Target parameter.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
Returns:
Target norm of approximant.
"""
return self.HFEngine.norm(self.getApp(mu, homogeneized))
def normRes(self, mu:complex, homogeneized : bool = False) -> float:
"""
Compute norm of approximant residual at arbitrary parameter.
Args:
mu: Target parameter.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
Returns:
Target norm of (A(mu)app(mu) - f(mu)).
"""
return self.HFEngine.norm(self.getRes(mu, homogeneized))
def normErr(self, mu:complex, homogeneized : bool = False) -> float:
"""
Compute norm of approximant error at arbitrary parameter.
Args:
mu: Target parameter.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
Returns:
Target norm of (approximant - HFsolution).
"""
return self.HFEngine.norm(self.getErr(mu, homogeneized))
def plotHF(self, mu:complex, name : str = "uHF", save : str = None,
what : strLst = 'all', saveFormat : str = "eps",
saveDPI : int = 100, homogeneized : bool = False, **figspecs):
"""
Do some nice plots of the HF solution at arbitrary parameter.
Args:
mu: Target parameter.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
uHF = self.getHF(mu, homogeneized)
self.HFEngine.plot(uHF, name = name, save = save, what = what,
saveFormat = saveFormat, saveDPI = saveDPI,
**figspecs)
def plotApp(self, mu:complex, name : str = "uApp", save : str = None,
what : strLst = 'all', saveFormat : str = "eps",
saveDPI : int = 100, homogeneized : bool = False, **figspecs):
"""
Do some nice plots of approximant at arbitrary parameter.
Args:
mu: Target parameter.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
uApp = self.getApp(mu, homogeneized)
self.HFEngine.plot(uApp, name = name, save = save, what = what,
saveFormat = saveFormat, saveDPI = saveDPI,
**figspecs)
def plotRes(self, mu:complex, name : str = "res", save : str = None,
what : strLst = 'all', saveFormat : str = "eps",
saveDPI : int = 100, homogeneized : bool = False, **figspecs):
"""
Do some nice plots of approximation residual at arbitrary parameter.
Args:
mu: Target parameter.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
uRes = self.getRes(mu, homogeneized)
self.HFEngine.plot(uRes, name = name, save = save, what = what,
saveFormat = saveFormat, saveDPI = saveDPI,
**figspecs)
def plotErr(self, mu:complex, name : str = "err", save : str = None,
what : strLst = 'all', saveFormat : str = "eps",
saveDPI : int = 100, homogeneized : bool = False, **figspecs):
"""
Do some nice plots of approximation error at arbitrary parameter.
Args:
mu: Target parameter.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
False.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
uErr = self.getErr(mu, homogeneized)
self.HFEngine.plot(uErr, name = name, save = save, what = what,
saveFormat = saveFormat, saveDPI = saveDPI,
**figspecs)

Event Timeline