diff --git a/rrompy/reduction_methods/__init__.py b/rrompy/reduction_methods/__init__.py
index f91242d..9e3d83f 100644
--- a/rrompy/reduction_methods/__init__.py
+++ b/rrompy/reduction_methods/__init__.py
@@ -1,49 +1,48 @@
# 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 .
#
-from .standard import (NearestNeighbor, RationalInterpolant,
- RationalMovingLeastSquares, RationalPade, ReducedBasis)
+from .standard import (NearestNeighbor, RationalInterpolant, RationalPade,
+ ReducedBasis)
from .standard.greedy import RationalInterpolantGreedy, ReducedBasisGreedy
from .pivoted import (RationalInterpolantPivotedNoMatch,
RationalInterpolantPivoted,
RationalInterpolantGreedyPivotedNoMatch,
RationalInterpolantGreedyPivoted)
from .pivoted.greedy import (RationalInterpolantPivotedGreedyNoMatch,
RationalInterpolantPivotedGreedy,
RationalInterpolantGreedyPivotedGreedyNoMatch,
RationalInterpolantGreedyPivotedGreedy)
__all__ = [
'NearestNeighbor',
'RationalInterpolant',
- 'RationalMovingLeastSquares',
'RationalPade',
'ReducedBasis',
'RationalInterpolantGreedy',
'ReducedBasisGreedy',
'RationalInterpolantPivotedNoMatch',
'RationalInterpolantPivoted',
'RationalInterpolantGreedyPivotedNoMatch',
'RationalInterpolantGreedyPivoted',
'RationalInterpolantPivotedGreedyNoMatch',
'RationalInterpolantPivotedGreedy',
'RationalInterpolantGreedyPivotedGreedyNoMatch',
'RationalInterpolantGreedyPivotedGreedy'
]
diff --git a/rrompy/reduction_methods/pivoted/generic_pivoted_approximant.py b/rrompy/reduction_methods/pivoted/generic_pivoted_approximant.py
index 3a539d8..c6aa142 100644
--- a/rrompy/reduction_methods/pivoted/generic_pivoted_approximant.py
+++ b/rrompy/reduction_methods/pivoted/generic_pivoted_approximant.py
@@ -1,579 +1,577 @@
# 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 .
#
import numpy as np
from copy import deepcopy as copy
from rrompy.reduction_methods.base.generic_approximant import (
GenericApproximant)
from rrompy.sampling import (SamplingEnginePivoted, SamplingEnginePivotedPOD,
SamplingEnginePivotedPODGlobal)
from rrompy.utilities.poly_fitting.polynomial import polybases as ppb
from rrompy.utilities.poly_fitting.radial_basis import polybases as rbpb
-from rrompy.utilities.poly_fitting.moving_least_squares import (
- polybases as mlspb)
from rrompy.utilities.base.types import paramList, ListAny
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.utilities.numerical.degree import reduceDegreeN
from rrompy.utilities.exception_manager import (RROMPyException, RROMPyAssert,
RROMPyWarning)
__all__ = ['GenericPivotedApproximantNoMatch', 'GenericPivotedApproximant',
'PODGlobal']
PODGlobal = 2
class GenericPivotedApproximantBase(GenericApproximant):
def __init__(self, directionPivot:ListAny, *args, **kwargs):
self._preInit()
if len(directionPivot) > 1:
raise RROMPyException(("Exactly 1 pivot parameter allowed in pole "
"matching."))
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
QSBase = QS([[0], [1]], "UNIFORM")
self._addParametersToList(["cutOffTolerance",
"radialDirectionalWeightsMarginal",
"interpRcondMarginal"], [np.inf, [1.], -1],
["samplerPivot", "SMarginal",
"samplerMarginal"], [QSBase, [1], QSBase])
del QS
self._directionPivot = directionPivot
super().__init__(*args, **kwargs)
self._postInit()
def setupSampling(self):
"""Setup sampling engine."""
RROMPyAssert(self._mode, message = "Cannot setup sampling engine.")
if not hasattr(self, "_POD") or self._POD is None: return
if self.POD:
if self.POD == PODGlobal:
SamplingEngine = SamplingEnginePivotedPODGlobal
else:
SamplingEngine = SamplingEnginePivotedPOD
else:
SamplingEngine = SamplingEnginePivoted
self.samplingEngine = SamplingEngine(self.HFEngine,
self.directionPivot,
sample_state = self.approx_state,
verbosity = self.verbosity)
def initializeModelData(self, datadict):
if "directionPivot" in datadict.keys():
from .trained_model.trained_model_pivoted_data import (
TrainedModelPivotedData)
return (TrainedModelPivotedData(datadict["mu0"],
datadict.pop("projMat"),
datadict["scaleFactor"],
datadict.pop("rescalingExp"),
datadict["directionPivot"]),
["mu0", "scaleFactor", "directionPivot", "mus"])
else:
return super().initializeModelData(datadict)
@property
def npar(self):
"""Number of parameters."""
if hasattr(self, "_temporaryPivot"): return self.nparPivot
return super().npar
@property
def mus(self):
"""Value of mus. Its assignment may reset snapshots."""
return self._mus
@mus.setter
def mus(self, mus):
musOld = copy(self.mus) if hasattr(self, '_mus') else None
if (musOld is None or len(mus) != len(musOld) or not mus == musOld):
self.resetSamples()
self._mus = mus
@property
def cutOffTolerance(self):
"""Value of cutOffTolerance."""
return self._cutOffTolerance
@cutOffTolerance.setter
def cutOffTolerance(self, cutOffTolerance):
self._cutOffTolerance = cutOffTolerance
self._approxParameters["cutOffTolerance"] = self.cutOffTolerance
@property
def SMarginal(self):
"""Value of SMarginal."""
return self._SMarginal
@SMarginal.setter
def SMarginal(self, SMarginal):
if SMarginal <= 0:
raise RROMPyException("SMarginal must be positive.")
if hasattr(self, "_SMarginal") and self._SMarginal is not None:
Sold = self.SMarginal
else: Sold = -1
self._SMarginal = SMarginal
self._approxParameters["SMarginal"] = self.SMarginal
if Sold != self.SMarginal: self.resetSamples()
@property
def radialDirectionalWeightsMarginal(self):
"""Value of radialDirectionalWeightsMarginal."""
return self._radialDirectionalWeightsMarginal
@radialDirectionalWeightsMarginal.setter
def radialDirectionalWeightsMarginal(self, radialDirWeightsMarginal):
if not hasattr(radialDirWeightsMarginal, "__len__"):
radialDirWeightsMarginal = [radialDirWeightsMarginal]
self._radialDirectionalWeightsMarginal = radialDirWeightsMarginal
self._approxParameters["radialDirectionalWeightsMarginal"] = (
self.radialDirectionalWeightsMarginal)
@property
def interpRcondMarginal(self):
"""Value of interpRcondMarginal."""
return self._interpRcondMarginal
@interpRcondMarginal.setter
def interpRcondMarginal(self, interpRcondMarginal):
self._interpRcondMarginal = interpRcondMarginal
self._approxParameters["interpRcondMarginal"] = (
self.interpRcondMarginal)
@property
def directionPivot(self):
"""Value of directionPivot. Its assignment may reset snapshots."""
return self._directionPivot
@directionPivot.setter
def directionPivot(self, directionPivot):
if hasattr(self, '_directionPivot'):
directionPivotOld = copy(self.directionPivot)
else:
directionPivotOld = None
if (directionPivotOld is None
or len(directionPivot) != len(directionPivotOld)
or not directionPivot == directionPivotOld):
self.resetSamples()
self._directionPivot = directionPivot
@property
def directionMarginal(self):
return [x for x in range(self.HFEngine.npar) \
if x not in self.directionPivot]
@property
def nparPivot(self):
return len(self.directionPivot)
@property
def nparMarginal(self):
return self.npar - self.nparPivot
@property
def rescalingExpPivot(self):
return [self.HFEngine.rescalingExp[x] for x in self.directionPivot]
@property
def rescalingExpMarginal(self):
return [self.HFEngine.rescalingExp[x] for x in self.directionMarginal]
@property
def muBounds(self):
"""Value of muBounds."""
return self.samplerPivot.lims
@property
def muBoundsMarginal(self):
"""Value of muBoundsMarginal."""
return self.samplerMarginal.lims
@property
def samplerPivot(self):
"""Value of samplerPivot."""
return self._samplerPivot
@samplerPivot.setter
def samplerPivot(self, samplerPivot):
if 'generatePoints' not in dir(samplerPivot):
raise RROMPyException("Pivot sampler type not recognized.")
if hasattr(self, '_samplerPivot') and self._samplerPivot is not None:
samplerOld = self.samplerPivot
self._samplerPivot = samplerPivot
self._approxParameters["samplerPivot"] = self.samplerPivot
if not 'samplerOld' in locals() or samplerOld != self.samplerPivot:
self.resetSamples()
@property
def samplerMarginal(self):
"""Value of samplerMarginal."""
return self._samplerMarginal
@samplerMarginal.setter
def samplerMarginal(self, samplerMarginal):
if 'generatePoints' not in dir(samplerMarginal):
raise RROMPyException("Marginal sampler type not recognized.")
if (hasattr(self, '_samplerMarginal')
and self._samplerMarginal is not None):
samplerOld = self.samplerMarginal
self._samplerMarginal = samplerMarginal
self._approxParameters["samplerMarginal"] = self.samplerMarginal
if not 'samplerOld' in locals() or samplerOld != self.samplerMarginal:
self.resetSamples()
def setSamples(self, samplingEngine):
"""Copy samplingEngine and samples."""
self.mus = copy(samplingEngine.mus[0])
for sEj in samplingEngine.mus[1:]:
self.mus.append(sEj)
super().setSamples(samplingEngine)
def computeScaleFactor(self):
"""Compute parameter rescaling factor."""
RROMPyAssert(self._mode, message = "Cannot compute rescaling factor.")
self.scaleFactorPivot = .5 * np.abs(
self.muBounds[0] ** self.rescalingExpPivot
- self.muBounds[1] ** self.rescalingExpPivot)
self.scaleFactorMarginal = .5 * np.abs(
self.muBoundsMarginal[0] ** self.rescalingExpMarginal
- self.muBoundsMarginal[1] ** self.rescalingExpMarginal)
self.scaleFactor = np.empty(self.npar)
self.scaleFactor[self.directionPivot] = self.scaleFactorPivot
self.scaleFactor[self.directionMarginal] = self.scaleFactorMarginal
def normApprox(self, mu:paramList) -> float:
_PODOld = self.POD
self._POD = self.POD == PODGlobal
result = super().normApprox(mu)
self._POD = _PODOld
return result
class GenericPivotedApproximantNoMatch(GenericPivotedApproximantBase):
"""
ROM pivoted approximant (without pole matching) computation for parametric
problems (ABSTRACT).
Args:
HFEngine: HF problem solver.
mu0(optional): Default parameter. Defaults to 0.
directionPivot(optional): Pivot components. 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;
- 'scaleFactorDer': scaling factors for derivative computation;
defaults to 'AUTO';
- 'cutOffTolerance': tolerance for ignoring parasitic poles;
defaults to np.inf;
- 'S': total number of pivot samples current approximant relies
upon;
- 'samplerPivot': pivot sample point generator;
- 'SMarginal': total number of marginal samples current approximant
relies upon;
- 'samplerMarginal': marginal sample point generator;
- 'radialDirectionalWeightsMarginal': radial basis weights for
marginal interpolant; defaults to 1;
- 'interpRcondMarginal': tolerance for marginal interpolation;
defaults to None.
Defaults to empty dict.
approx_state(optional): Whether to approximate state. Defaults to
False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
directionPivot: Pivot components.
mus: Array of snapshot parameters.
musMarginal: Array of marginal snapshot parameters.
approxParameters: Dictionary containing values for main parameters of
approximant. Recognized keys are in parameterList.
parameterListSoft: Recognized keys of soft approximant parameters:
- 'POD': whether to compute POD of snapshots;
- 'scaleFactorDer': scaling factors for derivative computation;
- 'cutOffTolerance': tolerance for ignoring parasitic poles;
- 'radialDirectionalWeightsMarginal': radial basis weights for
marginal interpolant;
- 'interpRcondMarginal': tolerance for marginal interpolation.
parameterListCritical: Recognized keys of critical approximant
parameters:
- 'S': total number of pivot samples current approximant relies
upon;
- 'samplerPivot': pivot sample point generator;
- 'SMarginal': total number of marginal samples current approximant
relies upon;
- 'samplerMarginal': marginal sample point generator.
approx_state: Whether to approximate state.
verbosity: Verbosity level.
POD: Whether to compute POD of snapshots.
scaleFactorDer: Scaling factors for derivative computation.
cutOffTolerance: Tolerance for ignoring parasitic poles.
S: Total number of pivot samples current approximant relies upon.
samplerPivot: Pivot sample point generator.
SMarginal: Total number of marginal samples current approximant relies
upon.
samplerMarginal: Marginal sample point generator.
radialDirectionalWeightsMarginal: Radial basis weights for marginal
interpolant.
interpRcondMarginal: Tolerance for marginal interpolation.
muBounds: list of bounds for pivot parameter values.
muBoundsMarginal: list of bounds for marginal parameter values.
samplingEngine: Sampling engine.
uHF: High fidelity solution(s) with parameter(s) lastSolvedHF as
sampleList.
lastSolvedHF: Parameter(s) corresponding to last computed high fidelity
solution(s) as parameterList.
uApproxReduced: Reduced approximate solution(s) with parameter(s)
lastSolvedApprox as sampleList.
lastSolvedApproxReduced: Parameter(s) corresponding to last computed
reduced approximate solution(s) as parameterList.
uApprox: Approximate solution(s) with parameter(s) lastSolvedApprox as
sampleList.
lastSolvedApprox: Parameter(s) corresponding to last computed
approximate solution(s) as parameterList.
"""
@property
def tModelType(self):
from .trained_model.trained_model_pivoted_rational_nomatch import (
TrainedModelPivotedRationalNoMatch)
return TrainedModelPivotedRationalNoMatch
def _finalizeMarginalization(self):
vbMng(self, "INIT", "Recompressing by cut off.", 10)
msg = self.trainedModel.recompressByCutOff(self.cutOffTolerance,
self.samplerPivot.normalFoci(),
self.samplerPivot.groundPotential())
vbMng(self, "DEL", "Done recompressing." + msg, 10)
self.trainedModel.setupMarginalInterp(self,
self.radialDirectionalWeightsMarginal)
self.trainedModel.data.approxParameters = copy(self.approxParameters)
class GenericPivotedApproximant(GenericPivotedApproximantBase):
"""
ROM pivoted approximant (with pole matching) computation for parametric
problems (ABSTRACT).
Args:
HFEngine: HF problem solver.
mu0(optional): Default parameter. Defaults to 0.
directionPivot(optional): Pivot components. 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;
- 'scaleFactorDer': scaling factors for derivative computation;
defaults to 'AUTO';
- 'matchingWeight': weight for pole matching optimization; defaults
to 1;
- 'cutOffTolerance': tolerance for ignoring parasitic poles;
defaults to np.inf;
- 'cutOffSharedRatio': required ratio of marginal points to share
resonance in cut off strategy; defaults to 1.;
- 'S': total number of pivot samples current approximant relies
upon;
- 'samplerPivot': pivot sample point generator;
- 'SMarginal': total number of marginal samples current approximant
relies upon;
- 'samplerMarginal': marginal sample point generator;
- 'polybasisMarginal': type of polynomial basis for marginal
interpolation; allowed values include 'MONOMIAL', 'CHEBYSHEV'
and 'LEGENDRE'; defaults to 'MONOMIAL';
- 'MMarginal': degree of marginal interpolant; defaults to 'AUTO',
i.e. maximum allowed;
- 'polydegreetypeMarginal': type of polynomial degree for marginal;
defaults to 'TOTAL';
- 'radialDirectionalWeightsMarginal': radial basis weights for
marginal interpolant; defaults to 1;
- 'interpRcondMarginal': tolerance for marginal interpolation;
defaults to None.
Defaults to empty dict.
approx_state(optional): Whether to approximate state. Defaults to
False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
directionPivot: Pivot components.
mus: Array of snapshot parameters.
musMarginal: Array of marginal snapshot parameters.
approxParameters: Dictionary containing values for main parameters of
approximant. Recognized keys are in parameterList.
parameterListSoft: Recognized keys of soft approximant parameters:
- 'POD': whether to compute POD of snapshots;
- 'scaleFactorDer': scaling factors for derivative computation;
- 'matchingWeight': weight for pole matching optimization;
- 'cutOffTolerance': tolerance for ignoring parasitic poles;
- 'cutOffSharedRatio': required ratio of marginal points to share
resonance in cut off strategy;
- 'polybasisMarginal': type of polynomial basis for marginal
interpolation;
- 'MMarginal': degree of marginal interpolant;
- 'polydegreetypeMarginal': type of polynomial degree for marginal;
- 'radialDirectionalWeightsMarginal': radial basis weights for
marginal interpolant;
- 'interpRcondMarginal': tolerance for marginal interpolation.
parameterListCritical: Recognized keys of critical approximant
parameters:
- 'S': total number of pivot samples current approximant relies
upon;
- 'samplerPivot': pivot sample point generator;
- 'SMarginal': total number of marginal samples current approximant
relies upon;
- 'samplerMarginal': marginal sample point generator.
approx_state: Whether to approximate state.
verbosity: Verbosity level.
POD: Whether to compute POD of snapshots.
scaleFactorDer: Scaling factors for derivative computation.
matchingWeight: Weight for pole matching optimization.
cutOffTolerance: Tolerance for ignoring parasitic poles.
cutOffSharedRatio: Required ratio of marginal points to share resonance
in cut off strategy.
S: Total number of pivot samples current approximant relies upon.
samplerPivot: Pivot sample point generator.
SMarginal: Total number of marginal samples current approximant relies
upon.
samplerMarginal: Marginal sample point generator.
polybasisMarginal: Type of polynomial basis for marginal interpolation.
MMarginal: Degree of marginal interpolant.
polydegreetypeMarginal: Type of polynomial degree for marginal.
radialDirectionalWeightsMarginal: Radial basis weights for marginal
interpolant.
interpRcondMarginal: Tolerance for marginal interpolation.
muBounds: list of bounds for pivot parameter values.
muBoundsMarginal: list of bounds for marginal parameter values.
samplingEngine: Sampling engine.
uHF: High fidelity solution(s) with parameter(s) lastSolvedHF as
sampleList.
lastSolvedHF: Parameter(s) corresponding to last computed high fidelity
solution(s) as parameterList.
uApproxReduced: Reduced approximate solution(s) with parameter(s)
lastSolvedApprox as sampleList.
lastSolvedApproxReduced: Parameter(s) corresponding to last computed
reduced approximate solution(s) as parameterList.
uApprox: Approximate solution(s) with parameter(s) lastSolvedApprox as
sampleList.
lastSolvedApprox: Parameter(s) corresponding to last computed
approximate solution(s) as parameterList.
"""
def __init__(self, *args, **kwargs):
self._preInit()
self._addParametersToList(["matchingWeight", "cutOffSharedRatio",
"polybasisMarginal", "MMarginal",
"polydegreetypeMarginal"],
[1., 1., "MONOMIAL", "AUTO", "TOTAL"])
super().__init__(*args, **kwargs)
self._postInit()
@property
def tModelType(self):
from .trained_model.trained_model_pivoted_rational import (
TrainedModelPivotedRational)
return TrainedModelPivotedRational
@property
def matchingWeight(self):
"""Value of matchingWeight."""
return self._matchingWeight
@matchingWeight.setter
def matchingWeight(self, matchingWeight):
self._matchingWeight = matchingWeight
self._approxParameters["matchingWeight"] = self.matchingWeight
@property
def cutOffSharedRatio(self):
"""Value of cutOffSharedRatio."""
return self._cutOffSharedRatio
@cutOffSharedRatio.setter
def cutOffSharedRatio(self, cutOffSharedRatio):
if cutOffSharedRatio > 1.:
RROMPyWarning("Cut off shared ratio too large. Clipping to 1.")
cutOffSharedRatio = 1.
elif cutOffSharedRatio < 0.:
RROMPyWarning("Cut off shared ratio too small. Clipping to 0.")
cutOffSharedRatio = 0.
self._cutOffSharedRatio = cutOffSharedRatio
self._approxParameters["cutOffSharedRatio"] = self.cutOffSharedRatio
@property
def polybasisMarginal(self):
"""Value of polybasisMarginal."""
return self._polybasisMarginal
@polybasisMarginal.setter
def polybasisMarginal(self, polybasisMarginal):
try:
polybasisMarginal = polybasisMarginal.upper().strip().replace(" ",
"")
- if polybasisMarginal not in ppb + rbpb + mlspb:
+ if polybasisMarginal not in ppb + rbpb:
raise RROMPyException(
"Prescribed marginal polybasis not recognized.")
self._polybasisMarginal = polybasisMarginal
except:
RROMPyWarning(("Prescribed marginal polybasis not recognized. "
"Overriding to 'MONOMIAL'."))
self._polybasisMarginal = "MONOMIAL"
self._approxParameters["polybasisMarginal"] = self.polybasisMarginal
@property
def MMarginal(self):
"""Value of MMarginal."""
return self._MMarginal
@MMarginal.setter
def MMarginal(self, MMarginal):
if isinstance(MMarginal, str):
MMarginal = MMarginal.strip().replace(" ","")
if "-" not in MMarginal: MMarginal = MMarginal + "-0"
self._MMarginal_isauto = True
self._MMarginal_shift = int(MMarginal.split("-")[-1])
MMarginal = 0
if MMarginal < 0:
raise RROMPyException("MMarginal must be non-negative.")
self._MMarginal = MMarginal
self._approxParameters["MMarginal"] = self.MMarginal
def _setMMarginalAuto(self):
self.MMarginal = max(0, reduceDegreeN(
len(self.musMarginal), len(self.musMarginal),
self.nparMarginal, self.polydegreetypeMarginal
) - self._MMarginal_shift)
vbMng(self, "MAIN", ("Automatically setting MMarginal to "
"{}.").format(self.MMarginal), 25)
@property
def polydegreetypeMarginal(self):
"""Value of polydegreetypeMarginal."""
return self._polydegreetypeMarginal
@polydegreetypeMarginal.setter
def polydegreetypeMarginal(self, polydegreetypeM):
try:
polydegreetypeM = polydegreetypeM.upper().strip().replace(" ","")
if polydegreetypeM not in ["TOTAL", "FULL"]:
raise RROMPyException(("Prescribed polydegreetypeMarginal not "
"recognized."))
self._polydegreetypeMarginal = polydegreetypeM
except:
RROMPyWarning(("Prescribed polydegreetypeMarginal not recognized. "
"Overriding to 'TOTAL'."))
self._polydegreetypeMarginal = "TOTAL"
self._approxParameters["polydegreetypeMarginal"] = (
self.polydegreetypeMarginal)
def _finalizeMarginalization(self):
vbMng(self, "INIT", "Recompressing by cut off.", 10)
msg = self.trainedModel.recompressByCutOff(self.cutOffTolerance,
self.cutOffSharedRatio,
self.samplerPivot.normalFoci(),
self.samplerPivot.groundPotential())
vbMng(self, "DEL", "Done recompressing." + msg, 10)
interpPars = [self.verbosity >= 5,
self.polydegreetypeMarginal == "TOTAL", {}]
if self.polybasisMarginal in ppb + rbpb:
interpPars += [{"rcond": self.interpRcondMarginal}]
self.trainedModel.setupMarginalInterp(self, interpPars,
hasattr(self, "_MMarginal_isauto"),
self.radialDirectionalWeightsMarginal,
hasattr(self, "_reduceDegreeNNoWarn"))
self.trainedModel.data.approxParameters = copy(self.approxParameters)
diff --git a/rrompy/reduction_methods/pivoted/trained_model/trained_model_pivoted_rational.py b/rrompy/reduction_methods/pivoted/trained_model/trained_model_pivoted_rational.py
index ded2be9..7f877ae 100644
--- a/rrompy/reduction_methods/pivoted/trained_model/trained_model_pivoted_rational.py
+++ b/rrompy/reduction_methods/pivoted/trained_model/trained_model_pivoted_rational.py
@@ -1,282 +1,280 @@
# 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 .
#
import numpy as np
from copy import deepcopy as copy
from .trained_model_pivoted_rational_nomatch import (
TrainedModelPivotedRationalNoMatch)
from rrompy.utilities.base.types import (Np1D, Np2D, List, ListAny, paramVal,
paramList, HFEng)
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.utilities.numerical.point_matching import (pointMatching,
chordalMetricAdjusted, potential)
from rrompy.utilities.numerical.degree import reduceDegreeN
from rrompy.utilities.poly_fitting.polynomial import (polybases as ppb,
PolynomialInterpolator as PI)
-from rrompy.utilities.poly_fitting.radial_basis import (polybases as rbpb,
+from rrompy.utilities.poly_fitting.radial_basis import (
RadialBasisInterpolator as RBI)
-from rrompy.utilities.poly_fitting.moving_least_squares import (
- MovingLeastSquaresInterpolator as MLSI)
from rrompy.utilities.poly_fitting.heaviside import (heavisideUniformShape,
rational2heaviside,
HeavisideInterpolator as HI)
from rrompy.utilities.exception_manager import (RROMPyException, RROMPyAssert,
RROMPyWarning)
from rrompy.parameter import checkParameterList
__all__ = ['TrainedModelPivotedRational']
class TrainedModelPivotedRational(TrainedModelPivotedRationalNoMatch):
"""
ROM approximant evaluation for pivoted approximants based on interpolation
of rational approximants (with pole matching).
Attributes:
Data: dictionary with all that can be pickled.
"""
def centerNormalizeMarginal(self, mu : paramList = [],
mu0 : paramVal = None) -> paramList:
"""
Compute normalized parameter to be plugged into approximant.
Args:
mu: Parameter(s) 1.
mu0: Parameter(s) 2. If None, set to self.data.mu0Marginal.
Returns:
Normalized parameter.
"""
mu = checkParameterList(mu, self.data.nparMarginal)[0]
if mu0 is None: mu0 = self.data.mu0Marginal
rad = ((mu ** self.data.rescalingExpMarginal
- mu0 ** self.data.rescalingExpMarginal)
/ self.data.scaleFactorMarginal)
return rad
def setupMarginalInterp(self, approx, interpPars:ListAny,
MMAuto:bool, rDWM : Np1D = None,
noWarnReduceAuto : bool = True):
vbMng(self, "INIT", "Starting computation of marginal interpolator.",
12)
musMCN = self.centerNormalizeMarginal(self.data.musMarginal)
pbM = approx.polybasisMarginal
self.data.marginalInterp = []
for ipts, pts in enumerate(self.data.suppEffPts):
if len(pts) > 0:
musMCNEff = musMCN[pts]
if MMAuto:
if ipts > 0:
verb = approx.verbosity
approx.verbosity = 0
_musM = approx.musMarginal
approx.musMarginal = musMCNEff
approx._setMMarginalAuto()
if ipts > 0:
approx.musMarginal = _musM
approx.verbosity = verb
if ipts == 0: _MMarginalEffective = approx.MMarginal
if not MMAuto:
approx.MMarginal = _MMarginalEffective
MM = reduceDegreeN(approx.MMarginal, len(musMCNEff),
self.data.nparMarginal,
approx.polydegreetypeMarginal)
if MM < approx.MMarginal:
if ipts == 0 and not noWarnReduceAuto:
RROMPyWarning(("MMarginal too large compared to "
"SMarginal. Reducing MMarginal by "
"{}").format(approx.MMarginal - MM))
approx.MMarginal = MM
MMEff = approx.MMarginal
while MMEff >= 0:
pParRest = copy(interpPars)
if pbM in ppb:
p = PI()
else:
pParRest = [rDWM] + pParRest
- p = RBI() if pbM in rbpb else MLSI()
+ p = RBI()
wellCond, msg = p.setupByInterpolation(musMCNEff,
np.eye(len(musMCNEff)),
MMEff, pbM, *pParRest)
vbMng(self, "MAIN", msg, 30)
if wellCond: break
vbMng(self, "MAIN",
("Polyfit is poorly conditioned. Reducing "
"MMarginal by 1."), 35)
MMEff -= 1
if MMEff < 0:
raise RROMPyException(("Instability in computation of "
"interpolant. Aborting."))
self.data.marginalInterp += [copy(p)]
approx.MMarginal = _MMarginalEffective
vbMng(self, "DEL", "Done computing marginal interpolator.", 12)
def initializeFromLists(self, poles:ListAny, coeffs:ListAny, basis:str,
HFEngine:HFEng, matchingWeight : float = 1.,
POD : bool = True, is_state : bool = True):
"""Initialize Heaviside representation."""
musM = self.data.musMarginal
margAbsDist = np.sum(np.abs(np.repeat(musM.data, len(musM), 0)
- np.tile(musM.data, [len(musM), 1])
), axis = 1).reshape(len(musM), len(musM))
explored = [0]
unexplored = list(range(1, len(musM)))
poles, coeffs = heavisideUniformShape(poles, coeffs)
N = len(poles[0])
for _ in range(1, len(musM)):
minIdx = np.argmin(np.concatenate([margAbsDist[ex, unexplored] \
for ex in explored]))
minIex = explored[minIdx // len(unexplored)]
minIunex = unexplored[minIdx % len(unexplored)]
resex = coeffs[minIex][: N]
resunex = coeffs[minIunex][: N]
if matchingWeight != 0 and not POD:
resex = self.data.projMat[:, : resex.shape[1]].dot(resex.T)
resunex = self.data.projMat[:, : resunex.shape[1]].dot(
resunex.T)
dist = chordalMetricAdjusted(poles[minIex], poles[minIunex],
matchingWeight, resex, resunex,
HFEngine, is_state)
reordering = pointMatching(dist)[1]
poles[minIunex] = poles[minIunex][reordering]
coeffs[minIunex][: N] = coeffs[minIunex][reordering]
explored += [minIunex]
unexplored.remove(minIunex)
super().initializeFromLists(poles, coeffs, basis)
self.data.suppEffPts = [np.arange(len(self.data.HIs))]
self.data.suppEffIdx = np.zeros(N, dtype = int)
def initializeFromRational(self, HFEngine:HFEng,
matchingWeight : float = 1., POD : bool = True,
is_state : bool = True):
"""Initialize Heaviside representation."""
RROMPyAssert(self.data.nparPivot, 1, "Number of pivot parameters")
poles, coeffs = [], []
for Q, P in zip(self.data.Qs, self.data.Ps):
cfs, pls, basis = rational2heaviside(P, Q)
poles += [pls]
coeffs += [cfs]
self.initializeFromLists(poles, coeffs, basis, HFEngine,
matchingWeight, POD, is_state)
def recompressByCutOff(self, tol:float, shared:float,
foci:List[np.complex], ground:float) -> str:
N = len(self.data.HIs[0].poles)
M = len(self.data.HIs)
mu0 = np.mean(foci)
goodLocPoles = np.array([potential(hi.poles, foci) - ground
<= tol * ground for hi in self.data.HIs])
self.data.suppEffPts = [np.arange(len(self.data.HIs))]
self.data.suppEffIdx = np.zeros(N, dtype = int)
if np.all(np.all(goodLocPoles)): return " No poles erased."
goodGlobPoles = np.sum(goodLocPoles, axis = 0)
goodEnoughPoles = goodGlobPoles >= max(1., 1. * shared * M)
keepPole = np.where(goodEnoughPoles)[0]
halfPole = np.where(np.logical_and(goodEnoughPoles,
goodGlobPoles < M))[0]
removePole = np.where(np.logical_not(goodEnoughPoles))[0]
if len(removePole) > 0:
keepCoeff = np.append(keepPole, np.append([N],
np.arange(N + 1, len(self.data.HIs[0].coeffs))))
for hi in self.data.HIs:
polyCorrection = np.zeros_like(hi.coeffs[0, :])
for j in removePole:
if not np.isinf(hi.poles[j]):
polyCorrection += hi.coeffs[j, :] / (mu0 - hi.poles[j])
if len(hi.coeffs) == N:
hi.coeffs = np.vstack((hi.coeffs, polyCorrection))
else:
hi.coeffs[N, :] += polyCorrection
hi.poles = hi.poles[keepPole]
hi.coeffs = hi.coeffs[keepCoeff, :]
for idxR in halfPole:
pts = np.where(goodLocPoles[:, idxR])[0]
idxEff = len(self.data.suppEffPts)
for idEff, prevPts in enumerate(self.data.suppEffPts):
if len(prevPts) == len(pts):
if np.allclose(prevPts, pts):
idxEff = idEff
break
if idxEff == len(self.data.suppEffPts):
self.data.suppEffPts += [pts]
self.data.suppEffIdx[idxR] = idxEff
self.data.suppEffIdx = self.data.suppEffIdx[keepPole]
return (" Hard-erased {} pole".format(len(removePole))
+ "s" * (len(removePole) != 1)
+ " and soft-erased {} pole".format(len(halfPole))
+ "s" * (len(halfPole) != 1) + ".")
def _interpolateMarginal(self, mu:paramList, objs:ListAny,
mIvals : List[Np2D] = None) -> Np2D:
res = np.zeros(objs[0].shape + (len(mu),), dtype = objs[0].dtype)
if mIvals is None: muC = self.centerNormalizeMarginal(mu)
for suppIdx, suppEffPt in enumerate(self.data.suppEffPts):
i = np.where(self.data.suppEffIdx == suppIdx)[0]
if suppIdx == 0:
i = np.append(i, np.arange(len(self.data.suppEffIdx),
len(res)))
if len(i) > 0:
if mIvals is None:
mIval = self.data.marginalInterp[suppIdx](muC)
else:
mIval = mIvals[suppIdx]
for ij, j in enumerate(suppEffPt):
res[i] += np.expand_dims(objs[j][i], - 1) * mIval[ij]
return res
def interpolateMarginalInterpolator(self, mu : paramList = []):
"""Obtain interpolated approximant interpolator."""
mu = checkParameterList(mu, self.data.nparMarginal)[0]
muC = self.centerNormalizeMarginal(mu)
mIvals = [None] * len(self.data.suppEffPts)
for suppIdx in range(len(self.data.suppEffPts)):
mIvals[suppIdx] = self.data.marginalInterp[suppIdx](muC)
poless = self.interpolateMarginalPoles(mu, mIvals)
coeffss = self.interpolateMarginalCoeffs(mu, mIvals)
his = [None] * len(mu)
for j in range(len(mu)):
his[j] = HI()
his[j].poles = poless[..., j]
his[j].coeffs = coeffss[..., j]
his[j].npar = 1
his[j].polybasis = self.data.HIs[0].polybasis
return his
def interpolateMarginalPoles(self, mu : paramList = [],
mIvals : Np2D = None) -> Np1D:
"""Obtain interpolated approximant poles."""
mu = checkParameterList(mu, self.data.nparMarginal)[0]
vbMng(self, "INIT",
"Interpolating marginal poles at mu = {}.".format(mu), 95)
intMPoles = self._interpolateMarginal(mu,
[hi.poles for hi in self.data.HIs],
mIvals)
vbMng(self, "DEL", "Done interpolating marginal poles.", 95)
return intMPoles
def interpolateMarginalCoeffs(self, mu : paramList = [],
mIvals : Np2D = None) -> Np1D:
"""Obtain interpolated approximant coefficients."""
mu = checkParameterList(mu, self.data.nparMarginal)[0]
vbMng(self, "INIT",
"Interpolating marginal coefficients at mu = {}.".format(mu), 95)
intMCoeffs = self._interpolateMarginal(mu,
[hi.coeffs for hi in self.data.HIs],
mIvals)
vbMng(self, "DEL", "Done interpolating marginal coefficients.", 95)
return intMCoeffs
diff --git a/rrompy/reduction_methods/standard/__init__.py b/rrompy/reduction_methods/standard/__init__.py
index 5155dab..eb87cda 100644
--- a/rrompy/reduction_methods/standard/__init__.py
+++ b/rrompy/reduction_methods/standard/__init__.py
@@ -1,33 +1,31 @@
# 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 .
#
from .nearest_neighbor import NearestNeighbor
from .rational_interpolant import RationalInterpolant
-from .rational_moving_least_squares import RationalMovingLeastSquares
from .rational_pade import RationalPade
from .reduced_basis import ReducedBasis
__all__ = [
'NearestNeighbor',
'RationalInterpolant',
- 'RationalMovingLeastSquares',
'RationalPade',
'ReducedBasis'
]
diff --git a/rrompy/reduction_methods/standard/rational_interpolant.py b/rrompy/reduction_methods/standard/rational_interpolant.py
index 9969d38..c7d73da 100644
--- a/rrompy/reduction_methods/standard/rational_interpolant.py
+++ b/rrompy/reduction_methods/standard/rational_interpolant.py
@@ -1,677 +1,674 @@
# 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 .
#
from copy import deepcopy as copy
import numpy as np
from rrompy.reduction_methods.base import checkRobustTolerance
from .generic_standard_approximant import GenericStandardApproximant
from rrompy.utilities.poly_fitting.polynomial import (
polybases as ppb, polyfitname,
polyvander as pvP, polyvanderTotal as pvTP,
polyTimes, polyTimesTable, vanderInvTable,
PolynomialInterpolator as PI)
from rrompy.utilities.poly_fitting.heaviside import rational2heaviside
from rrompy.utilities.poly_fitting.radial_basis import (polybases as rbpb,
RadialBasisInterpolator as RBI)
-from rrompy.utilities.poly_fitting.moving_least_squares import (
- polybases as mlspb,
- MovingLeastSquaresInterpolator as MLSI)
from rrompy.utilities.base.types import Np1D, Np2D, Tuple, List, sampList
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.utilities.numerical import customPInv, dot, potential
from rrompy.utilities.numerical.hash_derivative import nextDerivativeIndices
from rrompy.utilities.numerical.degree import (reduceDegreeN,
degreeTotalToFull, fullDegreeMaxMask,
totalDegreeMaxMask)
from rrompy.utilities.exception_manager import (RROMPyException, RROMPyAssert,
RROMPyWarning)
__all__ = ['RationalInterpolant']
class RationalInterpolant(GenericStandardApproximant):
"""
ROM rational interpolant 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;
- 'scaleFactorDer': scaling factors for derivative computation;
defaults to 'AUTO';
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator;
- 'polybasis': type of polynomial basis for interpolation; defaults
to 'MONOMIAL';
- 'M': degree of rational interpolant numerator; defaults to
'AUTO', i.e. maximum allowed;
- 'N': degree of rational interpolant denominator; defaults to
'AUTO', i.e. maximum allowed;
- 'polydegreetype': type of polynomial degree; defaults to 'TOTAL';
- 'radialDirectionalWeights': radial basis weights for interpolant
numerator; defaults to 1;
- 'interpRcond': tolerance for interpolation; defaults to None;
- 'robustTol': tolerance for robust rational denominator
management; defaults to 0;
- 'correctorForce': whether corrector should forcefully delete bad
poles; defaults to False;
- 'correctorTol': tolerance for corrector step; defaults to 0.,
i.e. no bad poles;
- 'correctorMaxIter': maximum number of corrector iterations;
defaults to 1.
Defaults to empty dict.
approx_state(optional): Whether to approximate state. Defaults to
False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
mus: Array of snapshot parameters.
approxParameters: Dictionary containing values for main parameters of
approximant. Recognized keys are in parameterList.
parameterListSoft: Recognized keys of soft approximant parameters:
- 'POD': whether to compute POD of snapshots;
- 'scaleFactorDer': scaling factors for derivative computation;
- 'polybasis': type of polynomial basis for interpolation;
- 'M': degree of rational interpolant numerator;
- 'N': degree of rational interpolant denominator;
- 'polydegreetype': type of polynomial degree;
- 'radialDirectionalWeights': radial basis weights for interpolant
numerator;
- 'interpRcond': tolerance for interpolation via numpy.polyfit;
- 'robustTol': tolerance for robust rational denominator
management;
- 'correctorForce': whether corrector should forcefully delete bad
poles;
- 'correctorTol': tolerance for corrector step;
- 'correctorMaxIter': maximum number of corrector iterations.
parameterListCritical: Recognized keys of critical approximant
parameters:
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator.
approx_state: Whether to approximate state.
verbosity: Verbosity level.
POD: Whether to compute POD of snapshots.
scaleFactorDer: Scaling factors for derivative computation.
S: Number of solution snapshots over which current approximant is
based upon.
sampler: Sample point generator.
polybasis: type of polynomial basis for interpolation.
M: Numerator degree of approximant.
N: Denominator degree of approximant.
polydegreetype: Type of polynomial degree.
radialDirectionalWeights: Radial basis weights for interpolant
numerator.
interpRcond: Tolerance for interpolation via numpy.polyfit.
robustTol: Tolerance for robust rational denominator management.
correctorForce: Whether corrector should forcefully delete bad poles.
correctorTol: Tolerance for corrector step.
correctorMaxIter: Maximum number of corrector iterations.
muBounds: list of bounds for parameter values.
samplingEngine: Sampling engine.
uHF: High fidelity solution(s) with parameter(s) lastSolvedHF as
sampleList.
lastSolvedHF: Parameter(s) corresponding to last computed high fidelity
solution(s) as parameterList.
uApproxReduced: Reduced approximate solution(s) with parameter(s)
lastSolvedApprox as sampleList.
lastSolvedApproxReduced: Parameter(s) corresponding to last computed
reduced approximate solution(s) as parameterList.
uApprox: Approximate solution(s) with parameter(s) lastSolvedApprox as
sampleList.
lastSolvedApprox: Parameter(s) corresponding to last computed
approximate solution(s) as parameterList.
Q: Numpy 1D vector containing complex coefficients of approximant
denominator.
P: Numpy 2D vector whose columns are FE dofs of coefficients of
approximant numerator.
"""
def __init__(self, *args, **kwargs):
self._preInit()
self._addParametersToList(["polybasis", "M", "N", "polydegreetype",
"radialDirectionalWeights", "interpRcond",
"robustTol", "correctorForce",
"correctorTol", "correctorMaxIter"],
["MONOMIAL", "AUTO", "AUTO", "TOTAL", [1.],
-1, 0., False, 0., 1])
super().__init__(*args, **kwargs)
self.catchInstability = 0
self._postInit()
@property
def tModelType(self):
from .trained_model.trained_model_rational import TrainedModelRational
return TrainedModelRational
@property
def polybasis(self):
"""Value of polybasis."""
return self._polybasis
@polybasis.setter
def polybasis(self, polybasis):
try:
polybasis = polybasis.upper().strip().replace(" ","")
- if polybasis not in ppb + rbpb + mlspb:
+ if polybasis not in ppb + rbpb:
raise RROMPyException("Prescribed polybasis not recognized.")
self._polybasis = polybasis
except:
RROMPyWarning(("Prescribed polybasis not recognized. Overriding "
"to 'MONOMIAL'."))
self._polybasis = "MONOMIAL"
self._approxParameters["polybasis"] = self.polybasis
@property
def polybasis0(self):
if "_" in self.polybasis:
return self.polybasis.split("_")[0]
return self.polybasis
@property
def interpRcond(self):
"""Value of interpRcond."""
return self._interpRcond
@interpRcond.setter
def interpRcond(self, interpRcond):
self._interpRcond = interpRcond
self._approxParameters["interpRcond"] = self.interpRcond
@property
def radialDirectionalWeights(self):
"""Value of radialDirectionalWeights."""
return self._radialDirectionalWeights
@radialDirectionalWeights.setter
def radialDirectionalWeights(self, radialDirectionalWeights):
if not hasattr(radialDirectionalWeights, "__len__"):
radialDirectionalWeights = [radialDirectionalWeights]
self._radialDirectionalWeights = radialDirectionalWeights
self._approxParameters["radialDirectionalWeights"] = (
self.radialDirectionalWeights)
@property
def M(self):
"""Value of M."""
return self._M
@M.setter
def M(self, M):
if isinstance(M, str):
M = M.strip().replace(" ","")
if "-" not in M: M = M + "-0"
self._M_isauto, self._M_shift = True, int(M.split("-")[-1])
M = 0
if M < 0: raise RROMPyException("M must be non-negative.")
self._M = M
self._approxParameters["M"] = self.M
def _setMAuto(self):
self.M = max(0, reduceDegreeN(self.S, self.S, self.npar,
self.polydegreetype) - self._M_shift)
vbMng(self, "MAIN", "Automatically setting M to {}.".format(self.M),
25)
@property
def N(self):
"""Value of N."""
return self._N
@N.setter
def N(self, N):
if isinstance(N, str):
N = N.strip().replace(" ","")
if "-" not in N: N = N + "-0"
self._N_isauto, self._N_shift = True, int(N.split("-")[-1])
N = 0
if N < 0: raise RROMPyException("N must be non-negative.")
self._N = N
self._approxParameters["N"] = self.N
def _setNAuto(self):
self.N = max(0, reduceDegreeN(self.S, self.S, self.npar,
self.polydegreetype) - self._N_shift)
vbMng(self, "MAIN", "Automatically setting N to {}.".format(self.N),
25)
@property
def polydegreetype(self):
"""Value of polydegreetype."""
return self._polydegreetype
@polydegreetype.setter
def polydegreetype(self, polydegreetype):
try:
polydegreetype = polydegreetype.upper().strip().replace(" ","")
if polydegreetype not in ["TOTAL", "FULL"]:
raise RROMPyException(("Prescribed polydegreetype not "
"recognized."))
self._polydegreetype = polydegreetype
except:
RROMPyWarning(("Prescribed polydegreetype not recognized. "
"Overriding to 'TOTAL'."))
self._polydegreetype = "TOTAL"
self._approxParameters["polydegreetype"] = self.polydegreetype
@property
def robustTol(self):
"""Value of tolerance for robust rational denominator management."""
return self._robustTol
@robustTol.setter
def robustTol(self, robustTol):
if robustTol < 0.:
RROMPyWarning(("Overriding prescribed negative robustness "
"tolerance to 0."))
robustTol = 0.
self._robustTol = robustTol
self._approxParameters["robustTol"] = self.robustTol
@property
def correctorForce(self):
"""Value of correctorForce."""
return self._correctorForce
@correctorForce.setter
def correctorForce(self, correctorForce):
self._correctorForce = correctorForce
self._approxParameters["correctorForce"] = self.correctorForce
@property
def correctorTol(self):
"""Value of correctorTol."""
return self._correctorTol
@correctorTol.setter
def correctorTol(self, correctorTol):
if correctorTol < 0. or (correctorTol > 0. and self.npar > 1):
RROMPyWarning(("Overriding prescribed corrector tolerance "
"to 0."))
correctorTol = 0.
self._correctorTol = correctorTol
self._approxParameters["correctorTol"] = self.correctorTol
@property
def correctorMaxIter(self):
"""Value of correctorMaxIter."""
return self._correctorMaxIter
@correctorMaxIter.setter
def correctorMaxIter(self, correctorMaxIter):
if correctorMaxIter < 1 or (correctorMaxIter > 1 and self.npar > 1):
RROMPyWarning(("Overriding prescribed max number of corrector "
"iterations to 1."))
correctorMaxIter = 1
self._correctorMaxIter = correctorMaxIter
self._approxParameters["correctorMaxIter"] = self.correctorMaxIter
def resetSamples(self):
"""Reset samples."""
super().resetSamples()
self._musUniqueCN = None
self._derIdxs = None
self._reorder = None
def _setupInterpolationIndices(self):
"""Setup parameters for polyvander."""
if self._musUniqueCN is None or len(self._reorder) != len(self.mus):
self._musUniqueCN, musIdxsTo, musIdxs, musCount = (
self.trainedModel.centerNormalize(self.mus).unique(
return_index = True, return_inverse = True,
return_counts = True))
self._musUnique = self.mus[musIdxsTo]
self._derIdxs = [None] * len(self._musUniqueCN)
self._reorder = np.empty(len(musIdxs), dtype = int)
filled = 0
for j, cnt in enumerate(musCount):
self._derIdxs[j] = nextDerivativeIndices([], self.mus.shape[1],
cnt)
jIdx = np.nonzero(musIdxs == j)[0]
self._reorder[jIdx] = np.arange(filled, filled + cnt)
filled += cnt
def _setupDenominator(self):
"""Compute rational denominator."""
RROMPyAssert(self._mode, message = "Cannot setup denominator.")
vbMng(self, "INIT", "Starting computation of denominator.", 7)
if hasattr(self, "_N_isauto"):
self._setNAuto()
else:
N = reduceDegreeN(self.N, self.S, self.npar, self.polydegreetype)
if N < self.N:
RROMPyWarning(("N too large compared to S. Reducing N by "
"{}").format(self.N - N))
self.N = N
while self.N > 0:
invD, fitinv = self._computeInterpolantInverseBlocks()
idxSamplesEff = list(range(self.S))
if self.POD:
ev, eV = self.findeveVGQR(
self.samplingEngine.RPOD[:, idxSamplesEff], invD)
else:
ev, eV = self.findeveVGExplicit(
self.samplingEngine.samples(idxSamplesEff), invD)
nevBad = checkRobustTolerance(ev, self.robustTol)
if nevBad <= 1: break
if self.catchInstability > 0:
raise RROMPyException(("Instability in denominator "
"computation: eigenproblem is poorly "
"conditioned."),
self.catchInstability == 1)
vbMng(self, "MAIN", ("Smallest {} eigenvalues below tolerance. "
"Reducing N by 1.").format(nevBad), 10)
self.N = self.N - 1
if self.N <= 0:
self.N = 0
eV = np.ones((1, 1))
q = PI()
q.npar = self.npar
q.polybasis = self.polybasis0
if self.polydegreetype == "TOTAL":
q.coeffs = degreeTotalToFull(tuple([self.N + 1] * self.npar),
self.npar, eV[:, 0])
else:
q.coeffs = eV[:, 0].reshape([self.N + 1] * self.npar)
vbMng(self, "DEL", "Done computing denominator.", 7)
return q, fitinv
def _setupNumerator(self):
"""Compute rational numerator."""
RROMPyAssert(self._mode, message = "Cannot setup numerator.")
vbMng(self, "INIT", "Starting computation of numerator.", 7)
self._setupInterpolationIndices()
Qevaldiag = polyTimesTable(self.trainedModel.data.Q, self._musUniqueCN,
self._reorder, self._derIdxs,
self.scaleFactorRel)
if self.POD:
Qevaldiag = Qevaldiag.dot(self.samplingEngine.RPOD.T)
if hasattr(self, "_M_isauto"):
self._setMAuto()
M = self.M
else:
M = reduceDegreeN(self.M, self.S, self.npar, self.polydegreetype)
if M < self.M:
RROMPyWarning(("M too large compared to S. Reducing M by "
"{}").format(self.M - M))
self.M = M
while self.M >= 0:
pParRest = [self.verbosity >= 5, self.polydegreetype == "TOTAL",
{"derIdxs": self._derIdxs, "reorder": self._reorder,
"scl": self.scaleFactorRel}]
if self.polybasis in ppb:
p = PI()
else:
pParRest = [self.radialDirectionalWeights] + pParRest
- p = RBI() if self.polybasis in rbpb else MLSI()
+ p = RBI()
if self.polybasis in ppb + rbpb:
pParRest += [{"rcond": self.interpRcond}]
wellCond, msg = p.setupByInterpolation(self._musUniqueCN,
Qevaldiag, self.M,
self.polybasis, *pParRest)
vbMng(self, "MAIN", msg, 5)
if wellCond: break
if self.catchInstability > 0:
raise RROMPyException(("Instability in numerator computation: "
"polyfit is poorly conditioned."),
self.catchInstability == 1)
vbMng(self, "MAIN", ("Polyfit is poorly conditioned. Reducing M "
"by 1."), 10)
self.M = self.M - 1
if self.M < 0:
raise RROMPyException(("Instability in computation of numerator. "
"Aborting."))
self.M = M
vbMng(self, "DEL", "Done computing numerator.", 7)
return p
def setupApprox(self) -> int:
"""Compute rational interpolant."""
if self.checkComputedApprox(): return -1
RROMPyAssert(self._mode, message = "Cannot setup approximant.")
vbMng(self, "INIT", "Setting up {}.". format(self.name()), 5)
self.computeSnapshots()
pMat = self.samplingEngine.samples.data
pMatEff = dot(self.HFEngine.C, pMat) if self.approx_state else pMat
if self.trainedModel is None:
self.trainedModel = self.tModelType()
self.trainedModel.verbosity = self.verbosity
self.trainedModel.timestamp = self.timestamp
datadict = {"mu0": self.mu0, "projMat": pMatEff,
"scaleFactor": self.scaleFactor,
"rescalingExp": self.HFEngine.rescalingExp}
self.trainedModel.data = self.initializeModelData(datadict)[0]
else:
self.trainedModel = self.trainedModel
self.trainedModel.data.projMat = copy(pMatEff)
self.trainedModel.data.mus = copy(self.mus)
self._iterCorrector()
self.trainedModel.data.approxParameters = copy(self.approxParameters)
vbMng(self, "DEL", "Done setting up approximant.", 5)
return 0
def _iterCorrector(self):
if self.correctorTol > 0. and (self.correctorMaxIter > 1
or self.correctorForce):
vbMng(self, "INIT", "Starting correction iterations.", 5)
self._Qhat = PI()
self._Qhat.npar = self.npar
self._Qhat.polybasis = "MONOMIAL"
self._Qhat.coeffs = np.ones(1, dtype = np.complex)
if self.POD:
self._RPODOld = copy(self.samplingEngine.RPOD)
else:
self._samplesOld = copy(self.samplingEngine.samples)
else: vbMng(self, "INIT", "Starting approximant finalization.", 5)
for j in range(self.correctorMaxIter):
if self.N > 0 or (hasattr(self, "_N_isauto")
and self.S > self.npar):
Q = self._setupDenominator()[0]
else:
Q = PI()
Q.coeffs = np.ones((1,) * self.npar, dtype = np.complex)
Q.npar = self.npar
Q.polybasis = self.polybasis
self.N = 0
if j == 0: _N0 = self.N
self.trainedModel.data.Q = Q
self.trainedModel.data.P = self._setupNumerator()
self._applyCorrector(j)
if self.N <= 0: break
self.N = _N0
if self.correctorTol <= 0. or (self.correctorMaxIter <= 1
and not self.correctorForce):
vbMng(self, "DEL", "Terminated approximant finalization.", 5)
return
if self.POD:
self.samplingEngine.RPOD = self._RPODOld
del self._RPODOld
else:
self.samplingEngine.samples = self._samplesOld
del self._samplesOld
if self.correctorForce:
QOld, QOldBasis = [1.], "MONOMIAL"
else:
QOld, QOldBasis = Q.coeffs, self.polybasis
Q = polyTimes(self._Qhat.coeffs, QOld, Pbasis = self._Qhat.polybasis,
Qbasis = QOldBasis, Rbasis = self.polybasis)
del self._Qhat
gamma = np.linalg.norm(Q)
self.trainedModel.data.Q.coeffs = np.pad(Q, (0, self.N - len(Q) + 1),
"constant") / gamma
if self.correctorForce:
self.trainedModel.data.P = self._setupNumerator()
else:
self.trainedModel.data.P.coeffs /= gamma
vbMng(self, "DEL", "Terminated correction iterations.", 5)
def _applyCorrector(self, j:int):
if self.correctorTol <= 0. or (j >= self.correctorMaxIter - 1
and not self.correctorForce):
self.N = 0
return
cfs, pls, _ = rational2heaviside(self.trainedModel.data.P,
self.trainedModel.data.Q)
cfs = cfs[: self.N]
if self.POD:
resEff = np.linalg.norm(cfs, axis = 1)
else:
resEff = self.HFEngine.norm(self.samplingEngine.samples.dot(cfs.T),
is_state = self.approx_state)
goodPole = np.logical_not(np.isinf(pls))
potentialGood = (potential(pls[goodPole], self.sampler.normalFoci())
/ self.sampler.groundPotential())
potentialGood[potentialGood < 1.] = 1.
resEff[goodPole] /= potentialGood
resEff /= np.max(resEff)
idxKeep = np.where(resEff >= self.correctorTol)[0]
vbMng(self, "MAIN",
("Correction iteration no. {}: {} out of {} residuals satisfy "
"tolerance.").format(j + 1, len(idxKeep), self.N), 10)
self.N -= len(idxKeep)
if self.N <= 0 and not self.correctorForce: return
for i in idxKeep:
self._Qhat.coeffs = polyTimes(self._Qhat.coeffs, [- pls[i], 1.],
Pbasis = self._Qhat.polybasis,
Rbasis = self._Qhat.polybasis)
self._Qhat.coeffs /= np.linalg.norm(self._Qhat.coeffs)
if self.N <= 0: return
vbMng(self, "MAIN",
("Removing poles at (normalized positions): "
"{}.").format(pls[resEff < self.correctorTol]), 65)
That = polyTimesTable(self._Qhat, self._musUniqueCN,
self._reorder, self._derIdxs,
self.scaleFactorRel).T
if self.POD:
self.samplingEngine.RPOD = self._RPODOld.dot(That)
else:
self.samplingEngine.samples = self._samplesOld.dot(That)
def _computeInterpolantInverseBlocks(self) -> Tuple[List[Np2D], Np2D]:
"""
Compute inverse factors for minimal interpolant target functional.
"""
RROMPyAssert(self._mode, message = "Cannot solve eigenvalue problem.")
self._setupInterpolationIndices()
TEGen = pvTP if self.polydegreetype == "TOTAL" else pvP
TEGenPar = [self.polybasis0, self._derIdxs, self._reorder,
self.scaleFactorRel]
if hasattr(self, "_M_isauto"): self._setMAuto()
E = max(self.M, self.N)
while E >= 0:
if self.polydegreetype == "TOTAL":
Eeff = E
idxsB = totalDegreeMaxMask(E, self.npar)
else: #if self.polydegreetype == "FULL":
Eeff = [E] * self.npar
idxsB = fullDegreeMaxMask(E, self.npar)
TE = TEGen(self._musUniqueCN, Eeff, *TEGenPar)
fitOut = customPInv(TE, rcond = self.interpRcond, full = True)
vbMng(self, "MAIN",
("Fitting {} samples with degree {} through {}... "
"Conditioning of pseudoinverse system: {:.4e}.").format(
TE.shape[0], E,
polyfitname(self.polybasis0),
fitOut[1][1][0] / fitOut[1][1][-1]),
5)
if fitOut[1][0] == TE.shape[1]:
fitinv = fitOut[0][idxsB, :]
break
if self.catchInstability > 0:
raise RROMPyException(("Instability in denominator "
"computation: polyfit is poorly "
"conditioned."),
self.catchInstability == 1)
EeqN = E == self.N
vbMng(self, "MAIN", ("Polyfit is poorly conditioned. Reducing E {}"
"by 1.").format("and N " * EeqN), 10)
if EeqN: self.N = self.N - 1
E -= 1
if self.N < 0:
raise RROMPyException(("Instability in computation of "
"denominator. Aborting."))
invD = vanderInvTable(fitinv, idxsB, self._reorder, self._derIdxs)
if self.N == E:
TN = TE
else:
if self.polydegreetype == "TOTAL":
Neff = self.N
idxsB = totalDegreeMaxMask(self.N, self.npar)
else: #if self.polydegreetype == "FULL":
Neff = [self.N] * self.npar
idxsB = fullDegreeMaxMask(self.N, self.npar)
TN = TEGen(self._musUniqueCN, Neff, *TEGenPar)
for k in range(len(invD)): invD[k] = dot(invD[k], TN)
return invD, fitinv
def findeveVGExplicit(self, sampleE:sampList,
invD:List[Np2D]) -> Tuple[Np1D, Np2D]:
"""
Compute explicitly eigenvalues and eigenvectors of rational denominator
matrix.
"""
RROMPyAssert(self._mode, message = "Cannot solve eigenvalue problem.")
nEnd = invD[0].shape[1]
eWidth = len(invD)
vbMng(self, "INIT", "Building gramian matrix.", 10)
gramian = self.HFEngine.innerProduct(sampleE, sampleE,
is_state = self.approx_state)
G = np.zeros((nEnd, nEnd), dtype = np.complex)
for k in range(eWidth):
G += dot(dot(gramian, invD[k]).T, invD[k].conj()).T
vbMng(self, "DEL", "Done building gramian.", 10)
vbMng(self, "INIT", "Solving eigenvalue problem for gramian matrix.",
7)
try:
ev, eV = np.linalg.eigh(G)
except np.linalg.LinAlgError as e:
raise RROMPyException(e)
vbMng(self, "MAIN",
("Solved eigenvalue problem of size {} with condition number "
"{:.4e}.").format(nEnd, ev[-1] / ev[0]), 5)
vbMng(self, "DEL", "Done solving eigenvalue problem.", 7)
return ev, eV
def findeveVGQR(self, RPODE:Np2D, invD:List[Np2D]) -> Tuple[Np1D, Np2D]:
"""
Compute eigenvalues and eigenvectors of rational denominator matrix
through SVD of R factor.
"""
RROMPyAssert(self._mode, message = "Cannot solve eigenvalue problem.")
nEnd = invD[0].shape[1]
S = RPODE.shape[0]
eWidth = len(invD)
vbMng(self, "INIT", "Building half-gramian matrix stack.", 10)
Rstack = np.zeros((S * eWidth, nEnd), dtype = np.complex)
for k in range(eWidth):
Rstack[k * S : (k + 1) * S, :] = dot(RPODE, invD[k])
vbMng(self, "DEL", "Done building half-gramian.", 10)
vbMng(self, "INIT", "Solving svd for square root of gramian matrix.",
7)
try:
_, s, eV = np.linalg.svd(Rstack, full_matrices = False)
except np.linalg.LinAlgError as e:
raise RROMPyException(e)
ev = s[::-1]
eV = eV[::-1, :].T.conj()
vbMng(self, "MAIN",
("Solved svd problem of size {} x {} with condition number "
"{:.4e}.").format(*Rstack.shape, s[0] / s[-1]), 5)
vbMng(self, "DEL", "Done solving svd.", 7)
return ev, eV
def getResidues(self, *args, **kwargs) -> Np1D:
"""
Obtain approximant residues.
Returns:
Matrix with residues as columns.
"""
return self.trainedModel.getResidues(*args, **kwargs)
diff --git a/rrompy/reduction_methods/standard/rational_moving_least_squares.py b/rrompy/reduction_methods/standard/rational_moving_least_squares.py
deleted file mode 100644
index fecdbec..0000000
--- a/rrompy/reduction_methods/standard/rational_moving_least_squares.py
+++ /dev/null
@@ -1,312 +0,0 @@
-# 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 .
-#
-
-from copy import deepcopy as copy
-import numpy as np
-from .rational_interpolant import RationalInterpolant
-from rrompy.utilities.poly_fitting.polynomial import (polybases as ppb,
- polyvander as pvP,
- polyvanderTotal as pvTP)
-from rrompy.utilities.base.types import Np2D
-from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.numerical import dot
-from rrompy.utilities.numerical.degree import (fullDegreeMaxMask,
- totalDegreeMaxMask)
-from rrompy.utilities.exception_manager import (RROMPyException, RROMPyAssert,
- RROMPyWarning)
-
-__all__ = ['RationalMovingLeastSquares']
-
-class RationalMovingLeastSquares(RationalInterpolant):
- """
- ROM rational moving LS interpolant 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;
- - 'scaleFactorDer': scaling factors for derivative computation;
- defaults to 'AUTO';
- - 'S': total number of samples current approximant relies upon;
- - 'sampler': sample point generator;
- - 'polybasis': type of polynomial basis for interpolation; defaults
- to 'MONOMIAL';
- - 'M': degree of rational interpolant numerator; defaults to
- 'AUTO', i.e. maximum allowed;
- - 'N': degree of rational interpolant denominator; defaults to
- 'AUTO', i.e. maximum allowed;
- - 'polydegreetype': type of polynomial degree; defaults to 'TOTAL';
- - 'radialBasis': numerator radial basis type; defaults to
- 'GAUSSIAN';
- - 'radialDirectionalWeights': radial basis weights for interpolant
- numerator; defaults to 1;
- - 'radialBasisDen': denominator radial basis type; defaults to
- 'GAUSSIAN';
- - 'radialDirectionalWeightsDen': radial basis weights for
- interpolant denominator; defaults to 1;
- - 'interpRcond': tolerance for interpolation; defaults to None;
- - 'robustTol': tolerance for robust rational denominator
- management; defaults to 0.
- Defaults to empty dict.
- approx_state(optional): Whether to approximate state. Defaults to
- False.
- verbosity(optional): Verbosity level. Defaults to 10.
-
- Attributes:
- HFEngine: HF problem solver.
- mu0: Default parameter.
- mus: Array of snapshot parameters.
- approxParameters: Dictionary containing values for main parameters of
- approximant. Recognized keys are in parameterList.
- parameterListSoft: Recognized keys of soft approximant parameters:
- - 'POD': whether to compute POD of snapshots;
- - 'scaleFactorDer': scaling factors for derivative computation;
- - 'polybasis': type of polynomial basis for interpolation;
- - 'M': degree of rational interpolant numerator;
- - 'N': degree of rational interpolant denominator;
- - 'polydegreetype': type of polynomial degree;
- - 'radialBasis': numerator radial basis type;
- - 'radialDirectionalWeights': radial basis weights for interpolant
- numerator;
- - 'radialBasisDen': denominator radial basis type;
- - 'radialDirectionalWeightsDen': radial basis weights for
- interpolant denominator;
- - 'interpRcond': tolerance for interpolation via numpy.polyfit;
- - 'robustTol': tolerance for robust rational denominator
- management.
- parameterListCritical: Recognized keys of critical approximant
- parameters:
- - 'S': total number of samples current approximant relies upon;
- - 'sampler': sample point generator.
- approx_state: Whether to approximate state.
- verbosity: Verbosity level.
- POD: Whether to compute POD of snapshots.
- scaleFactorDer: Scaling factors for derivative computation.
- S: Number of solution snapshots over which current approximant is
- based upon.
- sampler: Sample point generator.
- polybasis: type of polynomial basis for interpolation.
- M: Numerator degree of approximant.
- N: Denominator degree of approximant.
- polydegreetype: Type of polynomial degree.
- radialBasis: Numerator radial basis type.
- radialDirectionalWeights: Radial basis weights for interpolant
- numerator.
- radialBasisDen: Denominator radial basis type.
- radialDirectionalWeightsDen: Radial basis weights for interpolant
- denominator.
- interpRcond: Tolerance for interpolation via numpy.polyfit.
- robustTol: Tolerance for robust rational denominator management.
- muBounds: list of bounds for parameter values.
- samplingEngine: Sampling engine.
- uHF: High fidelity solution(s) with parameter(s) lastSolvedHF as
- sampleList.
- lastSolvedHF: Parameter(s) corresponding to last computed high fidelity
- solution(s) as parameterList.
- uApproxReduced: Reduced approximate solution(s) with parameter(s)
- lastSolvedApprox as sampleList.
- lastSolvedApproxReduced: Parameter(s) corresponding to last computed
- reduced approximate solution(s) as parameterList.
- uApprox: Approximate solution(s) with parameter(s) lastSolvedApprox as
- sampleList.
- lastSolvedApprox: Parameter(s) corresponding to last computed
- approximate solution(s) as parameterList.
- Q: Numpy 1D vector containing complex coefficients of approximant
- denominator.
- P: Numpy 2D vector whose columns are FE dofs of coefficients of
- approximant numerator.
- """
-
- def __init__(self, *args, **kwargs):
- self._preInit()
- self._addParametersToList(["radialBasis", "radialBasisDen",
- "radialDirectionalWeightsDen"],
- ["GAUSSIAN", "GAUSSIAN", 1.],
- toBeExcluded = ["correctorForce",
- "correctorTol",
- "correctorMaxIter"])
- super().__init__(*args, **kwargs)
- self.catchInstability = 0
- self._postInit()
-
- @property
- def correctorForce(self):
- """Value of correctorForce."""
- return False
- @correctorForce.setter
- def correctorForce(self, correctorForce):
- RROMPyWarning(("correctorForce is used just to simplify inheritance, "
- "and its value cannot be changed from False."))
-
- @property
- def correctorTol(self):
- """Value of correctorTol."""
- return 0.
- @correctorTol.setter
- def correctorTol(self, correctorTol):
- RROMPyWarning(("correctorTol is used just to simplify inheritance, "
- "and its value cannot be changed from 0."))
-
- @property
- def correctorMaxIter(self):
- """Value of correctorMaxIter."""
- return 1
- @correctorMaxIter.setter
- def correctorMaxIter(self, correctorMaxIter):
- RROMPyWarning(("correctorMaxIter is used just to simplify "
- "inheritance, and its value cannot be changed from 1."))
-
- @property
- def tModelType(self):
- from .trained_model.trained_model_rational_mls import (
- TrainedModelRationalMLS)
- return TrainedModelRationalMLS
-
- @property
- def polybasis(self):
- """Value of polybasis."""
- return self._polybasis
- @polybasis.setter
- def polybasis(self, polybasis):
- try:
- polybasis = polybasis.upper().strip().replace(" ","")
- if polybasis not in ppb:
- raise RROMPyException("Prescribed polybasis not recognized.")
- self._polybasis = polybasis
- except:
- RROMPyWarning(("Prescribed polybasis not recognized. Overriding "
- "to 'MONOMIAL'."))
- self._polybasis = "MONOMIAL"
- self._approxParameters["polybasis"] = self.polybasis
-
- @property
- def radialBasis(self):
- """Value of radialBasis."""
- return self._radialBasis
- @radialBasis.setter
- def radialBasis(self, radialBasis):
- self._radialBasis = radialBasis
- self._approxParameters["radialBasis"] = self.radialBasis
-
- @property
- def radialBasisDen(self):
- """Value of radialBasisDen."""
- return self._radialBasisDen
- @radialBasisDen.setter
- def radialBasisDen(self, radialBasisDen):
- self._radialBasisDen = radialBasisDen
- self._approxParameters["radialBasisDen"] = self.radialBasisDen
-
- @property
- def radialDirectionalWeightsDen(self):
- """Value of radialDirectionalWeightsDen."""
- return self._radialDirectionalWeightsDen
- @radialDirectionalWeightsDen.setter
- def radialDirectionalWeightsDen(self, radialDirectionalWeightsDen):
- self._radialDirectionalWeightsDen = radialDirectionalWeightsDen
- self._approxParameters["radialDirectionalWeightsDen"] = (
- self.radialDirectionalWeightsDen)
-
- def _setupDenominator(self) -> Np2D:
- """Compute rational denominator."""
- RROMPyAssert(self._mode, message = "Cannot setup denominator.")
- vbMng(self, "INIT",
- "Starting computation of denominator-related blocks.", 7)
- self._setupInterpolationIndices()
- pPar = [self._musUniqueCN, self.N, self.polybasis0, self._derIdxs,
- self._reorder, self.scaleFactorRel]
- if self.polydegreetype == "TOTAL":
- TN = pvTP(*pPar)
- else: #if self.polydegreetype == "FULL":
- pPar[1] = [pPar[1]] * self.npar
- TN = pvP(*pPar)
- TNTen = np.zeros((self.S, self.S, TN.shape[1]), dtype = TN.dtype)
- TNTen[np.arange(self.S), np.arange(self.S)] = TN
- if self.POD: TNTen = dot(self.samplingEngine.RPOD, TNTen)
- vbMng(self, "DEL", "Done computing denominator-related blocks.", 7)
- return TN, TNTen
-
- def _setupNumerator(self) -> Np2D:
- """Compute rational numerator."""
- RROMPyAssert(self._mode, message = "Cannot setup numerator.")
- vbMng(self, "INIT",
- "Starting computation of denominator-related blocks.", 7)
- self._setupInterpolationIndices()
- pPar = [self._musUniqueCN, self.M, self.polybasis0, self._derIdxs,
- self._reorder, self.scaleFactorRel]
- if self.polydegreetype == "TOTAL":
- TM = pvTP(*pPar)
- else: #if self.polydegreetype == "FULL":
- pPar[1] = [pPar[1]] * self.npar
- TM = pvP(*pPar)
- vbMng(self, "DEL", "Done computing denominator-related blocks.", 7)
- return TM
-
- def setupApprox(self) -> int:
- """Compute rational interpolant."""
- if self.checkComputedApprox(): return -1
- RROMPyAssert(self._mode, message = "Cannot setup approximant.")
- vbMng(self, "INIT", "Setting up {}.". format(self.name()), 5)
- self.computeSnapshots()
- pMat = self.samplingEngine.samples.data
- pMatEff = dot(self.HFEngine.C, pMat) if self.approx_state else pMat
- if self.trainedModel is None:
- self.trainedModel = self.tModelType()
- self.trainedModel.verbosity = self.verbosity
- self.trainedModel.timestamp = self.timestamp
- datadict = {"mu0": self.mu0, "projMat": pMatEff,
- "scaleFactor": self.scaleFactor,
- "rescalingExp": self.HFEngine.rescalingExp}
- data = self.initializeModelData(datadict)[0]
- data.POD = self.POD
- data.polybasis = self.polybasis
- data.polydegreetype = self.polydegreetype
- data.radialBasis = self.radialBasis
- data.radialWeights = self.radialDirectionalWeights
- data.radialBasisDen = self.radialBasisDen
- data.radialWeightsDen = self.radialDirectionalWeightsDen
- data.interpRcond = self.interpRcond
- self.trainedModel.data = data
- else:
- self.trainedModel = self.trainedModel
- self.trainedModel.data.projMat = copy(pMatEff)
- if not self.POD:
- self.trainedModel.data.gramian = self.HFEngine.innerProduct(
- self.samplingEngine.samples,
- self.samplingEngine.samples,
- is_state = self.approx_state)
- self.trainedModel.data.mus = copy(self.mus)
- self.trainedModel.data.M = self.M
- self.trainedModel.data.N = self.N
- QVan, self.trainedModel.data.QBlocks = self._setupDenominator()
- self.trainedModel.data.PVan = self._setupNumerator()
- if self.polydegreetype == "TOTAL":
- degreeMaxMask = totalDegreeMaxMask
- else: #if self.polydegreetype == "FULL":
- degreeMaxMask = fullDegreeMaxMask
- if self.N > self.M:
- self.trainedModel.data.QVan = QVan
- self.trainedModel.data.domQIdxs = degreeMaxMask(self.N, self.npar)
- else:
- self.trainedModel.data.domQIdxs = degreeMaxMask(self.M, self.npar)
- self.trainedModel.data.approxParameters = copy(self.approxParameters)
- vbMng(self, "DEL", "Done setting up approximant.", 5)
- return 0
-
diff --git a/rrompy/reduction_methods/standard/rational_pade.py b/rrompy/reduction_methods/standard/rational_pade.py
index d75461a..6b48d90 100644
--- a/rrompy/reduction_methods/standard/rational_pade.py
+++ b/rrompy/reduction_methods/standard/rational_pade.py
@@ -1,309 +1,307 @@
# 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 .
#
import numpy as np
from rrompy.reduction_methods.base import checkRobustTolerance
from .rational_interpolant import RationalInterpolant
from rrompy.utilities.poly_fitting.polynomial import (
polybases as ppb, polyfitname,
polyvander as pvP, polyvanderTotal as pvTP,
polyTimesTable, vanderInvTable,
PolynomialInterpolator as PI)
from rrompy.utilities.poly_fitting.radial_basis import (polybases as rbpb,
RadialBasisInterpolator as RBI)
-from rrompy.utilities.poly_fitting.moving_least_squares import (
- MovingLeastSquaresInterpolator as MLSI)
from rrompy.utilities.base.types import Np2D, Tuple, List
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.utilities.numerical import customPInv, dot
from rrompy.utilities.numerical.degree import (fullDegreeN, totalDegreeN,
reduceDegreeN, degreeTotalToFull,
fullDegreeMaxMask, totalDegreeMaxMask)
from rrompy.utilities.exception_manager import (RROMPyException, RROMPyAssert,
RROMPyWarning)
__all__ = ['RationalPade']
class RationalPade(RationalInterpolant):
"""
ROM rational Pade' 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;
- 'scaleFactorDer': scaling factors for derivative computation;
defaults to 'AUTO';
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator;
- 'polybasis': type of polynomial basis for interpolation; defaults
to 'MONOMIAL';
- 'M': degree of rational interpolant numerator; defaults to
'AUTO', i.e. maximum allowed;
- 'N': degree of rational interpolant denominator; defaults to
'AUTO', i.e. maximum allowed;
- 'polydegreetype': type of polynomial degree; defaults to 'TOTAL';
- 'radialDirectionalWeights': radial basis weights for interpolant
numerator; defaults to 1;
- 'interpRcond': tolerance for interpolation; defaults to None;
- 'robustTol': tolerance for robust rational denominator
management; defaults to 0;
- 'correctorForce': whether corrector should forcefully delete bad
poles; defaults to False;
- 'correctorTol': tolerance for corrector step; defaults to 0.,
i.e. no bad poles;
- 'correctorMaxIter': maximum number of corrector iterations;
defaults to 1.
Defaults to empty dict.
approx_state(optional): Whether to approximate state. Defaults to
False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
mus: Array of snapshot parameters.
approxParameters: Dictionary containing values for main parameters of
approximant. Recognized keys are in parameterList.
parameterListSoft: Recognized keys of soft approximant parameters:
- 'POD': whether to compute POD of snapshots;
- 'scaleFactorDer': scaling factors for derivative computation;
- 'polybasis': type of polynomial basis for interpolation;
- 'M': degree of rational interpolant numerator;
- 'N': degree of rational interpolant denominator;
- 'polydegreetype': type of polynomial degree;
- 'radialDirectionalWeights': radial basis weights for interpolant
numerator;
- 'interpRcond': tolerance for interpolation via numpy.polyfit;
- 'robustTol': tolerance for robust rational denominator
management;
- 'correctorForce': whether corrector should forcefully delete bad
poles;
- 'correctorTol': tolerance for corrector step;
- 'correctorMaxIter': maximum number of corrector iterations.
parameterListCritical: Recognized keys of critical approximant
parameters:
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator.
approx_state: Whether to approximate state.
verbosity: Verbosity level.
POD: Whether to compute POD of snapshots.
scaleFactorDer: Scaling factors for derivative computation.
S: Number of solution snapshots over which current approximant is
based upon.
sampler: Sample point generator.
polybasis: type of polynomial basis for interpolation.
M: Numerator degree of approximant.
N: Denominator degree of approximant.
polydegreetype: Type of polynomial degree.
radialDirectionalWeights: Radial basis weights for interpolant
numerator.
interpRcond: Tolerance for interpolation via numpy.polyfit.
robustTol: Tolerance for robust rational denominator management.
correctorForce: Whether corrector should forcefully delete bad poles.
correctorTol: Tolerance for corrector step.
correctorMaxIter: Maximum number of corrector iterations.
muBounds: list of bounds for parameter values.
samplingEngine: Sampling engine.
uHF: High fidelity solution(s) with parameter(s) lastSolvedHF as
sampleList.
lastSolvedHF: Parameter(s) corresponding to last computed high fidelity
solution(s) as parameterList.
uApproxReduced: Reduced approximate solution(s) with parameter(s)
lastSolvedApprox as sampleList.
lastSolvedApproxReduced: Parameter(s) corresponding to last computed
reduced approximate solution(s) as parameterList.
uApprox: Approximate solution(s) with parameter(s) lastSolvedApprox as
sampleList.
lastSolvedApprox: Parameter(s) corresponding to last computed
approximate solution(s) as parameterList.
Q: Numpy 1D vector containing complex coefficients of approximant
denominator.
P: Numpy 2D vector whose columns are FE dofs of coefficients of
approximant numerator.
"""
def _setupInterpolationIndices(self):
"""Setup parameters for polyvander."""
super()._setupInterpolationIndices()
if len(self._musUniqueCN) > 1:
raise RROMPyException(("Cannot apply centered-like method with "
"more than one distinct sample point."))
def _setupDenominator(self):
"""Compute rational denominator."""
RROMPyAssert(self._mode, message = "Cannot setup denominator.")
vbMng(self, "INIT", "Starting computation of denominator.", 7)
cfun = totalDegreeN if self.polydegreetype == "TOTAL" else fullDegreeN
if hasattr(self, "_N_isauto"):
self._setNAuto()
else:
N = reduceDegreeN(self.N, self.S, self.npar, self.polydegreetype)
if N < self.N:
RROMPyWarning(("N too large compared to S. Reducing N by "
"{}").format(self.N - N))
self.N = N
while self.N > 0:
invD, fitinv = self._computeInterpolantInverseBlocks()
Seff = cfun(self.N, self.npar)
idxSamplesEff = list(range(self.S - Seff, self.S))
if self.POD:
ev, eV = self.findeveVGQR(
self.samplingEngine.RPOD[:, idxSamplesEff], invD)
else:
ev, eV = self.findeveVGExplicit(
self.samplingEngine.samples(idxSamplesEff), invD)
nevBad = checkRobustTolerance(ev, self.robustTol)
if nevBad <= 1: break
if self.catchInstability > 0:
raise RROMPyException(("Instability in denominator "
"computation: eigenproblem is poorly "
"conditioned."),
self.catchInstability == 1)
RROMPyWarning(("Smallest {} eigenvalues below tolerance. Reducing "
"N by 1.").format(nevBad))
self.N = self.N - 1
if self.N <= 0:
self.N = 0
eV = np.ones((1, 1))
q = PI()
q.npar = self.npar
q.polybasis = self.polybasis0
if self.polydegreetype == "TOTAL":
q.coeffs = degreeTotalToFull(tuple([self.N + 1] * self.npar),
self.npar, eV[:, 0])
else:
q.coeffs = eV[:, 0].reshape([self.N + 1] * self.npar)
vbMng(self, "DEL", "Done computing denominator.", 7)
return q, fitinv
def _setupNumerator(self):
"""Compute rational numerator."""
RROMPyAssert(self._mode, message = "Cannot setup numerator.")
vbMng(self, "INIT", "Starting computation of numerator.", 7)
self._setupInterpolationIndices()
Qevaldiag = polyTimesTable(self.trainedModel.data.Q, self._musUniqueCN,
self._reorder, self._derIdxs,
self.scaleFactorRel)
if self.POD:
Qevaldiag = Qevaldiag.dot(self.samplingEngine.RPOD.T)
cfun = totalDegreeN if self.polydegreetype == "TOTAL" else fullDegreeN
if hasattr(self, "_M_isauto"):
self._setMAuto()
M = self.M
else:
M = reduceDegreeN(self.M, self.S, self.npar, self.polydegreetype)
if M < self.M:
RROMPyWarning(("M too large compared to S. Reducing M by "
"{}").format(self.M - M))
self.M = M
while self.M >= 0:
Seff = cfun(self.M, self.npar)
pParRest = [self.verbosity >= 5, self.polydegreetype == "TOTAL",
{"derIdxs": [self._derIdxs[0][: Seff]],
"reorder": self._reorder[: Seff],
"scl": self.scaleFactorRel}]
if self.polybasis in ppb:
p = PI()
else:
pParRest = [self.radialDirectionalWeights] + pParRest
- p = RBI() if self.polybasis in rbpb else MLSI()
+ p = RBI()
if self.polybasis in ppb + rbpb:
pParRest += [{"rcond": self.interpRcond}]
wellCond, msg = p.setupByInterpolation(self._musUniqueCN,
Qevaldiag[: Seff, : Seff],
self.M, self.polybasis,
*pParRest)
vbMng(self, "MAIN", msg, 5)
if wellCond: break
if self.catchInstability > 0:
raise RROMPyException(("Instability in numerator computation: "
"polyfit is poorly conditioned."),
self.catchInstability == 1)
vbMng(self, "MAIN", ("Polyfit is poorly conditioned. Reducing M "
"by 1."), 10)
self.M = self.M - 1
if self.M < 0:
raise RROMPyException(("Instability in computation of numerator. "
"Aborting."))
self.M = M
vbMng(self, "DEL", "Done computing numerator.", 7)
return p
def _computeInterpolantInverseBlocks(self) -> Tuple[List[Np2D], Np2D]:
"""
Compute inverse factors for minimal interpolant target functional.
"""
RROMPyAssert(self._mode, message = "Cannot solve eigenvalue problem.")
self._setupInterpolationIndices()
if self.polydegreetype == "TOTAL":
cfun, TEGen = totalDegreeN, pvTP
else:
cfun, TEGen = fullDegreeN, pvP
E = max(self.M, self.N)
while E >= 0:
Seff = cfun(E, self.npar)
TEGenPar = [self.polybasis0, [self._derIdxs[0][: Seff]],
self._reorder[: Seff], self.scaleFactorRel]
if self.polydegreetype == "TOTAL":
Eeff = E
idxsB = totalDegreeMaxMask(E, self.npar)
else: #if self.polydegreetype == "FULL":
Eeff = [E] * self.npar
idxsB = fullDegreeMaxMask(E, self.npar)
TE = TEGen(self._musUniqueCN, Eeff, *TEGenPar)
fitOut = customPInv(TE, rcond = self.interpRcond, full = True)
vbMng(self, "MAIN",
("Fitting {} samples with degree {} through {}... "
"Conditioning of pseudoinverse system: {:.4e}.").format(
TE.shape[0], E,
polyfitname(self.polybasis0),
fitOut[1][1][0] / fitOut[1][1][-1]),
5)
if fitOut[1][0] == TE.shape[1]:
fitinv = fitOut[0][idxsB, :]
break
if self.catchInstability > 0:
raise RROMPyException(("Instability in denominator "
"computation: polyfit is poorly "
"conditioned."),
self.catchInstability == 1)
EeqN = E == self.N
vbMng(self, "MAIN", ("Polyfit is poorly conditioned. Reducing E {}"
"by 1.").format("and N " * EeqN), 10)
if EeqN: self.N = self.N - 1
E -= 1
if self.N < 0:
raise RROMPyException(("Instability in computation of "
"denominator. Aborting."))
invD = vanderInvTable(fitinv, idxsB, self._reorder[: Seff],
[self._derIdxs[0][: Seff]])
if self.N == E:
TN = TE
else:
if self.polydegreetype == "TOTAL":
Neff = self.N
idxsB = totalDegreeMaxMask(self.N, self.npar)
else: #if self.polydegreetype == "FULL":
Neff = [self.N] * self.npar
idxsB = fullDegreeMaxMask(self.N, self.npar)
TN = TEGen(self._musUniqueCN, Neff, *TEGenPar)
for k in range(len(invD)): invD[k] = dot(invD[k], TN)
return invD, fitinv
diff --git a/rrompy/reduction_methods/standard/trained_model/trained_model_rational_mls.py b/rrompy/reduction_methods/standard/trained_model/trained_model_rational_mls.py
deleted file mode 100644
index d2fcaa3..0000000
--- a/rrompy/reduction_methods/standard/trained_model/trained_model_rational_mls.py
+++ /dev/null
@@ -1,189 +0,0 @@
-# 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 .
-#
-
-import numpy as np
-from .trained_model_rational import TrainedModelRational
-from rrompy.utilities.base.types import Np1D, paramVal, paramList, sampList
-from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.moving_least_squares import mlsweights
-from rrompy.utilities.poly_fitting.polynomial import (
- PolynomialInterpolator as PI)
-from rrompy.utilities.numerical import customPInv
-from rrompy.utilities.numerical.degree import degreeTotalToFull
-from rrompy.parameter import checkParameterList
-from rrompy.sampling import emptySampleList
-from rrompy.utilities.exception_manager import RROMPyException, RROMPyWarning
-
-__all__ = ['TrainedModelRationalMLS']
-
-class TrainedModelRationalMLS(TrainedModelRational):
- """
- ROM approximant evaluation for rational moving least squares approximant.
-
- Attributes:
- Data: dictionary with all that can be pickled.
- """
-
- def reset(self):
- super().reset()
- self.lastSetupMu = None
-
- def assembleReducedModel(self, mu:paramVal):
- if not (hasattr(self.data, "lastSetupMu")
- and self.data.lastSetupMu == mu):
- vbMng(self, "INIT", "Assembling reduced model for mu = {}."\
- .format(mu), 17)
- vbMng(self, "INIT", "Starting computation of denominator.", 35)
- muC = self.centerNormalize(mu)
- muSC = self.centerNormalize(self.data.mus)
- wQ = mlsweights(muC, muSC, self.data.radialBasisDen,
- directionalWeights = self.data.radialWeightsDen)
- if self.data.N > self.data.M:
- PQVan = self.data.QVan
- else:
- PQVan = self.data.PVan
- VQAdjW = PQVan.conj().T * wQ
- VQAdjWVQ = VQAdjW.dot(PQVan)
- interpPseudoInverse, info = customPInv(VQAdjWVQ, full = True,
- rcond = self.data.interpRcond)
- interpPseudoInverse = interpPseudoInverse.dot(VQAdjW).dot(
- self.data.QBlocks)
- if info[0] < interpPseudoInverse.shape[-1]:
- q = np.zeros(interpPseudoInverse.shape[-1], dtype = np.complex)
- q[0] = 1.
- else:
- halfGram = interpPseudoInverse[self.data.domQIdxs]
- if self.data.POD:
- Rstack = halfGram.reshape(-1, halfGram.shape[-1])
- vbMng(self, "INIT",
- "Solving svd for square root of gramian matrix.", 67)
- try:
- _, s, eV = np.linalg.svd(Rstack, full_matrices = False)
- except np.linalg.LinAlgError as e:
- raise RROMPyException(e)
- condN = s[0] / s[-1]
- q = eV[-1, :].T.conj()
- vbMng(self, "MAIN",
- ("Solved svd problem of size {} x {} with condition "
- "number {:.4e}.").format(*Rstack.shape, condN), 55)
- vbMng(self, "DEL", "Done solving svd.", 67)
- else:
- RRstack = np.tensordot(self.trainedModel.gramian, halfGram,
- 1).reshape(-1, halfGram.shape[-1])
- RLstack = halfGram.reshape(-1, halfGram.shape[-1])
- gram = RLstack.T.conj().dot(RRstack)
- vbMng(self, "INIT",
- "Solving eigenvalue problem for gramian matrix.", 67)
- try:
- ev, eV = np.linalg.eigh(gram)
- except np.linalg.LinAlgError as e:
- raise RROMPyException(e)
- condN = ev[-1] / ev[0]
- q = eV[:, 0]
- vbMng(self, "MAIN",
- ("Solved eigenvalue problem of size {} with "
- "condition number {:.4e}.").format(gram.shape[0],
- condN), 55)
- vbMng(self, "DEL", "Done solving eigenvalue problem.", 67)
- self.data.Q = PI()
- self.data.Q.npar = self.npar
- self.data.Q.polybasis = self.data.polybasis
- if self.data.polydegreetype == "TOTAL":
- self.data.Q.coeffs = degreeTotalToFull(
- (self.data.N + 1,) * self.npar,
- self.npar, q)
- else:
- self.data.Q.coeffs = q.reshape((self.data.N + 1,) * self.npar)
- vbMng(self, "DEL", "Done computing denominator.", 35)
- vbMng(self, "INIT", "Starting computation of numerator.", 35)
- self.data.P = PI()
- self.data.P.npar = self.npar
- self.data.P.polybasis = self.data.polybasis
- wP = mlsweights(muC, muSC, self.data.radialBasis,
- directionalWeights = self.data.radialWeights)
- VAdjW = self.data.PVan.conj().T * wP
- VAdjWV = VAdjW.dot(self.data.PVan)
- interpPPseudoInverse = customPInv(VAdjWV, self.data.interpRcond)
- Pcoeffs = np.tensordot(interpPPseudoInverse.dot(VAdjW),
- self.data.QBlocks.dot(q), ([1], [1]))
- if self.data.polydegreetype == "TOTAL":
- self.data.P.coeffs = degreeTotalToFull(
- (self.data.M + 1,) * self.npar
- + (self.data.QBlocks.shape[0],),
- self.npar, Pcoeffs)
- else:
- self.data.P.coeffs = Pcoeffs.reshape(
- (self.data.M + 1,) * self.npar
- + (self.data.QBlocks.shape[0],))
- vbMng(self, "DEL", "Done computing numerator.", 35)
- vbMng(self, "DEL", "Done assembling reduced model.", 17)
- self.data.lastSetupMu = mu
-
- def getApproxReduced(self, mu : paramList = []) -> sampList:
- """
- Evaluate reduced representation of approximant at arbitrary parameter.
-
- Args:
- mu: Target parameter.
- """
- mu = checkParameterList(mu, self.data.npar)[0]
- if (not hasattr(self, "lastSolvedApproxReduced")
- or self.lastSolvedApproxReduced != mu):
- vbMng(self, "INIT",
- "Evaluating approximant at mu = {}.".format(mu), 12)
- self.uApproxReduced = emptySampleList()
- for i in range(len(mu)):
- self.assembleReducedModel(mu[i])
- vbMng(self, "INIT",
- "Solving reduced model for mu = {}.".format(mu[i]), 15)
- Qv = self.getQVal(mu[i])
- if Qv == 0.:
- RROMPyWarning(("Adjusting approximation to avoid division "
- "by numerically zero denominator."))
- Qv = np.finfo(np.complex).eps / (1. + self.data.Q.deg[0])
- uAppR = self.getPVal(mu[i]) / Qv
- if i == 0:
- self.uApproxReduced.reset((uAppR.shape[0], len(mu)),
- dtype = uAppR.dtype)
- self.uApproxReduced[i] = uAppR
- vbMng(self, "DEL", "Done solving reduced model.", 15)
- vbMng(self, "DEL", "Done evaluating approximant.", 12)
- self.lastSolvedApproxReduced = mu
- return self.uApproxReduced
-
- def getPoles(self, *args, mu : paramVal = None, **kwargs) -> Np1D:
- """
- Obtain approximant poles.
-
- Returns:
- Numpy complex vector of poles.
- """
- if mu is None: mu = self.data.mu0
- self.assembleReducedModel(mu)
- return super().getPoles(*args, **kwargs)
-
- def getResidues(self, *args, mu : paramVal = None, **kwargs) -> Np1D:
- """
- Obtain approximant residues.
-
- Returns:
- Numpy matrix with residues as columns.
- """
- if mu is None: mu = self.data.mu0
- self.assembleReducedModel(mu)
- return super().getResidues(*args, **kwargs)
diff --git a/rrompy/utilities/poly_fitting/moving_least_squares/__init__.py b/rrompy/utilities/poly_fitting/moving_least_squares/__init__.py
deleted file mode 100644
index c126e42..0000000
--- a/rrompy/utilities/poly_fitting/moving_least_squares/__init__.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# 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 .
-#
-
-from .kernel import (radialGaussian, thinPlateSpline, multiQuadric,
- localWendland)
-from .base import mlsbases, polybases, polyfitname, polydomcoeff
-from .vander import mlsweights, polyvander, polyvanderTotal
-from .moving_least_squares_interpolator import MovingLeastSquaresInterpolator
-
-__all__ = [
- 'radialGaussian',
- 'thinPlateSpline',
- 'multiQuadric',
- 'localWendland',
- 'mlsbases',
- 'polybases',
- 'polyfitname',
- 'polydomcoeff',
- 'mlsweights',
- 'polyvander',
- 'polyvanderTotal',
- 'MovingLeastSquaresInterpolator'
- ]
-
-
diff --git a/rrompy/utilities/poly_fitting/moving_least_squares/base.py b/rrompy/utilities/poly_fitting/moving_least_squares/base.py
deleted file mode 100644
index 155b780..0000000
--- a/rrompy/utilities/poly_fitting/moving_least_squares/base.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# 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 .
-#
-
-from rrompy.utilities.poly_fitting.radial_basis.base import (
- rbbases, polybases as rbpb, polyfitname, polydomcoeff)
-
-__all__ = ['mlsbases', 'polybases', 'polyfitname', 'polydomcoeff']
-
-mlsbases = [rbb + "_MLS" for rbb in rbbases]
-
-polybases = [rbp + "_MLS" for rbp in rbpb]
-
diff --git a/rrompy/utilities/poly_fitting/moving_least_squares/kernel.py b/rrompy/utilities/poly_fitting/moving_least_squares/kernel.py
deleted file mode 100644
index 207a8f1..0000000
--- a/rrompy/utilities/poly_fitting/moving_least_squares/kernel.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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 .
-#
-
-from rrompy.utilities.poly_fitting.radial_basis.kernel import (radialGaussian,
- thinPlateSpline, multiQuadric, localWendland)
-
-__all__ = ['radialGaussian', 'thinPlateSpline', 'multiQuadric',
- 'localWendland']
-
diff --git a/rrompy/utilities/poly_fitting/moving_least_squares/moving_least_squares_interpolator.py b/rrompy/utilities/poly_fitting/moving_least_squares/moving_least_squares_interpolator.py
deleted file mode 100644
index 37440d2..0000000
--- a/rrompy/utilities/poly_fitting/moving_least_squares/moving_least_squares_interpolator.py
+++ /dev/null
@@ -1,139 +0,0 @@
-# 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 .
-#
-
-import numpy as np
-from copy import deepcopy as copy
-from rrompy.utilities.base.types import (List, ListAny, DictAny, Np1D, Np2D,
- paramList)
-from rrompy.utilities.numerical import customPInv, dot
-from .vander import mlsweights
-from rrompy.utilities.poly_fitting.interpolator import GenericInterpolator
-from rrompy.utilities.poly_fitting.polynomial.vander import (polyvander as pv,
- polyvanderTotal as pvT)
-from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
-from rrompy.parameter import checkParameterList
-
-__all__ = ['MovingLeastSquaresInterpolator']
-
-class MovingLeastSquaresInterpolator(GenericInterpolator):
- def __init__(self, other = None):
- if other is None: return
- self.support = other.support
- self.localProjector = other.localProjector
- self.localVanders = other.localVanders
- self.suppValues = other.suppValues
- self.directionalWeights = other.directionalWeights
- self.degree = other.degree
- self.npar = other.npar
- self.radialbasis = other.radialbasis
- self.polybasis = other.polybasis
- self.evalParams = other.evalParams
- self.totalDegree = other.totalDegree
-
- @property
- def shape(self):
- sh = self.suppValues.shape[1 :] if self.suppValues.ndim > 1 else 1
- return sh
-
- @property
- def deg(self):
- return self.degree
-
- def __call__(self, mu:paramList, der : List[int] = None,
- scl : Np1D = None):
- if der is not None and np.sum(der) > 0:
- raise RROMPyException(("Cannot take derivatives of moving least "
- "squares function."))
- mu = checkParameterList(mu, self.npar)[0]
- sh = self.shape
- if sh == 1: sh = tuple([])
- values = np.empty((len(mu),) + sh, dtype = np.complex)
- for i, m in enumerate(mu):
- weights = mlsweights(m, self.support, self.radialbasis,
- directionalWeights = self.directionalWeights)
- weights /= np.linalg.norm(weights)
- vanderLS = np.sum(self.localVanders * weights, axis = 2)
- RHSLS = dot(self.localProjector * weights, self.suppValues)
- if self.totalDegree:
- vanderEval = pvT(m, self.deg[0], self.polybasis,
- **self.evalParams)
- else:
- vanderEval = pv(m, self.deg, self.polybasis, **self.evalParams)
- vanderEval = vanderEval.flatten()
- values[i] = dot(vanderEval, dot(customPInv(vanderLS), RHSLS))
- return values
-
- def __copy__(self):
- return MovingLeastSquaresInterpolator(self)
-
- def __deepcopy__(self, memo):
- other = MovingLeastSquaresInterpolator()
- (other.support, other.localProjector, other.localVanders,
- other.suppValues, other.directionalWeights, other.degree, other.npar,
- other.radialbasis, other.polybasis, other.evalParams,
- other.totalDegree) = copy(
- (self.support, self.localProjector, self.localVanders,
- self.suppValues, self.directionalWeights, self.degree,
- self.npar, self.radialbasis, self.polybasis,
- self.evalParams, self.totalDegree), memo)
- return other
-
- def postmultiplyTensorize(self, A:Np2D):
- RROMPyAssert(A.shape[0], self.shape[-1], "Shape of output")
- self.suppValues = np.tensordot(self.suppValues, A, 1)
-
- def pad(self, nleft : List[int] = None, nright : List[int] = None):
- if nleft is None: nleft = [0] * len(self.shape)
- if nright is None: nright = [0] * len(self.shape)
- if not hasattr(nleft, "__len__"): nleft = [nleft]
- if not hasattr(nright, "__len__"): nright = [nright]
- RROMPyAssert(len(self.shape), len(nleft), "Shape of output")
- RROMPyAssert(len(self.shape), len(nright), "Shape of output")
- padwidth = [(0, 0)] + [(l, r) for l, r in zip(nleft, nright)]
- self.suppValues = np.pad(self.suppValues, padwidth, "constant",
- constant_values = (0., 0.))
-
- def setupByInterpolation(self, support:paramList, values:ListAny,
- deg:int, polybasis : str = "MONOMIAL_GAUSSIAN",
- directionalWeights : Np1D = None,
- totalDegree : bool = True,
- vanderCoeffs : DictAny = {}):
- support = checkParameterList(support)[0]
- self.support = copy(support)
- if "reorder" in vanderCoeffs.keys():
- self.support = self.support[vanderCoeffs["reorder"]]
- self.npar = support.shape[1]
- if directionalWeights is None:
- directionalWeights = np.ones(self.npar)
- self.directionalWeights = directionalWeights
- self.polybasis, self.radialbasis, _ = polybasis.split("_")
- self.totalDegree = totalDegree
- self.evalParams = vanderCoeffs
- if totalDegree:
- vander = pvT(support, deg, self.polybasis, **vanderCoeffs)
- if not hasattr(deg, "__len__"): deg = [deg] * self.npar
- else:
- if not hasattr(deg, "__len__"): deg = [deg] * self.npar
- vander = pv(support, deg, self.polybasis, **vanderCoeffs)
- self.degree = deg
- self.localProjector = vander.T.conj()
- self.localVanders = np.array([np.outer(van, van.conj()) \
- for van in vander])
- self.localVanders = np.swapaxes(self.localVanders, 0, 2)
- self.suppValues = np.array(values)
-
diff --git a/rrompy/utilities/poly_fitting/moving_least_squares/vander.py b/rrompy/utilities/poly_fitting/moving_least_squares/vander.py
deleted file mode 100644
index f378f57..0000000
--- a/rrompy/utilities/poly_fitting/moving_least_squares/vander.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# 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 .
-#
-
-import numpy as np
-from .kernel import (radialGaussian, thinPlateSpline, multiQuadric,
- localWendland)
-from rrompy.utilities.poly_fitting.polynomial.vander import (polyvander as pvP,
- polyvanderTotal as pvTP)
-from rrompy.utilities.base.types import (Np1D, Np2D, Tuple, List, paramVal,
- paramList)
-from rrompy.parameter import checkParameter, checkParameterList
-from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
-
-__all__ = ['mlsweights', 'polyvander', 'polyvanderTotal']
-
-def mlsweights(x:paramVal, xSupp:paramList, basis:str,
- reorder : List[int] = None,
- directionalWeights : Np1D = None) -> Np2D:
- """Compute moving least squares weight vector."""
- x = checkParameter(x)
- xSupp = checkParameterList(xSupp)[0]
- x = x.data
- xSupp = xSupp.data
- if directionalWeights is None:
- directionalWeights = np.ones(x.shape[1])
- elif not hasattr(directionalWeights, "__len__"):
- directionalWeights = directionalWeights * np.ones(x.shape[1])
- RROMPyAssert(len(directionalWeights), x.shape[1],
- "Number of directional weights")
- try:
- radialkernel = {"GAUSSIAN" : radialGaussian,
- "THINPLATE" : thinPlateSpline,
- "MULTIQUADRIC" : multiQuadric,
- "WENDLAND" : localWendland}[basis.upper()]
- except:
- raise RROMPyException("Radial basis not recognized.")
- if reorder is not None: xSupp = xSupp[reorder]
- muDiff = (xSupp.data - x) * directionalWeights
- r2 = np.sum(np.abs(muDiff) ** 2., axis = 1).reshape(1, -1)
- return radialkernel(r2)[0]
-
-def polyvander(x:paramVal, xSupp:paramList, degs:List[int], basis:str,
- derIdxs : List[List[List[int]]] = None,
- reorder : List[int] = None, directionalWeights : Np1D = None,
- scl : Np1D = None) -> Tuple[Np2D, Np2D]:
- """
- Compute full Hermite-Vandermonde matrix with specified derivative
- directions.
- """
- basisp, basisr, _ = basis.split("_")
- Weights = mlsweights(x, xSupp, basisr, reorder, directionalWeights)
- VanP = pvP(xSupp, degs, basisp, derIdxs = derIdxs, reorder = reorder,
- scl = scl)
- RHP = VanP.T.conj() * Weights
- return RHP.dot(VanP), RHP
-
-def polyvanderTotal(x:paramList, xSupp:paramList, deg:int, basis:str,
- derIdxs : List[List[List[int]]] = None,
- reorder : List[int] = None,
- directionalWeights : Np1D = None,
- scl : Np1D = None) -> Tuple[Np2D, Np2D]:
- """
- Compute full total degree Hermite-Vandermonde matrix with specified
- derivative directions.
- """
- basisp, basisr, _ = basis.split("_")
- Weights = mlsweights(x, xSupp, basisr, reorder, directionalWeights)
- VanP = pvTP(x, deg, basisp, derIdxs = derIdxs,
- reorder = reorder, scl = scl)
- RHP = VanP.T.conj() * Weights
- return RHP.dot(VanP), RHP