diff --git a/VERSION b/VERSION
index 081af9a..4684374 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.7.1
\ No newline at end of file
+1.8
\ No newline at end of file
diff --git a/examples/2d/base/fracture.py b/examples/2d/base/fracture.py
index d4f075e..b98b5e5 100644
--- a/examples/2d/base/fracture.py
+++ b/examples/2d/base/fracture.py
@@ -1,46 +1,46 @@
import numpy as np
import ufl
import fenics as fen
from rrompy.hfengines.linear_problem.bidimensional import \
MembraneFractureEngine as MFE
from rrompy.solver.fenics import affine_warping
verb = 100
mu0 = [45. ** .5, .7]
H = 1.
L = .75
delta = .05
n = 50
solver = MFE(mu0 = mu0, H = H, L = L, delta = delta,
n = n, verbosity = verb)
-u0 = solver.liftDirichletData(mu0)
+u0 = solver.liftDirichletData()
uh = solver.solve(mu0)[0]
#solver.plotmesh(figsize = (7.5, 4.5))
#solver.plot(u0, what = 'REAL', figsize = (8, 5))
print(solver.norm(uh))
#solver.plot(uh, what = 'REAL', figsize = (8, 5))
-#solver.plot(solver.residual(uh, mu0)[0], name = 'res',
+#solver.plot(solver.residual(mu0, uh)[0], name = 'res',
# what = 'REAL', figsize = (8, 5))
#solver.outParaviewTimeDomain(uh, mu0[0], filename = 'out', folder = True,
# forceNewFile = False)
y = fen.SpatialCoordinate(solver.V.mesh())[1]
warp1, warpI1 = affine_warping(solver.V.mesh(),
np.array([[1, 0], [0, 2. * mu0[1]]]))
warp2, warpI2 = affine_warping(solver.V.mesh(),
np.array([[1, 0], [0, 2. - 2. * mu0[1]]]))
warp = ufl.conditional(ufl.ge(y, 0.), warp1, warp2)
warpI = ufl.conditional(ufl.ge(y, 0.), warpI1, warpI2)
#solver.plotmesh([warp, warpI], figsize = (7.5, 4.5))
#solver.plot(u0, [warp, warpI], what = 'REAL', figsize = (8, 5))
solver.plot(uh, [warp, warpI], what = 'REAL', figsize = (8, 5))
-#solver.plot(solver.residual(uh, mu0)[0], [warp, warpI], name = 'res',
+#solver.plot(solver.residual(mu0, uh)[0], [warp, warpI], name = 'res',
# what = 'REAL', figsize = (8, 5))
#solver.outParaviewTimeDomain(uh, mu0[0], [warp, warpI],
# filename = 'outW', folder = True,
# forceNewFile = False)
diff --git a/examples/2d/base/fracture_nodomain.py b/examples/2d/base/fracture_nodomain.py
index 7be9125..400c730 100644
--- a/examples/2d/base/fracture_nodomain.py
+++ b/examples/2d/base/fracture_nodomain.py
@@ -1,47 +1,47 @@
import numpy as np
import ufl
import fenics as fen
from rrompy.hfengines.linear_problem import MembraneFractureEngineNoDomain \
as MFEND
from rrompy.solver.fenics import affine_warping
verb = 100
mu0Aug = [45. ** .5, .6]
mu0Aug = [45. ** .5, .1]
mu0 = mu0Aug[0]
H = 1.
L = .75
delta = .05
n = 50
solver = MFEND(mu0 = mu0Aug, H = H, L = L, delta = delta,
n = n, verbosity = verb)
-u0 = solver.liftDirichletData(mu0)
+u0 = solver.liftDirichletData()
uh = solver.solve(mu0)[0]
solver.plotmesh(figsize = (7.5, 4.5))
solver.plot(u0, what = 'REAL', figsize = (8, 5))
print(solver.norm(uh))
solver.plot(uh, what = 'REAL', figsize = (8, 5))
-solver.plot(solver.residual(uh, mu0)[0], name = 'res',
+solver.plot(solver.residual(mu0, uh)[0], name = 'res',
what = 'REAL', figsize = (8, 5))
solver.outParaviewTimeDomain(uh, mu0, filename = 'outND', folder = True)
##
L = mu0Aug[1]
y = fen.SpatialCoordinate(solver.V.mesh())[1]
warp1, warpI1 = affine_warping(solver.V.mesh(),
np.array([[1, 0], [0, 2. * L]]))
warp2, warpI2 = affine_warping(solver.V.mesh(),
np.array([[1, 0], [0, 2. - 2. * L]]))
warp = ufl.conditional(ufl.ge(y, 0.), warp1, warp2)
warpI = ufl.conditional(ufl.ge(y, 0.), warpI1, warpI2)
solver.plotmesh([warp, warpI], figsize = (7.5, 4.5))
solver.plot(u0, [warp, warpI], what = 'REAL', figsize = (8, 5))
solver.plot(uh, [warp, warpI], what = 'REAL', figsize = (8, 5))
-solver.plot(solver.residual(uh, mu0)[0], [warp, warpI], name = 'res',
+solver.plot(solver.residual(mu0, uh)[0], [warp, warpI], name = 'res',
what = 'REAL', figsize = (8, 5))
solver.outParaviewTimeDomain(uh, mu0, [warp, warpI],
filename = 'outNDW', folder = True)
diff --git a/examples/2d/base/square.py b/examples/2d/base/square.py
index ae2428e..856cf1a 100644
--- a/examples/2d/base/square.py
+++ b/examples/2d/base/square.py
@@ -1,13 +1,13 @@
import numpy as np
from rrompy.hfengines.linear_problem.bidimensional import \
HelmholtzSquareDomainProblemEngine as HSDPE
verb = 100
mu0 = [4 ** .5, 1.5 ** .5]
solver = HSDPE(kappa = 2.5, theta = np.pi / 3, mu0 = mu0, n = 50,
verbosity = verb)
uh = solver.solve(mu0)[0]
solver.plotmesh()
print(solver.norm(uh))
solver.plot(uh)
-solver.plot(solver.residual(uh, mu0)[0], 'res')
+solver.plot(solver.residual(mu0, uh)[0], 'res')
diff --git a/examples/2d/base/square_simplified.py b/examples/2d/base/square_simplified.py
index fa0e984..6188ee7 100644
--- a/examples/2d/base/square_simplified.py
+++ b/examples/2d/base/square_simplified.py
@@ -1,13 +1,13 @@
import numpy as np
from rrompy.hfengines.linear_problem.bidimensional import \
HelmholtzSquareSimplifiedDomainProblemEngine as HSSDPE
verb = 0
mu0 = [4 ** .5, 1.5 ** .5]
solver = HSSDPE(kappa = 2.5, theta = np.pi / 3, mu0 = mu0, n = 50,
verbosity = verb)
uh = solver.solve(mu0)[0]
solver.plotmesh()
print(solver.norm(uh))
solver.plot(uh)
-solver.plot(solver.residual(uh, mu0)[0], 'res')
+solver.plot(solver.residual(mu0, uh)[0], 'res')
diff --git a/examples/2d/greedy/fracture_pod.py b/examples/2d/greedy/fracture_pod.py
new file mode 100644
index 0000000..1732615
--- /dev/null
+++ b/examples/2d/greedy/fracture_pod.py
@@ -0,0 +1,221 @@
+import numpy as np
+from rrompy.hfengines.linear_problem.bidimensional import \
+ MembraneFractureEngine as MFE
+from rrompy.reduction_methods.greedy import RationalInterpolantGreedy as RIG
+from rrompy.reduction_methods.greedy import ReducedBasisGreedy as RBG
+from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
+ QuadratureSamplerTotal as QST)
+
+verb = 15
+size = 16
+show_sample = False
+show_norm = True
+
+MN = 1
+S = (MN + 2) * (MN + 1) // 2
+greedyTol = 1e-1
+collinearityTol = 0.
+nTestPoints = 900
+
+algo = "rational"
+#algo = "RB"
+
+if algo == "rational":
+ radial = ""
+ #radial = "_gaussian"
+ #radial = "_thinplate"
+ #radial = "_multiquadric"
+ rW0 = 5.
+ radialWeight = [rW0] * 2
+ polybasis = "CHEBYSHEV"
+ polybasis = "LEGENDRE"
+ #polybasis = "MONOMIAL"
+ errorEstimatorKind = 'AFFINE'
+ errorEstimatorKind = 'DISCREPANCY'
+ errorEstimatorKind = 'INTERPOLATORY'
+# errorEstimatorKind = 'EIM_DIAGONAL'
+ errorEstimatorKind = 'EIM_INTERPOLATORY'
+
+if size == 1: # below
+ mu0 = [40 ** .5, .4]
+ mutar = [45 ** .5, .4]
+ murange = [[30 ** .5, .3], [50 ** .5, .5]]
+elif size == 2: # top
+ mu0 = [40 ** .5, .6]
+ mutar = [45 ** .5, .6]
+ murange = [[30 ** .5, .5], [50 ** .5, .7]]
+elif size == 3: # interesting
+ mu0 = [40 ** .5, .5]
+ mutar = [45 ** .5, .5]
+ murange = [[30 ** .5, .3], [50 ** .5, .7]]
+elif size == 4: # wide_low
+ mu0 = [40 ** .5, .2]
+ mutar = [45 ** .5, .2]
+ murange = [[10 ** .5, .1], [70 ** .5, .3]]
+elif size == 5: # wide_hi
+ mu0 = [40 ** .5, .8]
+ mutar = [45 ** .5, .8]
+ murange = [[10 ** .5, .7], [70 ** .5, .9]]
+elif size == 6: # top_zoom
+ mu0 = [50 ** .5, .8]
+ mutar = [55 ** .5, .8]
+ murange = [[40 ** .5, .7], [60 ** .5, .9]]
+elif size == 7: # huge
+ mu0 = [50 ** .5, .5]
+ mutar = [55 ** .5, .5]
+ murange = [[10 ** .5, .2], [90 ** .5, .8]]
+elif size == 11: #L below
+ mu0 = [110 ** .5, .4]
+ mutar = [115 ** .5, .4]
+ murange = [[90 ** .5, .3], [130 ** .5, .5]]
+elif size == 12: #L top
+ mu0 = [110 ** .5, .6]
+ mutar = [115 ** .5, .6]
+ murange = [[90 ** .5, .5], [130 ** .5, .7]]
+elif size == 13: #L interesting
+ mu0 = [110 ** .5, .5]
+ mutar = [115 ** .5, .5]
+ murange = [[90 ** .5, .3], [130 ** .5, .7]]
+elif size == 14: #L belowbelow
+ mu0 = [110 ** .5, .2]
+ mutar = [115 ** .5, .2]
+ murange = [[90 ** .5, .1], [130 ** .5, .3]]
+elif size == 15: #L toptop
+ mu0 = [110 ** .5, .8]
+ mutar = [115 ** .5, .8]
+ murange = [[90 ** .5, .7], [130 ** .5, .9]]
+elif size == 16: #L interestinginteresting
+ mu0 = [110 ** .5, .5]
+ mutar = [115 ** .5, .6]
+ murange = [[90 ** .5, .1], [130 ** .5, .9]]
+elif size == 17: #L interestingtop
+ mu0 = [110 ** .5, .7]
+ mutar = [115 ** .5, .6]
+ murange = [[90 ** .5, .5], [130 ** .5, .9]]
+elif size == 18: #L interestingbelow
+ mu0 = [110 ** .5, .3]
+ mutar = [115 ** .5, .4]
+ murange = [[90 ** .5, .1], [130 ** .5, .5]]
+elif size == 100: # tiny
+ mu0 = [32.5 ** .5, .5]
+ mutar = [34 ** .5, .5]
+ murange = [[30 ** .5, .3], [35 ** .5, .7]]
+
+aEff = 1.05
+bEff = 1. - aEff
+murangeEff = [[(aEff*murange[0][0]**2. + bEff*murange[1][0]**2.) ** .5,
+ aEff*murange[0][1] + bEff*murange[1][1]],
+ [(aEff*murange[1][0]**2. + bEff*murange[0][0]**2.) ** .5,
+ aEff*murange[1][1] + bEff*murange[0][1]]]
+
+H = 1.
+L = .75
+delta = .05
+n = 20
+
+solver = MFE(mu0 = mu0, H = H, L = L, delta = delta, n = n, verbosity = verb)
+
+rescalingExp = [2., 1.]
+if algo == "rational":
+ params = {'S':S, 'POD':True, 'greedyTol':greedyTol,
+ 'sampler':QS(murange, 'UNIFORM', scalingExp = rescalingExp),
+ 'nTestPoints':nTestPoints, 'polybasis':polybasis + radial,
+ 'radialDirectionalWeights':radialWeight,
+ 'errorEstimatorKind':errorEstimatorKind,
+ 'trainSetGenerator':QST(murange, 'CHEBYSHEV',
+ scalingExp = rescalingExp)}
+ method = RIG
+else: #if algo == "RB":
+ params = {'S':S, 'POD':True, 'greedyTol':greedyTol,
+ 'sampler':QS(murange, 'UNIFORM', scalingExp = rescalingExp),
+ 'nTestPoints':nTestPoints,
+ 'trainSetGenerator':QST(murange, 'CHEBYSHEV',
+ scalingExp = rescalingExp)}
+ method = RBG
+
+approx = method(solver, mu0 = mu0, approxParameters = params, verbosity = verb)
+
+approx.greedy(True)
+
+if show_sample:
+ import ufl
+ import fenics as fen
+ from rrompy.solver.fenics import affine_warping
+ L = mutar[1]
+ y = fen.SpatialCoordinate(solver.V.mesh())[1]
+ warp1, warpI1 = affine_warping(solver.V.mesh(),
+ np.array([[1, 0], [0, 2. * L]]))
+ warp2, warpI2 = affine_warping(solver.V.mesh(),
+ np.array([[1, 0], [0, 2. - 2. * L]]))
+ warp = ufl.conditional(ufl.ge(y, 0.), warp1, warp2)
+ warpI = ufl.conditional(ufl.ge(y, 0.), warpI1, warpI2)
+
+ approx.plotApprox(mutar, [warp, warpI], name = 'u_app', what = "REAL")
+ approx.plotHF(mutar, [warp, warpI], name = 'u_HF', what = "REAL")
+ approx.plotErr(mutar, [warp, warpI], name = 'err', what = "REAL")
+# approx.plotRes(mutar, [warp, warpI], name = 'res', what = "REAL")
+ appErr = approx.normErr(mutar)
+ solNorm = approx.normHF(mutar)
+ resNorm = approx.normRes(mutar)
+ RHSNorm = approx.normRHS(mutar)
+ print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
+ np.divide(appErr, solNorm)))
+ print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+ np.divide(resNorm, RHSNorm)))
+
+verb = approx.trainedModel.verbosity
+approx.trainedModel.verbosity = 5
+from plot_zero_set import plotZeroSet2
+muZeroVals, Qvals = plotZeroSet2(murange, murangeEff, approx, mu0,
+ 200, [2., 1.])
+
+if show_norm:
+ from plot_inf_set import plotInfSet2
+ muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet2(
+ murange, murangeEff, approx, mu0, 50,
+ [2., 1.], relative = True,
+ nobeta = True)
+
+ try:
+ QV = approx.trainedModel.getQVal(muInfVals)
+ import warnings
+ from matplotlib import pyplot as plt
+ mu2x, mu2y = approx.mus(0) ** 2., approx.mus(1) ** 1.
+ murangeExp = [[murange[0][0] ** 2., murange[0][1]],
+ [murange[1][0] ** 2., murange[1][1]]]
+ mu1s = np.unique([m[0] for m in muInfVals])
+ mu2s = np.unique([m[1] for m in muInfVals])
+ mu1 = np.power(mu1s, 2.)
+ mu2 = np.power(mu2s, 1.)
+ Mu1, Mu2 = np.meshgrid(np.real(mu1), np.real(mu2))
+ Reste = (approx.errorEstimator(muInfVals) * QV).reshape(normEx.shape)
+ Rest = np.log10(Reste)
+ Restmin, Restmax = np.min(Rest), np.max(Rest)
+ cmap = plt.cm.jet
+ warnings.simplefilter("ignore", category = (UserWarning,
+ np.ComplexWarning))
+ plt.figure(figsize = (15, 7))
+ plt.jet()
+ p = plt.contourf(Mu1, Mu2, Rest,
+ levels = np.linspace(Restmin, Restmax, 50))
+ plt.plot(np.real(mu2x), np.real(mu2y), 'kx')
+ for j, xy in enumerate(zip(np.real(mu2x), np.real(mu2y))):
+ plt.annotate("{}".format(j), xy)
+ plt.plot([murangeExp[0][0]] * 2,
+ [murangeExp[0][1], murangeExp[1][1]], 'm:')
+ plt.plot([murangeExp[0][0], murangeExp[1][0]],
+ [murangeExp[1][1]] * 2, 'm:')
+ plt.plot([murangeExp[1][0]] * 2,
+ [murangeExp[1][1], murangeExp[0][1]], 'm:')
+ plt.plot([murangeExp[1][0], murangeExp[0][0]],
+ [murangeExp[0][1]] * 2, 'm:')
+ plt.title("log10|res_est(mu)|")
+ plt.colorbar(p)
+ plt.grid()
+ plt.show()
+ except: pass
+approx.trainedModel.verbosity = verb
+
+try:
+ print(np.sort(approx.getPoles([None, .5]) ** 2.))
+except: pass
diff --git a/examples/2d/greedy/plot_inf_set.py b/examples/2d/greedy/plot_inf_set.py
new file mode 120000
index 0000000..ad92d4d
--- /dev/null
+++ b/examples/2d/greedy/plot_inf_set.py
@@ -0,0 +1 @@
+/home/pradovera/Repos/RROMPy/examples/2d/pod/plot_inf_set.py
\ No newline at end of file
diff --git a/examples/2d/greedy/plot_zero_set.py b/examples/2d/greedy/plot_zero_set.py
new file mode 120000
index 0000000..6b5351e
--- /dev/null
+++ b/examples/2d/greedy/plot_zero_set.py
@@ -0,0 +1 @@
+/home/pradovera/Repos/RROMPy/examples/2d/pod/plot_zero_set.py
\ No newline at end of file
diff --git a/examples/2d/pod/cookie_single_pod.py b/examples/2d/pod/cookie_single_pod.py
index 0efdfd4..98a4f3c 100644
--- a/examples/2d/pod/cookie_single_pod.py
+++ b/examples/2d/pod/cookie_single_pod.py
@@ -1,134 +1,124 @@
import numpy as np
from rrompy.hfengines.linear_problem.bidimensional import \
CookieEngineSingle as CES
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
QuadratureSamplerTotal as QST,
ManualSampler as MS,
RandomSampler as RS)
verb = 5
size = 1
show_sample = True
show_norm = True
clip = -1
#clip = .4
#clip = .6
Delta = -10
-MN = 15
+MN = 5
R = (MN + 2) * (MN + 1) // 2
-S = [int(np.ceil(R ** .5))] * 2
+STensorized = (MN + 1) ** 2
PODTol = 1e-6
samples = "centered"
samples = "standard"
algo = "rational"
#algo = "RB"
sampling = "quadrature"
sampling = "quadrature_total"
sampling = "random"
if samples == "standard":
- radial = 0
-# radial = "gaussian"
-# radial = "thinplate"
-# radial = "multiquadric"
+ radial = ""
+# radial = "_gaussian"
+# radial = "_thinplate"
+# radial = "_multiquadric"
rW0 = 1.
radialWeight = [rW0] * 2
assert Delta <= 0
if size == 1: # below
mu0 = [20 ** .5, 1. ** .5]
mutar = [20.5 ** .5, 1.05 ** .5]
murange = [[18.5 ** .5, .85 ** .5], [21.5 ** .5, 1.15 ** .5]]
aEff = 1.#25
bEff = 1. - aEff
murangeEff = [[(aEff*murange[0][0]**2. + bEff*murange[1][0]**2.) ** .5,
aEff*murange[0][1] + bEff*murange[1][1]],
[(aEff*murange[1][0]**2. + bEff*murange[0][0]**2.) ** .5,
aEff*murange[1][1] + bEff*murange[0][1]]]
kappa = 20. ** .5
theta = - np.pi / 6.
n = 30
Rad = 1.
L = np.pi
nX = 2
nY = 1
solver = CES(kappa = kappa, theta = theta, n = n, R = Rad, L = L, nX = nX,
nY = nY, mu0 = mu0, verbosity = verb)
rescalingExp = [2.] * 2
if algo == "rational":
- params = {'N':MN, 'M':MN + Delta, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN + Delta, 'S':R, 'POD':True}
if samples == "standard":
- params['polybasis'] = "CHEBYSHEV"
-# params['polybasis'] = "LEGENDRE"
-# params['polybasis'] = "MONOMIAL"
- params['E'] = MN
- params['radialBasis'] = radial
- params['radialBasisWeights'] = radialWeight
+ params['polybasis'] = "CHEBYSHEV" + radial
+# params['polybasis'] = "LEGENDRE" + radial
+# params['polybasis'] = "MONOMIAL" + radial
+ params['radialDirectionalWeights'] = radialWeight
elif samples == "centered":
params['polybasis'] = "MONOMIAL"
- params['S'] = R
method = RI
else: #if algo == "RB":
- params = {'R':(MN + 2 + Delta) * (MN + 1 + Delta) // 2, 'S':S,
+ params = {'R':(MN + 2 + Delta) * (MN + 1 + Delta) // 2, 'S':R,
'POD':True, 'PODTolerance':PODTol}
- if samples == "centered":
- params['S'] = R
method = RB
if samples == "standard":
if sampling == "quadrature":
params['sampler'] = QS(murange, "CHEBYSHEV", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "GAUSSLEGENDRE", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "UNIFORM", scalingExp = rescalingExp)
- params['S'] = [max(j, MN + 1) for j in params['S']]
+ params['S'] = STensorized
elif sampling == "quadrature_total":
params['sampler'] = QST(murange, "CHEBYSHEV", scalingExp = rescalingExp)
- params['S'] = R
else: # if sampling == "random":
params['sampler'] = RS(murange, "HALTON", scalingExp = rescalingExp)
- params['S'] = R
elif samples == "centered":
params['sampler'] = MS(murange, points = [mu0], scalingExp = rescalingExp)
approx = method(solver, mu0 = mu0, approxParameters = params, verbosity = verb)
-if samples == "standard": approx.samplingEngine.allowRepeatedSamples = False
approx.setupApprox()
if show_sample:
L = mutar[1]
- approx.plotApprox(mutar, name = 'u_app', homogeneized = False,
- what = "REAL")
- approx.plotHF(mutar, name = 'u_HF', homogeneized = False, what = "REAL")
- approx.plotErr(mutar, name = 'err', homogeneized = False, what = "REAL")
-# approx.plotRes(mutar, name = 'res', homogeneized = False, what = "REAL")
+ approx.plotApprox(mutar, name = 'u_app', what = "REAL")
+ approx.plotHF(mutar, name = 'u_HF', what = "REAL")
+ approx.plotErr(mutar, name = 'err', what = "REAL")
+# approx.plotRes(mutar, name = 'res', what = "REAL")
appErr = approx.normErr(mutar)
solNorm = approx.normHF(mutar)
resNorm = approx.normRes(mutar)
RHSNorm = approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
if algo == "rational" and approx.N > 0:
from plot_zero_set import plotZeroSet2
muZeroVals, Qvals = plotZeroSet2(murange, murangeEff, approx, mu0,
200, [2., 2.], clip = clip)
if show_norm:
- solver._solveBatchSize = 100
from plot_inf_set import plotInfSet2
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet2(
murange, murangeEff, approx, mu0, 25,
[2., 2.], clip = clip, relative = False)
diff --git a/examples/2d/pod/fracture_pod.py b/examples/2d/pod/fracture_pod.py
index 646274d..c32c8a7 100644
--- a/examples/2d/pod/fracture_pod.py
+++ b/examples/2d/pod/fracture_pod.py
@@ -1,280 +1,265 @@
import numpy as np
from rrompy.hfengines.linear_problem.bidimensional import \
MembraneFractureEngine as MFE
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.reduction_methods.pivoted import RationalInterpolantPivoted as RIP
-from rrompy.reduction_methods.pivoted import ReducedBasisPivoted as RBP
-from rrompy.reduction_methods.pole_matching import \
- RationalInterpolantPoleMatching as RIPM
-from rrompy.reduction_methods.pole_matching import \
- ReducedBasisPoleMatching as RBPM
+#from rrompy.reduction_methods.pivoted import ReducedBasisPivoted as RBP
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
QuadratureSamplerTotal as QST,
ManualSampler as MS,
RandomSampler as RS)
-verb = 70
+verb = 10
size = 2
-show_sample = False
+show_sample = True
show_norm = True
Delta = 0
-MN = 8
+MN = 5
R = (MN + 2) * (MN + 1) // 2
-S = [int(np.ceil(R ** .5))] * 2
-PODTol = 1e-4
-SPivot = [MN + 1, 4]
-MMarginal = SPivot[1] - 1
+STensorized = (MN + 1) ** 2
+PODTol = 1e-10
+SPivot = MN + 1
+SMarginal = 4
+MMarginal = SMarginal - 1
matchingWeight = 1.
cutOffTolerance = 1. * np.inf
cutOffType = "MAGNITUDE"
samples = "centered"
samples = "standard"
-samples = "pivoted"
-samples = "pole matching"
+#samples = "pivoted"
algo = "rational"
algo = "RB"
sampling = "quadrature"
-sampling = "quadrature_total"
+#sampling = "quadrature_total"
#sampling = "random"
samplingM = "quadrature"
#samplingM = "quadrature_total"
#samplingM = "random"
-if samples in ["standard", "pivoted", "pole matching"]:
- radial = 0
-# radial = "gaussian"
-# radial = "thinplate"
-# radial = "multiquadric"
+polydegreetype = "TOTAL"
+polydegreetype = "FULL"
+if samples in ["standard", "pivoted"]:
+ radial = ""
+# radial = "_gaussian"
+# radial = "_thinplate"
+# radial = "_multiquadric"
rW0 = 5.
radialWeight = [rW0]
-if samples in ["pivoted", "pole matching"]:
- radialM = 0
-# radialM = "gaussian"
-# radialM = "thinplate"
-# radialM = "multiquadric"
+if samples == "pivoted":
+ radialM = ""
+# radialM = "_gaussian"
+# radialM = "_thinplate"
+# radialM = "_multiquadric"
rMW0 = 2.
radialWeightM = [rMW0]
assert Delta <= 0
if size == 1: # below
mu0 = [40 ** .5, .4]
mutar = [45 ** .5, .4]
murange = [[30 ** .5, .3], [50 ** .5, .5]]
elif size == 2: # top
mu0 = [40 ** .5, .6]
mutar = [45 ** .5, .6]
murange = [[30 ** .5, .5], [50 ** .5, .7]]
elif size == 3: # interesting
mu0 = [40 ** .5, .5]
mutar = [45 ** .5, .5]
murange = [[30 ** .5, .3], [50 ** .5, .7]]
elif size == 4: # wide_low
mu0 = [40 ** .5, .2]
mutar = [45 ** .5, .2]
murange = [[10 ** .5, .1], [70 ** .5, .3]]
elif size == 5: # wide_hi
mu0 = [40 ** .5, .8]
mutar = [45 ** .5, .8]
murange = [[10 ** .5, .7], [70 ** .5, .9]]
elif size == 6: # top_zoom
mu0 = [50 ** .5, .8]
mutar = [55 ** .5, .8]
murange = [[40 ** .5, .7], [60 ** .5, .9]]
elif size == 7: # huge
mu0 = [50 ** .5, .5]
mutar = [55 ** .5, .5]
murange = [[10 ** .5, .2], [90 ** .5, .8]]
elif size == 11: #L below
mu0 = [110 ** .5, .4]
mutar = [115 ** .5, .4]
murange = [[90 ** .5, .3], [130 ** .5, .5]]
elif size == 12: #L top
mu0 = [110 ** .5, .6]
mutar = [115 ** .5, .6]
murange = [[90 ** .5, .5], [130 ** .5, .7]]
elif size == 13: #L interesting
mu0 = [110 ** .5, .5]
mutar = [115 ** .5, .5]
murange = [[90 ** .5, .3], [130 ** .5, .7]]
elif size == 14: #L belowbelow
mu0 = [110 ** .5, .2]
mutar = [115 ** .5, .2]
murange = [[90 ** .5, .1], [130 ** .5, .3]]
elif size == 15: #L toptop
mu0 = [110 ** .5, .8]
mutar = [115 ** .5, .8]
murange = [[90 ** .5, .7], [130 ** .5, .9]]
elif size == 16: #L interestinginteresting
mu0 = [110 ** .5, .5]
mutar = [115 ** .5, .6]
murange = [[90 ** .5, .1], [130 ** .5, .9]]
elif size == 17: #L interestingtop
mu0 = [110 ** .5, .7]
mutar = [115 ** .5, .6]
murange = [[90 ** .5, .5], [130 ** .5, .9]]
elif size == 18: #L interestingbelow
mu0 = [110 ** .5, .3]
mutar = [115 ** .5, .4]
murange = [[90 ** .5, .1], [130 ** .5, .5]]
elif size == 100: # tiny
mu0 = [32.5 ** .5, .5]
mutar = [34 ** .5, .5]
murange = [[30 ** .5, .3], [35 ** .5, .7]]
aEff = 1.#25
bEff = 1. - aEff
murangeEff = [[(aEff*murange[0][0]**2. + bEff*murange[1][0]**2.) ** .5,
aEff*murange[0][1] + bEff*murange[1][1]],
[(aEff*murange[1][0]**2. + bEff*murange[0][0]**2.) ** .5,
aEff*murange[1][1] + bEff*murange[0][1]]]
H = 1.
L = .75
delta = .05
n = 20
solver = MFE(mu0 = mu0, H = H, L = L, delta = delta, n = n, verbosity = verb)
rescalingExp = [2., 1.]
if algo == "rational":
- params = {'N':MN, 'M':MN + Delta, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN + Delta, 'S':R, 'POD':True,
+ 'polydegreetype':polydegreetype}
if samples == "standard":
- params['polybasis'] = "CHEBYSHEV"
-# params['polybasis'] = "LEGENDRE"
-# params['polybasis'] = "MONOMIAL"
- params['E'] = MN
- params['radialBasis'] = radial
- params['radialBasisWeights'] = radialWeight
+ params['polybasis'] = "CHEBYSHEV" + radial
+# params['polybasis'] = "LEGENDRE" + radial
+# params['polybasis'] = "MONOMIAL" + radial
+ params['radialDirectionalWeights'] = radialWeight * 2
method = RI
elif samples == "centered":
params['polybasis'] = "MONOMIAL"
- params['S'] = R
method = RI
- elif samples in ["pivoted", "pole matching"]:
- params['S'] = [SPivot[0]]
- params['SMarginal'] = [SPivot[1]]
+ elif samples == "pivoted":
+ params['S'] = SPivot
+ params['SMarginal'] = SMarginal
params['MMarginal'] = MMarginal
- params['polybasisPivot'] = "CHEBYSHEV"
- params['polybasisMarginal'] = "MONOMIAL"
- params['radialBasisPivot'] = radial
- params['radialBasisMarginal'] = radialM
- params['radialBasisWeightsPivot'] = radialWeight
- params['radialBasisWeightsMarginal'] = radialWeightM
- if samples == "pivoted":
- method = RIP
- else:
- params['matchingWeight'] = matchingWeight
- params['cutOffTolerance'] = cutOffTolerance
- params["cutOffType"] = cutOffType
- method = RIPM
+ params['polybasisPivot'] = "CHEBYSHEV" + radial
+ params['polybasisMarginal'] = "MONOMIAL" + radialM
+ params['radialDirectionalWeightsPivot'] = radialWeight
+ params['radialDirectionalWeightsMarginal'] = radialWeightM
+ params['matchingWeight'] = matchingWeight
+ params['cutOffTolerance'] = cutOffTolerance
+ params["cutOffType"] = cutOffType
+ method = RIP
else: #if algo == "RB":
- params = {'R':(MN + 2 + Delta) * (MN + 1 + Delta) // 2, 'S':S,
+ params = {'R':(MN + 2 + Delta) * (MN + 1 + Delta) // 2, 'S':R,
'POD':True, 'PODTolerance':PODTol}
if samples == "standard":
method = RB
elif samples == "centered":
- params['S'] = R
method = RB
- elif samples in ["pivoted", "pole matching"]:
- params['S'] = [SPivot[0]]
- params['SMarginal'] = [SPivot[1]]
- params['MMarginal'] = MMarginal
- params['polybasisMarginal'] = "MONOMIAL"
- params['radialBasisMarginal'] = radialM
- params['radialBasisWeightsMarginal'] = radialWeightM
- method = RBP
- if samples == "pivoted":
- method = RBP
- else:
- params['matchingWeight'] = matchingWeight
- params['cutOffTolerance'] = cutOffTolerance
- params["cutOffType"] = cutOffType
- method = RBPM
+ elif samples == "pivoted":
+ raise
+# params['S'] = SPivot
+# params['R'] = SPivot
+# params['SMarginal'] = SMarginal
+# params['MMarginal'] = MMarginal
+# params['polybasisMarginal'] = "MONOMIAL" + radialM
+# params['radialDirectionalWeightsMarginal'] = radialWeightM
+# params['matchingWeight'] = matchingWeight
+# params['cutOffTolerance'] = cutOffTolerance
+# params["cutOffType"] = cutOffType
+# method = RBP
if samples == "standard":
if sampling == "quadrature":
params['sampler'] = QS(murange, "CHEBYSHEV", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "GAUSSLEGENDRE", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "UNIFORM", scalingExp = rescalingExp)
- params['S'] = [max(j, MN + 1) for j in params['S']]
+ params['S'] = STensorized
elif sampling == "quadrature_total":
params['sampler'] = QST(murange, "CHEBYSHEV", scalingExp = rescalingExp)
- params['S'] = R
else: # if sampling == "random":
params['sampler'] = RS(murange, "HALTON", scalingExp = rescalingExp)
- params['S'] = R
elif samples == "centered":
params['sampler'] = MS(murange, points = [mu0], scalingExp = rescalingExp)
-elif samples in ["pivoted", "pole matching"]:
+elif samples == "pivoted":
if sampling == "quadrature":
params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "CHEBYSHEV")
# params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "GAUSSLEGENDRE")
# params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "UNIFORM")
elif sampling == "quadrature_total":
params['samplerPivot'] = QST([murange[0][0], murange[1][0]], "CHEBYSHEV")
else: # if sampling == "random":
params['samplerPivot'] = RS([murange[0][0], murange[1][0]], "HALTON")
if samplingM == "quadrature":
params['samplerMarginal'] = QS([murange[0][1], murange[1][1]], "UNIFORM")
elif samplingM == "quadrature_total":
params['samplerMarginal'] = QST([murange[0][1], murange[1][1]], "CHEBYSHEV")
else: # if samplingM == "random":
params['samplerMarginal'] = RS([murange[0][1], murange[1][1]], "HALTON")
-if samples not in ["pivoted", "pole matching"]:
+if samples != "pivoted":
approx = method(solver, mu0 = mu0, approxParameters = params,
verbosity = verb)
else:
approx = method(solver, mu0 = mu0, directionPivot = [0],
approxParameters = params, verbosity = verb)
-if samples != "centered": approx.samplingEngine.allowRepeatedSamples = False
approx.setupApprox()
if show_sample:
import ufl
import fenics as fen
from rrompy.solver.fenics import affine_warping
L = mutar[1]
y = fen.SpatialCoordinate(solver.V.mesh())[1]
warp1, warpI1 = affine_warping(solver.V.mesh(),
np.array([[1, 0], [0, 2. * L]]))
warp2, warpI2 = affine_warping(solver.V.mesh(),
np.array([[1, 0], [0, 2. - 2. * L]]))
warp = ufl.conditional(ufl.ge(y, 0.), warp1, warp2)
warpI = ufl.conditional(ufl.ge(y, 0.), warpI1, warpI2)
- approx.plotApprox(mutar, [warp, warpI], name = 'u_app',
- homogeneized = False, what = "REAL")
- approx.plotHF(mutar, [warp, warpI], name = 'u_HF',
- homogeneized = False, what = "REAL")
- approx.plotErr(mutar, [warp, warpI], name = 'err',
- homogeneized = False, what = "REAL")
-# approx.plotRes(mutar, [warp, warpI], name = 'res',
-# homogeneized = False, what = "REAL")
+ approx.plotApprox(mutar, [warp, warpI], name = 'u_app', what = "REAL")
+ approx.plotHF(mutar, [warp, warpI], name = 'u_HF', what = "REAL")
+ approx.plotErr(mutar, [warp, warpI], name = 'err', what = "REAL")
+# approx.plotRes(mutar, [warp, warpI], name = 'res', what = "REAL")
appErr = approx.normErr(mutar)
solNorm = approx.normHF(mutar)
resNorm = approx.normRes(mutar)
RHSNorm = approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
approx.verbosity = 5
-from plot_zero_set import plotZeroSet2
-muZeroVals, Qvals = plotZeroSet2(murange, murangeEff, approx, mu0,
- 200, [2., 1.])
+try:
+ from plot_zero_set import plotZeroSet2
+ muZeroVals, Qvals = plotZeroSet2(murange, murangeEff, approx, mu0,
+ 200, [2., 1.])
+except:
+ pass
if show_norm:
- solver._solveBatchSize = 100
from plot_inf_set import plotInfSet2
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet2(
- murange, murangeEff, approx, mu0, 50,
+ murange, murangeEff, approx, mu0, 25,
[2., 1.], relative = True,
nobeta = True)
-print(np.sort(approx.getPoles([None, .5]) ** 2.))
+try:
+ print(np.sort(approx.getPoles([None, .5]) ** 2.))
+except:
+ pass
diff --git a/examples/2d/pod/fracture_pod_nodomain.py b/examples/2d/pod/fracture_pod_nodomain.py
index f43decc..516dccd 100644
--- a/examples/2d/pod/fracture_pod_nodomain.py
+++ b/examples/2d/pod/fracture_pod_nodomain.py
@@ -1,172 +1,157 @@
import numpy as np
from rrompy.hfengines.linear_problem import MembraneFractureEngineNoDomain \
as MFEND
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
QuadratureSamplerTotal as QST,
ManualSampler as MS,
RandomSampler as RS)
verb = 5
size = 1
show_sample = True
show_norm = True
ignore_forcing = True
ignore_forcing = False
clip = -1
#clip = .4
#clip = .6
homogeneize = False
#homogeneize = True
Delta = 0
MN = 6
R = MN + 1
-S = R
samples = "centered"
samples = "standard"
algo = "rational"
#algo = "RB"
sampling = "quadrature"
sampling = "quadrature_total"
sampling = "random"
if samples == "standard":
- radial = 0
-# radial = "gaussian"
-# radial = "thinplate"
-# radial = "multiquadric"
+ radial = ""
+# radial = "_gaussian"
+# radial = "_thinplate"
+# radial = "_multiquadric"
radialWeight = [2.]
assert Delta <= 0
if size == 1: # below
mu0Aug = [40 ** .5, .4]
mu0 = mu0Aug[0]
mutar = 45 ** .5
murange = [[30 ** .5], [50 ** .5]]
elif size == 2: # top
mu0Aug = [40 ** .5, .6]
mu0 = mu0Aug[0]
mutar = 45 ** .5
murange = [[30 ** .5], [50 ** .5]]
elif size == 3: # interesting
mu0Aug = [40 ** .5, .5]
mu0 = mu0Aug[0]
mutar = 45 ** .5
murange = [[30 ** .5], [50 ** .5]]
elif size == 4: # wide_low
mu0Aug = [40 ** .5, .2]
mu0 = mu0Aug[0]
mutar = 45 ** .5
murange = [[10 ** .5], [70 ** .5]]
elif size == 5: # wide_hi
mu0Aug = [40 ** .5, .8]
mu0 = mu0Aug[0]
mutar = 45 ** .5
murange = [[10 ** .5], [70 ** .5]]
elif size == 6: # top_zoom
mu0Aug = [50 ** .5, .8]
mu0 = mu0Aug[0]
mutar = 55 ** .5
murange = [[40 ** .5], [60 ** .5]]
aEff = 1.#25
bEff = 1. - aEff
murangeEff = [[(aEff*murange[0][0]**2. + bEff*murange[1][0]**2.) ** .5],
[(aEff*murange[1][0]**2. + bEff*murange[0][0]**2.) ** .5]]
H = 1.
L = .75
delta = .05
n = 20
solver = MFEND(mu0 = mu0Aug, H = H, L = L, delta = delta, n = n,
- verbosity = verb)
+ verbosity = verb, homogeneized = homogeneize)
rescalingExp = 2.
if algo == "rational":
- params = {'N':MN, 'M':MN + Delta, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN + Delta, 'S':R, 'POD':True}
if samples == "standard":
- params['polybasis'] = "CHEBYSHEV"
-# params['polybasis'] = "LEGENDRE"
-# params['polybasis'] = "MONOMIAL"
- params['E'] = MN
- params['radialBasis'] = radial
- params['radialBasisWeights'] = radialWeight
+ params['polybasis'] = "CHEBYSHEV" + radial
+# params['polybasis'] = "LEGENDRE" + radial
+# params['polybasis'] = "MONOMIAL" + radial
+ params['radialDirectionalWeights'] = radialWeight
elif samples == "centered":
params['polybasis'] = "MONOMIAL"
- params['S'] = R
method = RI
else: #if algo == "RB":
- params = {'R':R, 'S':S, 'POD':True}
- if samples == "centered":
- params['S'] = R
+ params = {'R':R, 'S':R, 'POD':True}
method = RB
if samples == "standard":
if sampling == "quadrature":
params['sampler'] = QS(murange, "CHEBYSHEV", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "GAUSSLEGENDRE", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "UNIFORM", scalingExp = rescalingExp)
- params['S'] = [max(j, MN + 1) for j in params['S']]
elif sampling == "quadrature_total":
params['sampler'] = QST(murange, "CHEBYSHEV", scalingExp = rescalingExp)
- params['S'] = R
else: # if sampling == "random":
params['sampler'] = RS(murange, "HALTON", scalingExp = rescalingExp)
- params['S'] = R
elif samples == "centered":
params['sampler'] = MS(murange, points = [mu0], scalingExp = rescalingExp)
approx = method(solver, mu0 = mu0, approxParameters = params,
- verbosity = verb, homogeneized = homogeneize)
-if samples == "standard": approx.samplingEngine.allowRepeatedSamples = False
+ verbosity = verb)
approx.setupApprox()
if show_sample:
import ufl
import fenics as fen
from rrompy.solver.fenics import affine_warping
L = solver.lFrac
y = fen.SpatialCoordinate(solver.V.mesh())[1]
warp1, warpI1 = affine_warping(solver.V.mesh(),
np.array([[1, 0], [0, 2. * L]]))
warp2, warpI2 = affine_warping(solver.V.mesh(),
np.array([[1, 0], [0, 2. - 2. * L]]))
warp = ufl.conditional(ufl.ge(y, 0.), warp1, warp2)
warpI = ufl.conditional(ufl.ge(y, 0.), warpI1, warpI2)
- approx.plotApprox(mutar, [warp, warpI], name = 'u_app',
- homogeneized = False, what = "REAL")
- approx.plotHF(mutar, [warp, warpI], name = 'u_HF',
- homogeneized = False, what = "REAL")
- approx.plotErr(mutar, [warp, warpI], name = 'err',
- homogeneized = False, what = "REAL")
-# approx.plotRes(mutar, [warp, warpI], name = 'res',
-# homogeneized = False, what = "REAL")
- appErr = approx.normErr(mutar, homogeneized = homogeneize)
- solNorm = approx.normHF(mutar, homogeneized = homogeneize)
- resNorm = approx.normRes(mutar, homogeneized = homogeneize)
- RHSNorm = approx.normRHS(mutar, homogeneized = homogeneize)
+ approx.plotApprox(mutar, [warp, warpI], name = 'u_app', what = "REAL")
+ approx.plotHF(mutar, [warp, warpI], name = 'u_HF', what = "REAL")
+ approx.plotErr(mutar, [warp, warpI], name = 'err', what = "REAL")
+# approx.plotRes(mutar, [warp, warpI], name = 'res', what = "REAL")
+ appErr = approx.normErr(mutar)
+ solNorm = approx.normHF(mutar)
+ resNorm = approx.normRes(mutar)
+ RHSNorm = approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
if algo == "rational":
from plot_zero_set import plotZeroSet1
muZeroVals, Qvals = plotZeroSet1(murange, murangeEff, approx, mu0,
1000, 2.)
if show_norm:
- solver._solveBatchSize = 10
from plot_inf_set import plotInfSet1
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet1(
murange, murangeEff, approx, mu0,
200, 2., relative = False,
normalizeDen = True)
print(approx.getPoles() ** 2.)
diff --git a/examples/2d/pod/matrix_passive_pod.py b/examples/2d/pod/matrix_passive_pod.py
index 7d3e9d7..294c429 100644
--- a/examples/2d/pod/matrix_passive_pod.py
+++ b/examples/2d/pod/matrix_passive_pod.py
@@ -1,209 +1,191 @@
import numpy as np
from rrompy.hfengines.linear_problem.tridimensional import \
MatrixDynamicalPassive as MDP
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.reduction_methods.pivoted import RationalInterpolantPivoted as RIP
-from rrompy.reduction_methods.pivoted import ReducedBasisPivoted as RBP
-from rrompy.reduction_methods.pole_matching import \
- RationalInterpolantPoleMatching as RIPM
-from rrompy.reduction_methods.pole_matching import \
- ReducedBasisPoleMatching as RBPM
+#from rrompy.reduction_methods.pivoted import ReducedBasisPivoted as RBP
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
QuadratureSamplerTotal as QST,
ManualSampler as MS,
RandomSampler as RS)
verb = 10
size = 3
show_sample = True
show_norm = True
Delta = 0
-MN = 7
+MN = 5
R = (MN + 2) * (MN + 1) // 2
-S = [int(np.ceil(R ** .5))] * 2
+STensorized = (MN + 1) ** 2
PODTol = 1e-6
-SPivot = [MN + 1, 3]
-MMarginal = SPivot[1] - 1
+SPivot = MN + 1
+SMarginal = 3
+MMarginal = SMarginal - 1
samples = "centered"
samples = "standard"
samples = "pivoted"
-samples = "pole matching"
algo = "rational"
-#algo = "RB"
+algo = "RB"
sampling = "quadrature"
#sampling = "quadrature_total"
#sampling = "random"
samplingM = "quadrature"
#samplingM = "quadrature_total"
#samplingM = "random"
-if samples in ["standard", "pivoted", "pole matching"]:
- radial = 0
-# radial = "gaussian"
-# radial = "thinplate"
-# radial = "multiquadric"
+if samples in ["standard", "pivoted"]:
+ radial = ""
+# radial = "_gaussian"
+# radial = "_thinplate"
+# radial = "_multiquadric"
rW0 = 10.
radialWeight = [rW0]
-if samples in ["pivoted", "pole matching"]:
- radialM = 0
-# radialM = "gaussian"
-# radialM = "thinplate"
-# radialM = "multiquadric"
+if samples == "pivoted":
+ radialM = ""
+# radialM = "_gaussian"
+# radialM = "_thinplate"
+# radialM = "_multiquadric"
rMW0 = 2.
radialWeightM = [rMW0]
matchingWeight = 1.
cutOffTolerance = 5.
cutOffType = "POTENTIAL"
if size == 1:
mu0 = [2.7e2, 20]
mutar = [3e2, 25]
murange = [[20., 10], [5.2e2, 30]]
elif size == 2:
mu0 = [2.7e2, 60]
mutar = [3e2, 75]
murange = [[20., 10], [5.2e2, 110]]
elif size == 3:
mu0 = [2.7e2, 160]
mutar = [3e2, 105]
murange = [[20., 10], [5.2e2, 310]]
assert Delta <= 0
aEff = 1.#25
bEff = 1. - aEff
murangeEff = [[aEff*murange[0][0] + bEff*murange[1][0],
aEff*murange[0][1] + bEff*murange[1][1]],
[aEff*murange[1][0] + bEff*murange[0][0],
aEff*murange[1][1] + bEff*murange[0][1]]]
n = 100
b = 10
solver = MDP(mu0 = mu0, n = n, b = b, verbosity = verb)
if algo == "rational":
- params = {'N':MN, 'M':MN + Delta, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN + Delta, 'S':R, 'POD':True}
if samples == "standard":
- params['polybasis'] = "CHEBYSHEV"
-# params['polybasis'] = "LEGENDRE"
-# params['polybasis'] = "MONOMIAL"
- params['E'] = MN
- params['radialBasis'] = radial
- params['radialBasisWeights'] = radialWeight
+ params['polybasis'] = "CHEBYSHEV" + radial
+# params['polybasis'] = "LEGENDRE" + radial
+# params['polybasis'] = "MONOMIAL" + radial
+ params['radialDirectionalWeights'] = radialWeight * 2
method = RI
elif samples == "centered":
params['polybasis'] = "MONOMIAL"
- params['S'] = R
method = RI
- elif samples in ["pivoted", "pole matching"]:
- params['S'] = [SPivot[0]]
- params['SMarginal'] = [SPivot[1]]
+ elif samples == "pivoted":
+ params['S'] = SPivot
+ params['SMarginal'] = SMarginal
params['MMarginal'] = MMarginal
- params['polybasisPivot'] = "CHEBYSHEV"
- params['polybasisMarginal'] = "MONOMIAL"
- params['radialBasisPivot'] = radial
- params['radialBasisMarginal'] = radialM
- params['radialBasisWeightsPivot'] = radialWeight
- params['radialBasisWeightsMarginal'] = radialWeightM
- if samples == "pivoted":
- method = RIP
- else:
- params['matchingWeight'] = matchingWeight
- params['cutOffTolerance'] = cutOffTolerance
- params["cutOffType"] = cutOffType
- method = RIPM
+ params['polybasisPivot'] = "CHEBYSHEV" + radial
+ params['polybasisMarginal'] = "MONOMIAL" + radialM
+ params['radialDirectionalWeightsPivot'] = radialWeight
+ params['radialDirectionalWeightsMarginal'] = radialWeightM
+ params['matchingWeight'] = matchingWeight
+ params['cutOffTolerance'] = cutOffTolerance
+ params["cutOffType"] = cutOffType
+ method = RIP
else: #if algo == "RB":
- params = {'R':(MN + 2 + Delta) * (MN + 1 + Delta) // 2, 'S':S,
+ params = {'R':(MN + 2 + Delta) * (MN + 1 + Delta) // 2, 'S':R,
'POD':True, 'PODTolerance':PODTol}
if samples == "standard":
method = RB
elif samples == "centered":
- params['S'] = R
method = RB
- elif samples in ["pivoted", "pole matching"]:
- params['R'] = SPivot[0]
- params['S'] = [SPivot[0]]
- params['SMarginal'] = [SPivot[1]]
- params['MMarginal'] = MMarginal
- params['polybasisMarginal'] = "MONOMIAL"
- params['radialBasisMarginal'] = radialM
- params['radialBasisWeightsMarginal'] = radialWeightM
- if samples == "pivoted":
- method = RBP
- else:
- params['matchingWeight'] = matchingWeight
- params['cutOffTolerance'] = cutOffTolerance
- params["cutOffType"] = cutOffType
- method = RBPM
+ elif samples == "pivoted":
+ raise
+# params['R'] = SPivot
+# params['S'] = SPivot
+# params['SMarginal'] = SMarginal
+# params['MMarginal'] = MMarginal
+# params['polybasisMarginal'] = "MONOMIAL" + radialM
+# params['radialDirectionalWeightsMarginal'] = radialWeightM
+# params['matchingWeight'] = matchingWeight
+# params['cutOffTolerance'] = cutOffTolerance
+# params["cutOffType"] = cutOffType
+# method = RBP
if samples == "standard":
if sampling == "quadrature":
params['sampler'] = QS(murange, "CHEBYSHEV")
# params['sampler'] = QS(murange, "GAUSSLEGENDRE")
# params['sampler'] = QS(murange, "UNIFORM")
+ params["S"] = STensorized
elif sampling == "quadrature_total":
params['sampler'] = QST(murange, "CHEBYSHEV")
else: # if sampling == "random":
params['sampler'] = RS(murange, "HALTON")
elif samples == "centered":
params['sampler'] = MS(murange, points = [mu0])
-elif samples in ["pivoted", "pole matching"]:
+elif samples == "pivoted":
if sampling == "quadrature":
params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "CHEBYSHEV")
# params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "GAUSSLEGENDRE")
# params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "UNIFORM")
elif sampling == "quadrature_total":
params['samplerPivot'] = QST([murange[0][0], murange[1][0]], "CHEBYSHEV")
else: # if sampling == "random":
params['samplerPivot'] = RS([murange[0][0], murange[1][0]], "HALTON")
if samplingM == "quadrature":
params['samplerMarginal'] = QS([murange[0][1], murange[1][1]], "UNIFORM")
elif samplingM == "quadrature_total":
params['samplerMarginal'] = QST([murange[0][1], murange[1][1]], "CHEBYSHEV")
else: # if samplingM == "random":
params['samplerMarginal'] = RS([murange[0][1], murange[1][1]], "HALTON")
-if samples not in ["pivoted", "pole matching"]:
+if samples != "pivoted":
approx = method(solver, mu0 = mu0, approxParameters = params,
verbosity = verb)
else:
approx = method(solver, mu0 = mu0, directionPivot = [0],
approxParameters = params, verbosity = verb)
-if samples != "centered": approx.samplingEngine.allowRepeatedSamples = False
approx.setupApprox()
if show_sample:
L = mutar[1]
- approx.plotApprox(mutar, name = 'u_app', homogeneized = False,
- what = "REAL")
- approx.plotHF(mutar, name = 'u_HF', homogeneized = False, what = "REAL")
- approx.plotErr(mutar, name = 'err', homogeneized = False, what = "REAL")
-# approx.plotRes(mutar, name = 'res', homogeneized = False, what = "REAL")
+ approx.plotApprox(mutar, name = 'u_app', what = "REAL")
+ approx.plotHF(mutar, name = 'u_HF', what = "REAL")
+ approx.plotErr(mutar, name = 'err', what = "REAL")
+# approx.plotRes(mutar, name = 'res', what = "REAL")
appErr = approx.normErr(mutar)
solNorm = approx.normHF(mutar)
resNorm = approx.normRes(mutar)
RHSNorm = approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
try:
from plot_zero_set import plotZeroSet2
muZeroVals, Qvals = plotZeroSet2(murange, murangeEff, approx, mu0,
200, [1., 1], polesImTol = 2.)
except: pass
if show_norm:
- solver._solveBatchSize = 100
from plot_inf_set import plotInfSet2
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet2(
murange, murangeEff, approx, mu0, 50,
[1., 1.], relative = False,
nobeta = True)
print(1.j * approx.getPoles([None, 50.]))
diff --git a/examples/2d/pod/plot_inf_set.py b/examples/2d/pod/plot_inf_set.py
index d7ba227..a19285e 100644
--- a/examples/2d/pod/plot_inf_set.py
+++ b/examples/2d/pod/plot_inf_set.py
@@ -1,335 +1,362 @@
import warnings
import numpy as np
from matplotlib import pyplot as plt
def plotInfSet1FromData(mus, Z, T, R, E, beta, murange, approx, mu0,
exp = 2., normalizeDen = False):
if hasattr(approx, "mus"):
mu2x = approx.mus(0) ** exp
else:
mu2x = mu0[0] ** exp
murangeExp = [[murange[0][0] ** exp], [murange[1][0] ** exp]]
mu1 = np.real(np.power(mus, exp))
ZTmin, ZTmax = min(np.min(Z), np.min(T)), max(np.max(Z), np.max(T))
Rmin, Rmax = np.min(R), np.max(R)
Emin, Emax = np.min(E), np.max(E)
if not np.isnan(beta[0]):
eta = R / beta / E
betamin, betamax = np.min(beta), np.max(beta)
etamin, etamax = np.min(eta), np.max(eta)
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, Z)
plt.semilogy(mu1, T, '--')
for l_ in approx.trainedModel.getPoles():
plt.plot([np.real(l_ ** exp)] * 2, [ZTmin, ZTmax], 'b:')
plt.plot(np.real(mu2x), [ZTmin] * len(mu2x), 'kx')
+ for j, x in enumerate(np.real(mu2x)):
+ plt.annotate("{}".format(j), (x, ZTmin))
plt.plot([murangeExp[0][0]] * 2, [ZTmin, ZTmax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [ZTmin, ZTmax], 'm:')
plt.xlim(mu1[0], mu1[-1])
plt.title("|u(mu)|, |u_app(mu)|")
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, R)
for l_ in approx.trainedModel.getPoles():
plt.plot([np.real(l_ ** exp)] * 2, [Rmin, Rmax], 'b:')
plt.plot(np.real(mu2x), [Rmax] * len(mu2x), 'kx')
+ for j, x in enumerate(np.real(mu2x)):
+ plt.annotate("{}".format(j), (x, Rmax))
plt.plot([murangeExp[0][0]] * 2, [Rmin, Rmax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [Rmin, Rmax], 'm:')
plt.xlim(mu1[0], mu1[-1])
if normalizeDen:
plt.title("|Q(mu)res(mu)|")
else:
plt.title("|res(mu)|")
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, E)
for l_ in approx.trainedModel.getPoles():
plt.plot([np.real(l_ ** exp)] * 2, [Emin, Emax], 'b:')
plt.plot(np.real(mu2x), [Emax] * len(mu2x), 'kx')
+ for j, x in enumerate(np.real(mu2x)):
+ plt.annotate("{}".format(j), (x, Emax))
plt.plot([murangeExp[0][0]] * 2, [Emin, Emax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [Emin, Emax], 'm:')
plt.xlim(mu1[0], mu1[-1])
if normalizeDen:
plt.title("|Q(mu)err(mu)|")
else:
plt.title("|err(mu)|")
plt.grid()
plt.show()
if not np.isnan(beta[0]):
plt.figure(figsize = (15, 7))
plt.jet()
plt.plot(mu1, beta)
for l_ in approx.trainedModel.getPoles():
plt.plot([np.real(l_ ** exp)] * 2, [betamin, betamax], 'b:')
plt.plot(np.real(mu2x), [betamax] * len(mu2x), 'kx')
+ for j, x in enumerate(np.real(mu2x)):
+ plt.annotate("{}".format(j), (x, betamax))
plt.plot([murangeExp[0][0]] * 2, [betamin, betamax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [betamin, betamax], 'm:')
plt.xlim(mu1[0], mu1[-1])
plt.title("beta(mu)")
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, R / beta)
plt.semilogy(mu1, E, '--')
for l_ in approx.trainedModel.getPoles():
plt.plot([np.real(l_ ** exp)] * 2, [Emin, Emax], 'b:')
plt.plot(np.real(mu2x), [Emax] * len(mu2x), 'kx')
+ for j, x in enumerate(np.real(mu2x)):
+ plt.annotate("{}".format(j), (x, Emax))
plt.plot([murangeExp[0][0]] * 2, [Emin, Emax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [Emin, Emax], 'm:')
plt.xlim(mu1[0], mu1[-1])
if normalizeDen:
plt.title("|Q(mu)res(mu)/beta(mu)|")
else:
plt.title("|res(mu)/beta(mu)|")
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, eta)
for l_ in approx.trainedModel.getPoles():
plt.plot([np.real(l_ ** exp)] * 2, [etamin, etamax], 'b:')
plt.plot(np.real(mu2x), [etamax] * len(mu2x), 'kx')
+ for j, x in enumerate(np.real(mu2x)):
+ plt.annotate("{}".format(j), (x, etamax))
plt.plot([murangeExp[0][0]] * 2, [etamin, etamax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [etamin, etamax], 'm:')
plt.xlim(mu1[0], mu1[-1])
plt.title("eta(mu)")
plt.grid()
plt.show()
def plotInfSet1(murange, murangeEff, approx, mu0, nSamples = 20, exp = 2.,
relative = True, normalizeDen = False, nobeta = False):
mu1 = np.linspace(murangeEff[0][0] ** exp, murangeEff[1][0] ** exp,
nSamples)
mus = np.power(mu1, 1. / exp)
Z = approx.normHF(mus)
T = approx.normApprox(mus)
R = approx.normRes(mus)
E = approx.normErr(mus)
if relative:
F = approx.normRHS(mus)
R /= F
E /= Z
if normalizeDen:
Qvals = np.abs(approx.trainedModel.getQVal(mus))
R *= Qvals
E *= Qvals
if nobeta:
beta = np.empty(len(mus))
beta[:] = np.nan
else:
- beta = approx.HFEngine.stabilityFactor(approx.getHF(mus), mus)
+ beta = approx.HFEngine.stabilityFactor(mus, approx.getHF(mus))
plotInfSet1FromData(mus, Z, T, R, E, beta, murange, approx, mu0,
exp, normalizeDen)
return mus, Z, T, R, E, beta
def plotInfSet2FromData(mus, Ze, Te, Re, Ee, beta, murange, approx, mu0,
exps = [2., 2.], clip = -1, normalizeDen = False):
if hasattr(approx, "mus"):
mu2x, mu2y = approx.mus(0) ** exps[0], approx.mus(1) ** exps[1]
else:
mu2x, mu2y = mu0[0] ** exps[0], mu0[1] ** exps[1]
murangeExp = [[murange[0][0] ** exps[0], murange[0][1] ** exps[1]],
[murange[1][0] ** exps[0], murange[1][1] ** exps[1]]]
mu1s = np.unique([m[0] for m in mus])
mu2s = np.unique([m[1] for m in mus])
mu1 = np.power(mu1s, exps[0])
mu2 = np.power(mu2s, exps[1])
Mu1, Mu2 = np.meshgrid(np.real(mu1), np.real(mu2))
Z = np.log10(Ze)
T = np.log10(Te)
R = np.log10(Re)
E = np.log10(Ee)
ZTmin, ZTmax = min(np.min(Z), np.min(T)), max(np.max(Z), np.max(T))
Rmin, Rmax = np.min(R), np.max(R)
Emin, Emax = np.min(E), np.max(E)
if not np.isnan(beta[0, 0]):
betamin, betamax = np.min(beta), np.max(beta)
if clip > 0:
ZTmax -= clip * (ZTmax - ZTmin)
cmap = plt.cm.bone
else:
cmap = plt.cm.jet
- warnings.simplefilter("ignore", category = UserWarning)
+ warnings.simplefilter("ignore", category = (UserWarning,
+ np.ComplexWarning))
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, Z, cmap = cmap,
levels = np.linspace(ZTmin, ZTmax, 50))
if clip > 0:
plt.contour(Mu1, Mu2, Z, [ZTmin])
plt.plot(np.real(mu2x), np.real(mu2y), 'kx')
+ for j, xy in enumerate(zip(np.real(mu2x), np.real(mu2y))):
+ plt.annotate("{}".format(j), xy)
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
plt.colorbar(p)
plt.title("log10|u(mu)|")
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, T, cmap = cmap,
levels = np.linspace(ZTmin, ZTmax, 50))
if clip > 0:
plt.contour(Mu1, Mu2, T, [ZTmin])
plt.plot(np.real(mu2x), np.real(mu2y), 'kx')
+ for j, xy in enumerate(zip(np.real(mu2x), np.real(mu2y))):
+ plt.annotate("{}".format(j), xy)
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
plt.title("log10|u_app(mu)|")
plt.colorbar(p)
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, R, levels = np.linspace(Rmin, Rmax, 50))
plt.plot(np.real(mu2x), np.real(mu2y), 'kx')
+ for j, xy in enumerate(zip(np.real(mu2x), np.real(mu2y))):
+ plt.annotate("{}".format(j), xy)
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
if normalizeDen:
plt.title("log10|Q(mu)res(mu)|")
else:
plt.title("log10|res(mu)|")
plt.colorbar(p)
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, E, levels = np.linspace(Emin, Emax, 50))
plt.plot(np.real(mu2x), np.real(mu2y), 'kx')
+ for j, xy in enumerate(zip(np.real(mu2x), np.real(mu2y))):
+ plt.annotate("{}".format(j), xy)
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
if normalizeDen:
plt.title("log10|Q(mu)err(mu)|")
else:
plt.title("log10|err(mu)|")
plt.colorbar(p)
plt.grid()
plt.show()
if not np.isnan(beta[0, 0]):
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, beta,
levels = np.linspace(betamin, betamax, 50))
plt.plot(np.real(mu2x), np.real(mu2y), 'kx')
+ for j, xy in enumerate(zip(np.real(mu2x), np.real(mu2y))):
+ plt.annotate("{}".format(j), xy)
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
plt.title("beta(mu)")
plt.colorbar(p)
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, R - np.log10(beta),
levels = np.linspace(Emin, Emax, 50))
plt.plot(np.real(mu2x), np.real(mu2y), 'kx')
+ for j, xy in enumerate(zip(np.real(mu2x), np.real(mu2y))):
+ plt.annotate("{}".format(j), xy)
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
if normalizeDen:
plt.title("log10|Q(mu)res(mu)/beta(mu)|")
else:
plt.title("log10|res(mu)/beta(mu)|")
plt.colorbar(p)
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, R - np.log10(beta) - E, 50)
plt.plot(np.real(mu2x), np.real(mu2y), 'kx')
+ for j, xy in enumerate(zip(np.real(mu2x), np.real(mu2y))):
+ plt.annotate("{}".format(j), xy)
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
plt.title("log10|eta(mu)|")
plt.colorbar(p)
plt.grid()
plt.show()
def plotInfSet2(murange, murangeEff, approx, mu0, nSamples = 200,
exps = [2., 2.], clip = -1, relative = True,
normalizeDen = False, nobeta = False):
mu1 = np.linspace(murangeEff[0][0] ** exps[0], murangeEff[1][0] ** exps[0],
nSamples)
mu2 = np.linspace(murangeEff[0][1] ** exps[1], murangeEff[1][1] ** exps[1],
nSamples)
mu1s = np.power(mu1, 1. / exps[0])
mu2s = np.power(mu2, 1. / exps[1])
mus = [(m1, m2) for m2 in mu2s for m1 in mu1s]
Ze = approx.normHF(mus).reshape((nSamples, nSamples))
Te = approx.normApprox(mus).reshape((nSamples, nSamples))
Re = approx.normRes(mus).reshape((nSamples, nSamples))
Ee = approx.normErr(mus).reshape((nSamples, nSamples))
if relative:
Fe = approx.normRHS(mus).reshape((nSamples, nSamples))
Re /= Fe
Ee /= Ze
if normalizeDen:
Qvals = np.abs(approx.trainedModel.getQVal(mus).reshape(
(nSamples, nSamples)))
Re *= Qvals
Ee *= Qvals
if nobeta:
betae = np.empty((nSamples, nSamples))
betae[:, :] = np.nan
else:
- betae = approx.HFEngine.stabilityFactor(approx.getHF(mus), mus)\
+ betae = approx.HFEngine.stabilityFactor(mus, approx.getHF(mus))\
.reshape((nSamples, nSamples))
plotInfSet2FromData(mus, Ze, Te, Re, Ee, betae, murange,
approx, mu0, exps, clip, normalizeDen)
return mus, Ze, Te, Re, Ee, betae
diff --git a/examples/2d/pod/plot_zero_set.py b/examples/2d/pod/plot_zero_set.py
index 825bf66..ab58ee5 100644
--- a/examples/2d/pod/plot_zero_set.py
+++ b/examples/2d/pod/plot_zero_set.py
@@ -1,93 +1,108 @@
import warnings
import numpy as np
from matplotlib import pyplot as plt
def plotZeroSet1(murange, murangeEff, approx, mu0, nSamples = 200, exp = 2.):
if hasattr(approx, "mus"):
mu2x = approx.mus(0) ** exp
else:
mu2x = mu0[0] ** exp
murangeExp = [[murange[0][0] ** exp], [murange[1][0] ** exp]]
mu1 = np.linspace(murangeEff[0][0] ** exp, murangeEff[1][0] ** exp,
nSamples)
mus = np.power(mu1, 1. / exp)
mu1 = np.real(mu1)
- Z = approx.trainedModel.getQVal(mus)
- Zabs = np.abs(Z)
- Zmin, Zmax = np.min(Zabs), np.max(Zabs)
+ try:
+ Z = approx.trainedModel.getQVal(mus)
+ Zabs = np.abs(Z)
+ Zmin, Zmax = np.min(Zabs), np.max(Zabs)
+ except:
+ Z = None
+ Zmin, Zmax = 0., 1.
plt.figure(figsize = (15, 7))
plt.jet()
- plt.semilogy(mu1, Zabs)
+ if Z is not None:
+ plt.semilogy(mu1, Zabs)
for l_ in approx.trainedModel.getPoles():
plt.plot([np.real(l_ ** exp)] * 2, [Zmin, Zmax], 'b--')
plt.plot(mu2x, [Zmax] * len(mu2x), 'kx')
+ for j, x in enumerate(mu2x):
+ plt.annotate("{}".format(j), (x, Zmax))
plt.plot([murangeExp[0][0]] * 2, [Zmin, Zmax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [Zmin, Zmax], 'm:')
plt.xlim(mu1[0], mu1[-1])
plt.title("|Q(mu)|")
plt.grid()
plt.show()
return mus, Z
def plotZeroSet2(murange, murangeEff, approx, mu0, nSamples = 200,
exps = [2., 2.], clip = -1, polesImTol : float = 1e-5):
if hasattr(approx, "mus"):
mu2x, mu2y = approx.mus(0) ** exps[0], approx.mus(1) ** exps[1]
else:
mu2x, mu2y = mu0[0] ** exps[0], mu0[1] ** exps[1]
murangeExp = [[murange[0][0] ** exps[0], murange[0][1] ** exps[1]],
[murange[1][0] ** exps[0], murange[1][1] ** exps[1]]]
mu1 = np.linspace(murangeEff[0][0] ** exps[0], murangeEff[1][0] ** exps[0],
nSamples)
mu2 = np.linspace(murangeEff[0][1] ** exps[1], murangeEff[1][1] ** exps[1],
nSamples)
mu1s = np.power(mu1, 1. / exps[0])
mu2s = np.power(mu2, 1. / exps[1])
Mu1, Mu2 = np.meshgrid(np.real(mu1), np.real(mu2))
mus = [(m1, m2) for m2 in mu2s for m1 in mu1s]
poles1, poles2 = [], []
for m2 in mu2s:
- pls = approx.getPoles([None, m2]) ** exps[0]
+ pls = approx.getPoles([None, m2])
+ if pls is None:
+ poles1 = [None]
+ poles2 = [m2]
+ break
+ pls = pls ** exps[0]
pls[np.imag(pls) > polesImTol] = np.nan
pls = np.real(pls)
poles1 += list(pls)
poles2 += [m2] * len(pls)
try:
Z = approx.trainedModel.getQVal(mus).reshape(Mu1.shape)
Zabs = np.log10(np.abs(Z))
Zabsmin, Zabsmax = np.min(Zabs), np.max(Zabs)
if clip > 0:
Zabsmin += clip * (Zabsmax - Zabsmin)
cmap = plt.cm.bone_r
else:
cmap = plt.cm.jet
except:
Z = None
cmap = plt.cm.jet
- warnings.simplefilter("ignore", category = UserWarning)
+ warnings.simplefilter("ignore", category = (UserWarning,
+ np.ComplexWarning))
plt.figure(figsize = (15, 7))
plt.jet()
if Z is not None:
p = plt.contourf(Mu1, Mu2, Zabs, cmap = cmap,
levels = np.linspace(Zabsmin, Zabsmax, 50))
if clip > 0:
plt.contour(Mu1, Mu2, Zabs, [Zabsmin])
plt.plot(poles1, poles2, 'k.')
plt.plot(np.real(mu2x), np.real(mu2y), 'kx')
+ for j, xy in enumerate(zip(np.real(mu2x), np.real(mu2y))):
+ plt.annotate("{}".format(j), xy)
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
if Z is not None:
plt.colorbar(p)
plt.xlim(murangeExp[0][0], murangeExp[1][0])
plt.ylim(murangeExp[0][1], murangeExp[1][1])
plt.title("log10|Q(mu)|")
plt.grid()
plt.show()
return mus, Z
diff --git a/examples/2d/pod/square_pod.py b/examples/2d/pod/square_pod.py
index ecdb2f3..c089941 100644
--- a/examples/2d/pod/square_pod.py
+++ b/examples/2d/pod/square_pod.py
@@ -1,194 +1,190 @@
import numpy as np
from rrompy.hfengines.linear_problem.bidimensional import \
HelmholtzSquareDomainProblemEngine as HSDPE
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
-from rrompy.reduction_methods.pole_matching import \
- RationalInterpolantPoleMatching as RIPM
-from rrompy.reduction_methods.pole_matching import \
- ReducedBasisPoleMatching as RBPM
+from rrompy.reduction_methods.pivoted import RationalInterpolantPivoted as RIP
+#from rrompy.reduction_methods.pivoted import ReducedBasisPivoted as RBP
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
QuadratureSamplerTotal as QST,
ManualSampler as MS,
RandomSampler as RS)
verb = 5
-size = 7
+size = 6
show_sample = False
show_norm = True
ignore_forcing = True
ignore_forcing = False
clip = -1
#clip = .4
#clip = .6
MN = 6
R = (MN + 2) * (MN + 1) // 2
-S = [int(np.ceil(R ** .5))] * 2
-SPivot = [MN + 1, 3]
-MMarginal = SPivot[1] - 2
-matchingWeight = 10.
+STensorized = (MN + 1) ** 2
+PODTol = 1e-6
+SPivot = MN + 1
+SMarginal = 4
+MMarginal = SMarginal - 1
samples = "centered"
samples = "standard"
-samples = "pole matching"
+samples = "pivoted"
algo = "rational"
#algo = "RB"
sampling = "quadrature"
sampling = "quadrature_total"
#sampling = "random"
samplingM = "quadrature"
#samplingM = "quadrature_total"
#samplingM = "random"
-if samples == "pole matching":
- radialM = 0
- radialM = "gaussian"
-# radialM = "thinplate"
-# radialM = "multiquadric"
+if samples == "pivoted":
+ radialM = ""
+ radialM = "_gaussian"
+# radialM = "_thinplate"
+# radialM = "_multiquadric"
rMW0 = 2.
radialWeightM = [rMW0]
+ cutOffTolerance = 1. * np.inf
+ cutOffType = "MAGNITUDE"
+ matchingWeight = 10.
if size == 1: # small
mu0 = [4 ** .5, 1.5 ** .5]
mutar = [5 ** .5, 1.75 ** .5]
murange = [[2 ** .5, 1. ** .5], [6 ** .5, 2. ** .5]]
elif size == 2: # medium
mu0 = [4 ** .5, 1.75 ** .5]
mutar = [5 ** .5, 1.25 ** .5]
murange = [[1 ** .5, 1. ** .5], [7 ** .5, 2.5 ** .5]]
elif size == 3: # fat
mu0 = [6 ** .5, 4 ** .5]
mutar = [2 ** .5, 2.5 ** .5]
murange = [[0 ** .5, 2 ** .5], [12 ** .5, 6 ** .5]]
elif size == 4: # crowded
mu0 = [10 ** .5, 2 ** .5]
mutar = [9 ** .5, 2.25 ** .5]
murange = [[8 ** .5, 1.5 ** .5], [12 ** .5, 2.5 ** .5]]
elif size == 5: # tall
mu0 = [11 ** .5, 2.25 ** .5]
mutar = [10.5 ** .5, 2.5 ** .5]
murange = [[10 ** .5, 1.5 ** .5], [12 ** .5, 3 ** .5]]
elif size == 6: # taller
mu0 = [11 ** .5, 2.25 ** .5]
mutar = [10.5 ** .5, 2.5 ** .5]
murange = [[10 ** .5, 1.25 ** .5], [12 ** .5, 3.25 ** .5]]
elif size == 7: # low
mu0 = [7 ** .5, .75 ** .5]
mutar = [6.5 ** .5, .9 ** .5]
murange = [[6 ** .5, .5 ** .5], [8 ** .5, 1. ** .5]]
-aEff = 1.1
+aEff = 1.#1
bEff = 1. - aEff
murangeEff = [[(aEff*murange[0][0]**2. + bEff*murange[1][0]**2.) ** .5,
(aEff*murange[0][1]**2. + bEff*murange[1][1]**2.) ** .5],
[(aEff*murange[1][0]**2. + bEff*murange[0][0]**2.) ** .5,
(aEff*murange[1][1]**2. + bEff*murange[0][1]**2.) ** .5]]
solver = HSDPE(kappa = 2.5, theta = np.pi / 3, mu0 = mu0, n = 20,
verbosity = verb)
if ignore_forcing: solver.nbs = 1
rescalingExp = [2., 1.]
if algo == "rational":
- params = {'N':MN, 'M':MN, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN, 'S':R, 'POD':True}
if samples == "standard":
params['polybasis'] = "CHEBYSHEV"
# params['polybasis'] = "LEGENDRE"
# params['polybasis'] = "MONOMIAL"
- params['E'] = MN
method = RI
elif samples == "centered":
params['polybasis'] = "MONOMIAL"
- params['S'] = R
method = RI
- elif samples == "pole matching":
- params['S'] = [SPivot[0]]
- params['SMarginal'] = [SPivot[1]]
+ elif samples == "pivoted":
+ params['S'] = SPivot
+ params['SMarginal'] = SMarginal
params['MMarginal'] = MMarginal
params['polybasisPivot'] = "CHEBYSHEV"
- params['polybasisMarginal'] = "MONOMIAL"
+ params['polybasisMarginal'] = "MONOMIAL" + radialM
params['matchingWeight'] = matchingWeight
- params['radialBasisMarginal'] = radialM
- params['radialBasisWeightsMarginal'] = radialWeightM
- method = RIPM
+ params['radialDirectionalWeightsMarginal'] = radialWeightM
+ params['cutOffTolerance'] = cutOffTolerance
+ params["cutOffType"] = cutOffType
+ method = RIP
else: #if algo == "RB":
- params = {'R':R, 'S':S, 'POD':True}
- if samples == "standard":
- method = RB
- elif samples == "centered":
- params['S'] = R
+ params = {'R':R, 'S':R, 'POD':True}
+ if samples in ["standard", "centered"]:
method = RB
- elif samples == "pole matching":
- params['S'] = [SPivot[0]]
- params['SMarginal'] = [SPivot[1]]
- params['MMarginal'] = MMarginal
- params['polybasisMarginal'] = "MONOMIAL"
- params['matchingWeight'] = matchingWeight
- params['radialBasisMarginal'] = radialM
- params['radialBasisWeightsMarginal'] = radialWeightM
- method = RBPM
+ elif samples == "pivoted":
+ raise
+# params['S'] = SPivot
+# params['SMarginal'] = SMarginal
+# params['MMarginal'] = MMarginal
+# params['polybasisMarginal'] = "MONOMIAL" + radialM
+# params['matchingWeight'] = matchingWeight
+# params['radialDirectionalWeightsMarginal'] = radialWeightM
+# params['cutOffTolerance'] = cutOffTolerance
+# params["cutOffType"] = cutOffType
+# method = RBP
if samples == "standard":
if sampling == "quadrature":
params['sampler'] = QS(murange, "CHEBYSHEV", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "GAUSSLEGENDRE", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "UNIFORM", scalingExp = rescalingExp)
- params['S'] = [max(j, MN + 1) for j in params['S']]
+ params['S'] = STensorized
elif sampling == "quadrature_total":
params['sampler'] = QST(murange, "CHEBYSHEV", scalingExp = rescalingExp)
- params['S'] = R
else: # if sampling == "random":
params['sampler'] = RS(murange, "HALTON", scalingExp = rescalingExp)
- params['S'] = R
elif samples == "centered":
params['sampler'] = MS(murange, points = [mu0], scalingExp = rescalingExp)
-elif samples == "pole matching":
+elif samples == "pivoted":
if sampling == "quadrature":
params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "CHEBYSHEV")
# params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "GAUSSLEGENDRE")
# params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "UNIFORM")
elif sampling == "quadrature_total":
params['samplerPivot'] = QST([murange[0][0], murange[1][0]], "CHEBYSHEV")
else: # if sampling == "random":
params['samplerPivot'] = RS([murange[0][0], murange[1][0]], "HALTON")
if samplingM == "quadrature":
params['samplerMarginal'] = QS([murange[0][1], murange[1][1]], "UNIFORM")
elif samplingM == "quadrature_total":
params['samplerMarginal'] = QST([murange[0][1], murange[1][1]], "CHEBYSHEV")
else: # if samplingM == "random":
params['samplerMarginal'] = RS([murange[0][1], murange[1][1]], "HALTON")
-if samples != "pole matching":
+if samples != "pivoted":
approx = method(solver, mu0 = mu0, approxParameters = params,
verbosity = verb)
else:
approx = method(solver, mu0 = mu0, directionPivot = [0],
approxParameters = params, verbosity = verb)
-if samples != "centered": approx.samplingEngine.allowRepeatedSamples = False
approx.setupApprox()
if show_sample:
approx.plotApprox(mutar, name = 'u_app')
approx.plotHF(mutar, name = 'u_HF')
approx.plotErr(mutar, name = 'err')
approx.plotRes(mutar, name = 'res')
appErr, solNorm = approx.normErr(mutar), approx.normHF(mutar)
resNorm, RHSNorm = approx.normRes(mutar), approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
if algo == "rational":
from plot_zero_set import plotZeroSet2
muZeroVals, Qvals = plotZeroSet2(murange, murangeEff, approx, mu0,
200, [2., 1.])
if show_norm:
- solver._solveBatchSize = 100
from plot_inf_set import plotInfSet2
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet2(
murange, murangeEff, approx, mu0, 20, [2., 1.], clip = clip,
- relative = False, nobeta = True)
+ relative = True, nobeta = True)
diff --git a/examples/2d/pod/square_pod_hermite.py b/examples/2d/pod/square_pod_hermite.py
index 6a6bd23..e3d5851 100644
--- a/examples/2d/pod/square_pod_hermite.py
+++ b/examples/2d/pod/square_pod_hermite.py
@@ -1,95 +1,95 @@
import numpy as np
from rrompy.hfengines.linear_problem.bidimensional import \
HelmholtzSquareDomainProblemEngine as HSDPE
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
RandomSampler as RS,
ManualSampler as MS)
verb = 0
size = 1
show_sample = False
show_norm = True
MN = 4
R = (MN + 2) * (MN + 1) // 2
-S0 = [3] * 2
-S = [25]
-assert R < np.prod(S)
+MN0 = 2
+R0 = (MN0 + 2) * (MN0 + 1) // 2
+S0Tensorized = (MN0 + 1) ** 2
algo = "rational"
#algo = "RB"
sampling = "quadrature"
sampling = "random"
if size == 1: # small
mu0 = [4 ** .5, 1.5 ** .5]
mutar = [5 ** .5, 1.75 ** .5]
murange = [[2 ** .5, 1. ** .5], [6 ** .5, 2. ** .5]]
elif size == 2: # medium
mu0 = [4 ** .5, 1.75 ** .5]
mutar = [4.5 ** .5, 1.25 ** .5]
murange = [[1 ** .5, 1. ** .5], [7 ** .5, 2.5 ** .5]]
elif size == 3: # large
mu0 = [6 ** .5, 4 ** .5]
mutar = [2 ** .5, 2.5 ** .5]
murange = [[0 ** .5, 2 ** .5], [12 ** .5, 6 ** .5]]
elif size == 4: # crowded
mu0 = [10 ** .5, 2 ** .5]
mutar = [9 ** .5, 2.25 ** .5]
murange = [[8 ** .5, 1.5 ** .5], [12 ** .5, 2.5 ** .5]]
aEff = 1.25
bEff = 1. - aEff
murangeEff = [[(aEff*murange[0][0]**2. + bEff*murange[1][0]**2.) ** .5,
(aEff*murange[0][1]**2. + bEff*murange[1][1]**2.) ** .5],
[(aEff*murange[1][0]**2. + bEff*murange[0][0]**2.) ** .5,
(aEff*murange[1][1]**2. + bEff*murange[0][1]**2.) ** .5]]
solver = HSDPE(kappa = 2.5, theta = np.pi / 3, mu0 = mu0, n = 20,
verbosity = verb)
rescalingExp = [2., 1.]
if algo == "rational":
- params = {'N':MN, 'M':MN, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN, 'S':R, 'POD':True}
params['polybasis'] = "CHEBYSHEV"
method = RI
else: #if algo == "RB":
- params = {'R':R, 'S':S, 'POD':True}
+ params = {'R':R, 'S':R, 'POD':True}
method = RB
if sampling == "quadrature":
sampler0 = QS(murange, "CHEBYSHEV", scalingExp = rescalingExp)
+ S0 = S0Tensorized
else: # if sampling == "random":
sampler0 = RS(murange, "SOBOL", scalingExp = rescalingExp)
- S0 = np.prod(S0)
+ S0 = R0
params['sampler'] = MS(murange, points = sampler0.generatePoints(S0))
approx = method(solver, mu0 = mu0, approxParameters = params,
verbosity = verb)
approx.setupApprox()
if show_sample:
approx.plotApprox(mutar, name = 'u_app')
approx.plotHF(mutar, name = 'u_HF')
approx.plotErr(mutar, name = 'err')
approx.plotRes(mutar, name = 'res')
appErr, solNorm = approx.normErr(mutar), approx.normHF(mutar)
resNorm, RHSNorm = approx.normRes(mutar), approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
if algo == "rational":
from plot_zero_set import plotZeroSet2
muZeroVals, Qvals = plotZeroSet2(murange, murangeEff, approx, mu0,
200, [2., 2.])
if show_norm:
- solver._solveBatchSize = 100
from plot_inf_set import plotInfSet2
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet2(
murange, murangeEff, approx, mu0, 25, [2., 2.])
diff --git a/examples/2d/pod/square_simplified_pod.py b/examples/2d/pod/square_simplified_pod.py
index 8273c12..0b3bde9 100644
--- a/examples/2d/pod/square_simplified_pod.py
+++ b/examples/2d/pod/square_simplified_pod.py
@@ -1,127 +1,120 @@
import numpy as np
from rrompy.hfengines.linear_problem.bidimensional import \
HelmholtzSquareSimplifiedDomainProblemEngine as HSSDPE
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
QuadratureSamplerTotal as QST,
ManualSampler as MS,
RandomSampler as RS)
verb = 5
size = 1
show_sample = False
show_norm = True
MN = 5
R = (MN + 2) * (MN + 1) // 2
-S = [int(np.ceil(R ** .5))] * 2
+STensorized = (MN + 1) ** 2
samples = "centered"
samples = "standard"
algo = "rational"
#algo = "RB"
sampling = "quadrature"
sampling = "quadrature_total"
sampling = "random"
if size == 1: # small
mu0 = [4 ** .5, 1.5 ** .5]
mutar = [5 ** .5, 1.75 ** .5]
murange = [[2 ** .5, 1. ** .5], [6 ** .5, 2. ** .5]]
elif size == 2: # medium
mu0 = [4 ** .5, 1.75 ** .5]
mutar = [5 ** .5, 1.25 ** .5]
murange = [[1 ** .5, 1. ** .5], [7 ** .5, 2.5 ** .5]]
elif size == 3: # fat
mu0 = [6 ** .5, 4 ** .5]
mutar = [2 ** .5, 2.5 ** .5]
murange = [[0 ** .5, 2 ** .5], [12 ** .5, 6 ** .5]]
elif size == 4: # crowded
mu0 = [10 ** .5, 2 ** .5]
mutar = [9 ** .5, 2.25 ** .5]
murange = [[8 ** .5, 1.5 ** .5], [12 ** .5, 2.5 ** .5]]
elif size == 5: # tall
mu0 = [11 ** .5, 2.25 ** .5]
mutar = [10.5 ** .5, 2.5 ** .5]
murange = [[10 ** .5, 1.5 ** .5], [12 ** .5, 3 ** .5]]
elif size == 6: # taller
mu0 = [11 ** .5, 2.25 ** .5]
mutar = [10.5 ** .5, 2.5 ** .5]
murange = [[10 ** .5, 1.25 ** .5], [12 ** .5, 3.25 ** .5]]
elif size == 7: # low
mu0 = [7 ** .5, .75 ** .5]
mutar = [8 ** .5, 1 ** .5]
murange = [[6 ** .5, .25 ** .5], [8 ** .5, 1.25 ** .5]]
aEff = 1.25
bEff = 1. - aEff
murangeEff = [[(aEff*murange[0][0]**2. + bEff*murange[1][0]**2.) ** .5,
(aEff*murange[0][1]**2. + bEff*murange[1][1]**2.) ** .5],
[(aEff*murange[1][0]**2. + bEff*murange[0][0]**2.) ** .5,
(aEff*murange[1][1]**2. + bEff*murange[0][1]**2.) ** .5]]
solver = HSSDPE(kappa = 2.5, theta = np.pi / 3, mu0 = mu0, n = 20,
verbosity = verb)
rescalingExp = [2.] * 2
if algo == "rational":
- params = {'N':MN, 'M':MN, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN, 'S':R, 'POD':True}
if samples == "standard":
params['polybasis'] = "CHEBYSHEV"
params['polybasis'] = "LEGENDRE"
params['polybasis'] = "MONOMIAL"
- params['E'] = MN
elif samples == "centered":
params['polybasis'] = "MONOMIAL"
- params['S'] = R
method = RI
else: #if algo == "RB":
- params = {'R':R, 'S':S, 'POD':True}
- if samples == "centered":
- params['S'] = R
+ params = {'R':R, 'S':R, 'POD':True}
method = RB
if samples == "standard":
if sampling == "quadrature":
params['sampler'] = QS(murange, "CHEBYSHEV", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "GAUSSLEGENDRE", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "UNIFORM", scalingExp = rescalingExp)
- params['S'] = [max(j, MN + 1) for j in params['S']]
+ params['S'] = STensorized
elif sampling == "quadrature_total":
params['sampler'] = QST(murange, "CHEBYSHEV", scalingExp = rescalingExp)
- params['S'] = R
else: # if sampling == "random":
params['sampler'] = RS(murange, "HALTON", scalingExp = rescalingExp)
- params['S'] = R
elif samples == "centered":
params['sampler'] = MS(murange, points = [mu0], scalingExp = rescalingExp)
approx = method(solver, mu0 = mu0, approxParameters = params,
verbosity = verb)
approx.setupApprox()
if show_sample:
approx.plotApprox(mutar, name = 'u_app')
approx.plotHF(mutar, name = 'u_HF')
approx.plotErr(mutar, name = 'err')
approx.plotRes(mutar, name = 'res')
appErr, solNorm = approx.normErr(mutar), approx.normHF(mutar)
resNorm, RHSNorm = approx.normRes(mutar), approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
if algo == "rational":
from plot_zero_set import plotZeroSet2
muZeroVals, Qvals = plotZeroSet2(murange, murangeEff, approx, mu0,
200, [2., 2.])
if show_norm:
- solver._solveBatchSize = 100
from plot_inf_set import plotInfSet2
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet2(
murange, murangeEff, approx, mu0, 25, [2., 2.])
diff --git a/examples/2d/pod/square_simplified_pod_hermite.py b/examples/2d/pod/square_simplified_pod_hermite.py
index 3257756..69b0bb4 100644
--- a/examples/2d/pod/square_simplified_pod_hermite.py
+++ b/examples/2d/pod/square_simplified_pod_hermite.py
@@ -1,95 +1,95 @@
import numpy as np
from rrompy.hfengines.linear_problem.bidimensional import \
HelmholtzSquareSimplifiedDomainProblemEngine as HSSDPE
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
RandomSampler as RS,
ManualSampler as MS)
verb = 0
size = 1
show_sample = False
show_norm = True
MN = 4
R = (MN + 2) * (MN + 1) // 2
-S0 = [3] * 2
-S = [25]
-assert R < np.prod(S)
+MN0 = 2
+R0 = (MN0 + 2) * (MN0 + 1) // 2
+S0Tensorized = (MN0 + 1) ** 2
algo = "rational"
#algo = "RB"
sampling = "quadrature"
#sampling = "random"
if size == 1: # small
mu0 = [4 ** .5, 1.5 ** .5]
mutar = [5 ** .5, 1.75 ** .5]
murange = [[2 ** .5, 1. ** .5], [6 ** .5, 2. ** .5]]
elif size == 2: # medium
mu0 = [4 ** .5, 1.75 ** .5]
mutar = [4.5 ** .5, 1.25 ** .5]
murange = [[1 ** .5, 1. ** .5], [7 ** .5, 2.5 ** .5]]
elif size == 3: # large
mu0 = [6 ** .5, 4 ** .5]
mutar = [2 ** .5, 2.5 ** .5]
murange = [[0 ** .5, 2 ** .5], [12 ** .5, 6 ** .5]]
elif size == 4: # crowded
mu0 = [10 ** .5, 2 ** .5]
mutar = [9 ** .5, 2.25 ** .5]
murange = [[8 ** .5, 1.5 ** .5], [12 ** .5, 2.5 ** .5]]
aEff = 1.25
bEff = 1. - aEff
murangeEff = [[(aEff*murange[0][0]**2. + bEff*murange[1][0]**2.) ** .5,
(aEff*murange[0][1]**2. + bEff*murange[1][1]**2.) ** .5],
[(aEff*murange[1][0]**2. + bEff*murange[0][0]**2.) ** .5,
(aEff*murange[1][1]**2. + bEff*murange[0][1]**2.) ** .5]]
solver = HSSDPE(kappa = 2.5, theta = np.pi / 3, mu0 = mu0, n = 20,
verbosity = verb)
rescalingExp = [2.] * 2
if algo == "rational":
- params = {'N':MN, 'M':MN, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN, 'S':R, 'POD':True}
params['polybasis'] = "CHEBYSHEV"
method = RI
else: #if algo == "RB":
- params = {'R':R, 'S':S, 'POD':True}
+ params = {'R':R, 'S':R, 'POD':True}
method = RB
if sampling == "quadrature":
sampler0 = QS(murange, "CHEBYSHEV", scalingExp = rescalingExp)
+ S0 = S0Tensorized
else: # if sampling == "random":
sampler0 = RS(murange, "SOBOL", scalingExp = rescalingExp)
- S0 = np.prod(S0)
+ S0 = R0
params['sampler'] = MS(murange, points = sampler0.generatePoints(S0))
approx = method(solver, mu0 = mu0, approxParameters = params,
verbosity = verb)
approx.setupApprox()
if show_sample:
approx.plotApprox(mutar, name = 'u_app')
approx.plotHF(mutar, name = 'u_HF')
approx.plotErr(mutar, name = 'err')
approx.plotRes(mutar, name = 'res')
appErr, solNorm = approx.normErr(mutar), approx.normHF(mutar)
resNorm, RHSNorm = approx.normRes(mutar), approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
if algo == "rational":
from plot_zero_set import plotZeroSet2
muZeroVals, Qvals = plotZeroSet2(murange, murangeEff, approx, mu0,
200, [2., 2.])
if show_norm:
- solver._solveBatchSize = 100
from plot_inf_set import plotInfSet2
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet2(
murange, murangeEff, approx, mu0, 50, [2., 2.])
diff --git a/examples/2d/pod/synthetic_pod.py b/examples/2d/pod/synthetic_pod.py
index b91fc84..074169d 100644
--- a/examples/2d/pod/synthetic_pod.py
+++ b/examples/2d/pod/synthetic_pod.py
@@ -1,140 +1,129 @@
import numpy as np
from rrompy.hfengines.linear_problem.bidimensional import \
SyntheticBivariateEngine as SBE
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
QuadratureSamplerTotal as QST,
ManualSampler as MS,
RandomSampler as RS)
verb = 5
size = 1
show_sample = True
show_norm = True
clip = -1
#clip = .4
#clip = .6
Delta = 0
MN = 10
R = (MN + 2) * (MN + 1) // 2
-S = [int(np.ceil(R ** .5))] * 2
+STensorized = (MN + 1) ** 2
PODTol = 1e-6
samples = "centered"
samples = "standard"
algo = "rational"
#algo = "RB"
sampling = "quadrature"
#sampling = "quadrature_total"
#sampling = "random"
if samples == "standard":
- radial = 0
- radial = "gaussian"
-# radial = "thinplate"
-# radial = "multiquadric"
+ radial = ""
+ radial = "_gaussian"
+# radial = "_thinplate"
+# radial = "_multiquadric"
rW0 = 10.
radialWeight = [rW0] * 2
if size == 1: # small
mu0 = [10. ** .5, 15. ** .5]
mutar = [12. ** .5, 14. ** .5]
murange = [[5. ** .5, 10. ** .5], [15 ** .5, 20 ** .5]]
if size == 2: # large
mu0 = [15. ** .5, 17.5 ** .5]
mutar = [18. ** .5, 22. ** .5]
murange = [[5. ** .5, 10. ** .5], [25 ** .5, 25 ** .5]]
if size == 3: # medium
mu0 = [17.5 ** .5, 15 ** .5]
mutar = [20. ** .5, 18. ** .5]
murange = [[10. ** .5, 10. ** .5], [25 ** .5, 20 ** .5]]
assert Delta <= 0
aEff = 1.#25
bEff = 1. - aEff
murangeEff = [[(aEff*murange[0][0]**2. + bEff*murange[1][0]**2.) ** .5,
aEff*murange[0][1] + bEff*murange[1][1]],
[(aEff*murange[1][0]**2. + bEff*murange[0][0]**2.) ** .5,
aEff*murange[1][1] + bEff*murange[0][1]]]
kappa = 20. ** .5
theta = - np.pi / 6.
n = 20
L = np.pi
solver = SBE(kappa = kappa, theta = theta, n = n, L = L,
mu0 = mu0, verbosity = verb)
rescalingExp = [2.] * 2
if algo == "rational":
- params = {'N':MN, 'M':MN + Delta, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN + Delta, 'S':R, 'POD':True}
if samples == "standard":
- params['polybasis'] = "CHEBYSHEV"
-# params['polybasis'] = "LEGENDRE"
-# params['polybasis'] = "MONOMIAL"
- params['E'] = MN
- params['radialBasis'] = radial
- params['radialBasisWeights'] = radialWeight
+ params['polybasis'] = "CHEBYSHEV" + radial
+# params['polybasis'] = "LEGENDRE" + radial
+# params['polybasis'] = "MONOMIAL" + radial
+ params['radialDirectionalWeights'] = radialWeight
method = RI
elif samples == "centered":
params['polybasis'] = "MONOMIAL"
- params['S'] = R
method = RI
else: #if algo == "RB":
- params = {'R':(MN + 2 + Delta) * (MN + 1 + Delta) // 2, 'S':S,
+ params = {'R':(MN + 2 + Delta) * (MN + 1 + Delta) // 2, 'S':R,
'POD':True, 'PODTolerance':PODTol}
- if samples == "centered":
- params['S'] = R
method = RB
if samples == "standard":
if sampling == "quadrature":
params['sampler'] = QS(murange, "CHEBYSHEV", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "GAUSSLEGENDRE", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "UNIFORM", scalingExp = rescalingExp)
- params['S'] = [max(j, MN + 1) for j in params['S']]
+ params['S'] = STensorized
elif sampling == "quadrature_total":
params['sampler'] = QST(murange, "CHEBYSHEV", scalingExp = rescalingExp)
- params['S'] = R
else: # if sampling == "random":
params['sampler'] = RS(murange, "HALTON", scalingExp = rescalingExp)
- params['S'] = R
-
elif samples == "centered":
params['sampler'] = MS(murange, points = [mu0], scalingExp = rescalingExp)
approx = method(solver, mu0 = mu0, approxParameters = params, verbosity = verb)
-if samples == "standard": approx.samplingEngine.allowRepeatedSamples = False
approx.setupApprox()
if show_sample:
L = mutar[1]
- approx.plotApprox(mutar, name = 'u_app', homogeneized = False,
- what = "REAL")
- approx.plotHF(mutar, name = 'u_HF', homogeneized = False, what = "REAL")
- approx.plotErr(mutar, name = 'err', homogeneized = False, what = "REAL")
-# approx.plotRes(mutar, name = 'res', homogeneized = False, what = "REAL")
+ approx.plotApprox(mutar, name = 'u_app', what = "REAL")
+ approx.plotHF(mutar, name = 'u_HF', what = "REAL")
+ approx.plotErr(mutar, name = 'err', what = "REAL")
+# approx.plotRes(mutar, name = 'res', what = "REAL")
appErr = approx.normErr(mutar)
solNorm = approx.normHF(mutar)
resNorm = approx.normRes(mutar)
RHSNorm = approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
if algo == "rational" and approx.N > 0:
from plot_zero_set import plotZeroSet2
muZeroVals, Qvals = plotZeroSet2(murange, murangeEff, approx, mu0,
200, [2., 2.], clip = clip)
if show_norm:
- solver._solveBatchSize = 100
from plot_inf_set import plotInfSet2
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet2(
murange, murangeEff, approx, mu0, 50,
[2., 2.], clip = clip, relative = False)
diff --git a/examples/3d/base/fracture3.py b/examples/3d/base/fracture3.py
index 02f4a18..13b6a32 100644
--- a/examples/3d/base/fracture3.py
+++ b/examples/3d/base/fracture3.py
@@ -1,35 +1,35 @@
from rrompy.hfengines.linear_problem.tridimensional import \
MembraneFractureEngine3 as MFE
from fracture3_warping import fracture3_warping
verb = 100
mu0 = [45. ** .5, .7, .075]
H = 1.
L = .75
delta = .05
n = 50
solver = MFE(mu0 = mu0, H = H, L = L, delta = delta,
n = n, verbosity = verb)
-u0 = solver.liftDirichletData(mu0)
+u0 = solver.liftDirichletData()
uh = solver.solve(mu0)[0]
#solver.plotmesh(figsize = (7.5, 4.5))
#solver.plot(u0, what = 'REAL', figsize = (8, 5))
print(solver.norm(uh))
#solver.plot(uh, what = 'REAL', figsize = (8, 5))
-#solver.plot(solver.residual(uh, mu0)[0], name = 'res',
+#solver.plot(solver.residual(mu0, uh)[0], name = 'res',
# what = 'REAL', figsize = (8, 5))
#solver.outParaviewTimeDomain(uh, mu0[0], filename = 'out', folder = True,
# forceNewFile = False)
warps = fracture3_warping(solver.V.mesh(), L, mu0[1], delta, mu0[2])
#solver.plotmesh(warps, figsize = (7.5, 4.5))
#solver.plot(u0, warps, what = 'REAL', figsize = (8, 5))
solver.plot(uh, warps, what = 'REAL', figsize = (8, 5))
-#solver.plot(solver.residual(uh, mu0)[0], warps, name = 'res',
+#solver.plot(solver.residual(mu0, uh)[0], warps, name = 'res',
# what = 'REAL', figsize = (8, 5))
#solver.outParaviewTimeDomain(uh, mu0[0], warps, filename = 'outW',
# folder = True, forceNewFile = False)
diff --git a/examples/3d/base/matrix_3.py b/examples/3d/base/matrix_3.py
index dce8d7b..6f885e6 100644
--- a/examples/3d/base/matrix_3.py
+++ b/examples/3d/base/matrix_3.py
@@ -1,74 +1,77 @@
import scipy.sparse as sp
import numpy as np
from rrompy.hfengines.base import MatrixEngineBase as MEB
verb = 100
deg = 2
N = 150
exp = 1.05
assert exp > 1.
empty = sp.csr_matrix((np.zeros(0), np.zeros(0), np.zeros(N + 1)),
shape = (N, N))
solver = MEB(verbosity = verb)
solver.npar = 3
A0 = sp.spdiags([np.arange(1, 1 + 2 * N, 2) ** exp - (2 * (N // 4)) ** exp],
[0], N, N)
if deg == 1:
solver.nAs = 4
solver.As = [A0, sp.eye(N), - sp.eye(N), - sp.eye(N)]
elif deg == 2:
solver.nAs = 7
solver.As = ([A0] + [empty] + [- sp.eye(N)] + [empty] * 3 + [sp.eye(N)])
elif deg == 3:
solver.nAs = 13
solver.As = ([A0] + [empty] + [- sp.eye(N)] + [empty] * 9 + [sp.eye(N)])
np.random.seed(420)
solver.nbs = 1
solver.bs = [np.random.randn(N) + 1.j * np.random.randn(N)]
+solver._affinePoly = True
+solver.thAs = solver.getMonomialWeights(solver.nAs)
+solver.thbs = solver.getMonomialWeights(solver.nbs)
mu0 = [.8, 0., .2]
uh = solver.solve(mu0)[0]
solver.plot(uh, what = 'REAL', figsize = (8, 5))
murange = np.linspace(-1., 1., 20)
Mu1, Mu2, Mu3 = np.meshgrid(murange, murange, murange, indexing = 'ij')
mus = []
if deg == 1:
f = Mu1 - Mu2 - Mu3
elif deg == 2:
f = Mu1 * Mu3 - Mu2
elif deg == 3:
f = Mu3 * Mu1**2 - Mu2
from matplotlib import pyplot as plt
pts = []
for jdir in range(len(Mu3)):
z = Mu3[0, 0, jdir]
xis, yis, fis = Mu1[:, :, jdir], Mu2[:, :, jdir], f[:, :, jdir]
plt.figure()
CS = plt.contour(xis, yis, np.real(fis), levels = [0.])
plt.close()
for i, CSc in enumerate(CS.allsegs):
if np.isclose(CS.cvalues[i], 0.):
for j, CScj in enumerate(CSc):
for k in range(len(CScj)):
pts += [[CScj[k, 0], CScj[k, 1], z]]
pts += [[np.nan] * 3]
pts = np.array(pts)
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize = (8, 6))
ax = Axes3D(fig)
ax.plot(pts[:, 0], pts[:, 1], pts[:, 2], 'k-')
ax.set_xlim(-1., 1.)
ax.set_ylim(-1., 1.)
ax.set_zlim(-1., 1.)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.show()
plt.close()
diff --git a/examples/3d/base/scattering1.py b/examples/3d/base/scattering1.py
index 0124267..f9a0c2d 100644
--- a/examples/3d/base/scattering1.py
+++ b/examples/3d/base/scattering1.py
@@ -1,29 +1,29 @@
from rrompy.hfengines.linear_problem.tridimensional import Scattering1d as S1D
import fenics as fen
import numpy as np
verb = 100
mu0 = [4., np.pi, 0.]
mu = [4.5, np.pi, 1.]
n = 100
solver = S1D(mu0 = mu0, n = n, verbosity = verb)
-u0 = solver.liftDirichletData(mu0)
+u0 = solver.liftDirichletData()
uh = solver.solve(mu)[0]
#solver.plotmesh(figsize = (12, 2))
#solver.plot(u0, what = ['REAL', 'IMAG'], figsize = (12, 4))
print(solver.norm(uh))
#solver.plot(uh, what = ['REAL', 'IMAG'], figsize = (12, 4))
-#solver.plot(solver.residual(uh, mu0)[0], name = 'res',
+#solver.plot(solver.residual(mu0, uh)[0], name = 'res',
# what = ['REAL', 'IMAG'], figsize = (12, 4))
x = fen.SpatialCoordinate(solver.V.mesh())
warps = [x * mu[1] / solver._L - x, x * solver._L / mu[1] - x]
#solver.plotmesh(warps, figsize = (12, 2))
#solver.plot(u0, warps, what = ['REAL', 'IMAG'], figsize = (12, 4))
solver.plot(uh, warps, what = ['REAL', 'IMAG'], figsize = (12, 4))
-#solver.plot(solver.residual(uh, mu0)[0], warps, name = 'res',
+#solver.plot(solver.residual(mu0, uh)[0], warps, name = 'res',
# what = ['REAL', 'IMAG'], figsize = (12, 4))
diff --git a/examples/3d/pod/fracture3_pod.py b/examples/3d/pod/fracture3_pod.py
index 802dca1..a4e4b74 100644
--- a/examples/3d/pod/fracture3_pod.py
+++ b/examples/3d/pod/fracture3_pod.py
@@ -1,253 +1,241 @@
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
from rrompy.hfengines.linear_problem.tridimensional import \
MembraneFractureEngine3 as MFE
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
-from rrompy.reduction_methods.pole_matching import \
- RationalInterpolantPoleMatching as RIPM
-from rrompy.reduction_methods.pole_matching import \
- ReducedBasisPoleMatching as RBPM
+from rrompy.reduction_methods.pivoted import RationalInterpolantPivoted as RIP
+#from rrompy.reduction_methods.pivoted import ReducedBasisPivoted as RBP
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
QuadratureSamplerTotal as QST,
ManualSampler as MS,
RandomSampler as RS)
verb = 70
size = 4
show_sample = False
show_norm = False
clip = -1
#clip = .4
#clip = .6
Delta = 0
MN = 5
R = (MN + 3) * (MN + 2) * (MN + 1) // 6
-S = [int(np.ceil(R ** (1. / 3.)))] * 3
+STensorized = (MN + 1) ** 3
PODTol = 1e-8
-SPivot = [MN + 1, 2, 2]
-MMarginal = SPivot[1] - 1
+SPivot = MN + 1
+SMarg1d = 5
+MMarginal = SMarg1d - 1
+SMarginal = (MMarginal + 2) * (MMarginal + 1) // 2
+SMarginalTensorized = SMarg1d ** 2
matchingWeight = 10.
samples = "centered"
samples = "standard"
-samples = "pole matching"
+#samples = "pivoted"
algo = "rational"
#algo = "RB"
sampling = "quadrature"
-sampling = "quadrature_total"
+#sampling = "quadrature_total"
#sampling = "random"
samplingM = "quadrature"
-#samplingM = "quadrature_total"
+samplingM = "quadrature_total"
#samplingM = "random"
+polydegreetype = "TOTAL"
+#polydegreetype = "FULL"
if samples == "standard":
- radial = 0
- radial = "gaussian"
-# radial = "thinplate"
-# radial = "multiquadric"
+ radial = ""
+# radial = "_gaussian"
+# radial = "_thinplate"
+# radial = "_multiquadric"
rW0 = 5.
radialWeight = [rW0] * 3
-if samples == "pole matching":
- radial = 0
-# radial = "gaussian"
-# radial = "thinplate"
-# radial = "multiquadric"
+if samples == "pivoted":
+ radial = ""
+# radial = "_gaussian"
+# radial = "_thinplate"
+# radial = "_multiquadric"
rW0 = 5.
radialWeight = [rW0]
- radialM = 0
- radialM = "gaussian"
-# radialM = "thinplate"
-# radialM = "multiquadric"
+ radialM = ""
+# radialM = "_gaussian"
+# radialM = "_thinplate"
+# radialM = "_multiquadric"
rMW0 = 2.
radialWeightM = [rMW0] * 2
assert Delta <= 0
if size == 1:
mu0 = [47.5 ** .5, .4, .05]
mutar = [50 ** .5, .45, .07]
murange = [[40 ** .5, .3, .025], [55 ** .5, .5, .075]]
if size == 2:
mu0 = [50 ** .5, .3, .02]
mutar = [55 ** .5, .4, .03]
murange = [[40 ** .5, .1, .005], [60 ** .5, .5, .035]]
if size == 3:
mu0 = [45 ** .5, .5, .05]
mutar = [47 ** .5, .4, .045]
murange = [[40 ** .5, .3, .04], [50 ** .5, .7, .06]]
if size == 4:
mu0 = [45 ** .5, .4, .05]
mutar = [47 ** .5, .45, .045]
murange = [[40 ** .5, .3, .04], [50 ** .5, .5, .06]]
+if size == 5:
+ mu0 = [45 ** .5, .5, .05]
+ mutar = [47 ** .5, .45, .045]
+ murange = [[40 ** .5, .3, .04], [50 ** .5, .7, .06]]
aEff = 1.#25
bEff = 1. - aEff
murangeEff = [[(aEff*murange[0][0]**2. + bEff*murange[1][0]**2.) ** .5,
aEff*murange[0][1] + bEff*murange[1][1],
aEff*murange[0][2] + bEff*murange[1][2]],
[(aEff*murange[1][0]**2. + bEff*murange[0][0]**2.) ** .5,
aEff*murange[1][1] + bEff*murange[0][1],
aEff*murange[1][2] + bEff*murange[0][2]]]
H = 1.
L = .75
delta = .05
n = 50
solver = MFE(mu0 = mu0, H = H, L = L, delta = delta, n = n, verbosity = verb)
rescalingExp = [2., 1., 1.]
if algo == "rational":
- params = {'N':MN, 'M':MN + Delta, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN + Delta, 'S':R, 'POD':True,
+ 'polydegreetype':polydegreetype}
if samples == "standard":
- params['polybasis'] = "CHEBYSHEV"
-# params['polybasis'] = "LEGENDRE"
-# params['polybasis'] = "MONOMIAL"
- params['E'] = MN
- params['radialBasis'] = radial
- params['radialBasisWeights'] = radialWeight
+ params['polybasis'] = "CHEBYSHEV" + radial
+# params['polybasis'] = "LEGENDRE" + radial
+# params['polybasis'] = "MONOMIAL" + radial
+ params['radialDirectionalWeights'] = radialWeight
method = RI
elif samples == "centered":
params['polybasis'] = "MONOMIAL"
- params['S'] = R
method = RI
- elif samples == "pole matching":
- params['S'] = [SPivot[0]]
- params['SMarginal'] = SPivot[1:]
+ elif samples == "pivoted":
+ params['S'] = SPivot
+ params['SMarginal'] = SMarginal
params['MMarginal'] = MMarginal
- params['polybasisPivot'] = "CHEBYSHEV"
- params['polybasisMarginal'] = "MONOMIAL"
+ params['polybasisPivot'] = "CHEBYSHEV" + radial
+ params['polybasisMarginal'] = "MONOMIAL" + radialM
params['matchingWeight'] = matchingWeight
- params['radialBasisPivot'] = radial
- params['radialBasisMarginal'] = radialM
- params['radialBasisWeightsPivot'] = radialWeight
- params['radialBasisWeightsMarginal'] = radialWeightM
- method = RIPM
+ params['radialDirectionalWeightsPivot'] = radialWeight
+ params['radialDirectionalWeightsMarginal'] = radialWeightM
+ method = RIP
else: #if algo == "RB":
params = {'R':(MN + 3 + Delta) * (MN + 2 + Delta) * (MN + 1 + Delta) // 6,
- 'S':S, 'POD':True, 'PODTolerance':PODTol}
- if samples == "standard":
+ 'S':R, 'POD':True, 'PODTolerance':PODTol}
+ if samples in ["standard", "centered"]:
method = RB
- elif samples == "centered":
- params['S'] = R
- method = RB
- elif samples == "pole matching":
- params['S'] = [SPivot[0]]
- params['SMarginal'] = SPivot[1:]
- params['MMarginal'] = MMarginal
- params['polybasisMarginal'] = "MONOMIAL"
- params['matchingWeight'] = matchingWeight
- params['radialBasisMarginal'] = radialM
- params['radialBasisWeightsMarginal'] = radialWeightM
- method = RBPM
+ elif samples == "pivoted":
+ raise
+# params['S'] = SPivot
+# params['SMarginal'] = SMarginal
+# params['MMarginal'] = MMarginal
+# params['polybasisMarginal'] = "MONOMIAL" + radialM
+# params['matchingWeight'] = matchingWeight
+# params['radialDirectionalWeightsMarginal'] = radialWeightM
+# method = RBP
if samples == "standard":
if sampling == "quadrature":
params['sampler'] = QS(murange, "CHEBYSHEV", scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "GAUSSLEGENDRE",scalingExp = rescalingExp)
# params['sampler'] = QS(murange, "UNIFORM", scalingExp = rescalingExp)
- params['S'] = [max(j, MN + 1) for j in params['S']]
+ params['S'] = STensorized
elif sampling == "quadrature_total":
params['sampler'] = QST(murange, "CHEBYSHEV", scalingExp = rescalingExp)
- params['S'] = R
else: # if sampling == "random":
params['sampler'] = RS(murange, "HALTON", scalingExp = rescalingExp)
- params['S'] = R
-
elif samples == "centered":
params['sampler'] = MS(murange, points = [mu0], scalingExp = rescalingExp)
-elif samples == "pole matching":
+elif samples == "pivoted":
if sampling == "quadrature":
params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "CHEBYSHEV")
# params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "GAUSSLEGENDRE")
# params['samplerPivot'] = QS([murange[0][0], murange[1][0]], "UNIFORM")
elif sampling == "quadrature_total":
params['samplerPivot'] = QST([murange[0][0], murange[1][0]], "CHEBYSHEV")
- params['S'] = MN + 1
else: # if sampling == "random":
params['samplerPivot'] = RS([murange[0][0], murange[1][0]], "HALTON")
- params['S'] = MN + 1
if samplingM == "quadrature":
params['samplerMarginal'] = QS([murange[0][1:], murange[1][1:]], "UNIFORM")
+ params['SMarginal'] = SMarginalTensorized
elif samplingM == "quadrature_total":
params['samplerMarginal'] = QST([murange[0][1:], murange[1][1:]], "CHEBYSHEV")
- params['SMarginal'] = (MMarginal + 2) * (MMarginal + 1) // 2
- params['polybasisMarginal'] = "CHEBYSHEV"
+ params['polybasisMarginal'] = "CHEBYSHEV" + radialM
else: # if samplingM == "random":
params['samplerMarginal'] = RS([murange[0][1:], murange[1][1:]], "HALTON")
- params['SMarginal'] = (MMarginal + 2) * (MMarginal + 1) // 2
-if samples != "pole matching":
+if samples != "pivoted":
approx = method(solver, mu0 = mu0, approxParameters = params,
verbosity = verb)
else:
approx = method(solver, mu0 = mu0, directionPivot = [0],
approxParameters = params, verbosity = verb)
-if samples != "centered": approx.samplingEngine.allowRepeatedSamples = False
approx.setupApprox()
if show_sample:
from fracture3_warping import fracture3_warping
warps = fracture3_warping(solver.V.mesh(), L, mutar[1], delta, mutar[2])
- approx.plotApprox(mutar, warps, name = 'u_app',
- homogeneized = False, what = "REAL")
- approx.plotHF(mutar, warps, name = 'u_HF',
- homogeneized = False, what = "REAL")
- approx.plotErr(mutar, warps, name = 'err',
- homogeneized = False, what = "REAL")
-# approx.plotRes(mutar, warps, name = 'res',
-# homogeneized = False, what = "REAL")
+ approx.plotApprox(mutar, warps, name = 'u_app', what = "REAL")
+ approx.plotHF(mutar, warps, name = 'u_HF', what = "REAL")
+ approx.plotErr(mutar, warps, name = 'err', what = "REAL")
+# approx.plotRes(mutar, warps, name = 'res', what = "REAL")
appErr = approx.normErr(mutar)
solNorm = approx.normHF(mutar)
resNorm = approx.normRes(mutar)
RHSNorm = approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
- np.divide(appErr, solNorm)))
+ np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
- np.divide(resNorm, RHSNorm)))
+ np.divide(resNorm, RHSNorm)))
fig = plt.figure(figsize = (8, 6))
ax = Axes3D(fig)
ax.scatter(np.real(approx.mus(0) ** 2.), np.real(approx.mus(1)),
np.real(approx.mus(2)), '.')
plt.show()
plt.close()
approx.verbosity = 0
approx.trainedModel.verbosity = 0
from plot_zero_set_3 import plotZeroSet3
#muZeroVals, Qvals = plotZeroSet3(murange, murangeEff, approx, mu0, 200,
# [None, mu0[1], mu0[2]], [2., 1., 1.],
# clip = clip)
#muZeroVals, Qvals = plotZeroSet3(murange, murangeEff, approx, mu0, 200,
# [None, None, mu0[2]], [2., 1., 1.],
# clip = clip)
#muZeroVals, Qvals = plotZeroSet3(murange, murangeEff, approx, mu0, 200,
# [None, mu0[1], None], [2., 1., 1.],
# clip = clip)
muZeroScatter = plotZeroSet3(murange, murangeEff, approx, mu0, 50,
[None, None, None], [2., 1., 1.], clip = clip)
if show_norm:
- solver._solveBatchSize = 25
from plot_inf_set_3 import plotInfSet3
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet3(
murange, murangeEff, approx, mu0, 25,
[None, mu0[1], mu0[2]], [2., 1., 1.],
clip = clip, relative = False,
normalizeDen = True)
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet3(
murange, murangeEff, approx, mu0, 25,
[None, None, mu0[2]], [2., 1., 1.],
clip = clip, relative = False,
normalizeDen = True)
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet3(
murange, murangeEff, approx, mu0, 25,
[None, mu0[1], None], [2., 1., 1.],
clip = clip, relative = False,
normalizeDen = True)
print(approx.getPoles([None, .5, .05]) ** 2.)
diff --git a/examples/3d/pod/matrix_3_pod.py b/examples/3d/pod/matrix_3_pod.py
index ae358a5..6cf3d40 100644
--- a/examples/3d/pod/matrix_3_pod.py
+++ b/examples/3d/pod/matrix_3_pod.py
@@ -1,187 +1,178 @@
import numpy as np
import scipy.sparse as sp
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
from rrompy.hfengines.base import MatrixEngineBase as MEB
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
QuadratureSamplerTotal as QST,
ManualSampler as MS,
RandomSampler as RS)
verb = 50
deg = 2
size = 1
show_sample = True
show_norm = False
Delta = 0
MN = 15
R = (MN + 3) * (MN + 2) * (MN + 1) // 6
-S = [int(np.ceil(R ** (1. / 3.)))] * 3
+STensorized = (MN + 1) ** 3
PODTol = 1e-8
samples = "centered"
samples = "standard"
-#samples, nDer = "standard_MMM", 2
+samples, nDer = "standard_MMM", 2
algo = "rational"
#algo = "RB"
sampling = "quadrature"
sampling = "quadrature_total"
sampling = "random"
if samples == "standard":
- radial = 0
-# radial = "gaussian"
-# radial = "thinplate"
-# radial = "multiquadric"
+ radial = ""
+# radial = "_gaussian"
+# radial = "_thinplate"
+# radial = "_multiquadric"
rW0 = 5.
radialWeight = [rW0] * 2
assert Delta <= 0
if size == 1:
mu0 = [0.] * 3
mutar = [.8, .8, .8]
murange = [[-1.] * 3, [1.] * 3]
aEff = 1.#25
bEff = 1. - aEff
murangeEff = [[aEff*murange[0][0] + bEff*murange[1][0],
aEff*murange[0][1] + bEff*murange[1][1],
aEff*murange[0][2] + bEff*murange[1][2]],
[aEff*murange[1][0] + bEff*murange[0][0],
aEff*murange[1][1] + bEff*murange[0][1],
aEff*murange[1][2] + bEff*murange[0][2]]]
N = 150
exp = 1.05
assert exp > 1.
empty = sp.csr_matrix((np.zeros(0), np.zeros(0), np.zeros(N + 1)),
shape = (N, N))
solver = MEB(verbosity = verb)
solver.npar = 3
A0 = sp.spdiags([np.arange(1, 1 + 2 * N, 2) ** exp - (2 * (N // 4)) ** exp],
[0], N, N)
if deg == 1:
solver.nAs = 4
solver.As = [A0, sp.eye(N), - sp.eye(N), - sp.eye(N)]
elif deg == 2:
solver.nAs = 7
solver.As = [A0] + [empty] + [- sp.eye(N)] + [empty] * 3 + [sp.eye(N)]
elif deg == 3:
solver.nAs = 13
solver.As = [A0] + [empty] + [- sp.eye(N)] + [empty] * 9 + [sp.eye(N)]
np.random.seed(420)
solver.nbs = 1
solver.bs = [np.random.randn(N) + 1.j * np.random.randn(N)]
-
+solver._affinePoly = True
+solver.thAs = solver.getMonomialWeights(solver.nAs)
+solver.thbs = solver.getMonomialWeights(solver.nbs)
if algo == "rational":
- params = {'N':MN, 'M':MN + Delta, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN + Delta, 'S':R, 'POD':True}
if samples == "standard":
- params['polybasis'] = "CHEBYSHEV"
-# params['polybasis'] = "LEGENDRE"
-# params['polybasis'] = "MONOMIAL"
- params['E'] = MN
- params['radialBasis'] = radial
- params['radialBasisWeights'] = radialWeight
+ params['polybasis'] = "CHEBYSHEV" + radial
+# params['polybasis'] = "LEGENDRE" + radial
+# params['polybasis'] = "MONOMIAL" + radial
+ params['radialDirectionalWeights'] = radialWeight
elif samples == "centered":
params['polybasis'] = "MONOMIAL"
- params['S'] = R
else: #MMM
params['S'] = nDer * int(np.ceil(R / nDer))
method = RI
else: #if algo == "RB":
params = {'R':(MN + 3 + Delta) * (MN + 2 + Delta) * (MN + 1 + Delta) // 6,
- 'S':S, 'POD':True, 'PODTolerance':PODTol}
- if samples == "standard":
- pass
- elif samples == "centered":
- params['S'] = R
- else: #MMM
+ 'S':R, 'POD':True, 'PODTolerance':PODTol}
+ if samples == "MMM":
params['S'] = nDer * int(np.ceil(R / nDer))
method = RB
if samples == "standard":
if sampling == "quadrature":
params['sampler'] = QS(murange, "CHEBYSHEV")
# params['sampler'] = QS(murange, "GAUSSLEGENDRE")
# params['sampler'] = QS(murange, "UNIFORM")
- params['S'] = [max(j, MN + 1) for j in params['S']]
+ params['S'] = STensorized
elif sampling == "quadrature_total":
params['sampler'] = QST(murange, "CHEBYSHEV")
- params['S'] = R
else: # if sampling == "random":
params['sampler'] = RS(murange, "HALTON")
- params['S'] = R
elif samples == "centered":
params['sampler'] = MS(murange, points = [mu0])
elif samples == "standard_MMM":
if sampling == "quadrature":
- SdirEff = int(np.ceil(int(np.ceil(R / nDer)) ** (1. / 3)))
- pts = QS(murange, "CHEBYSHEV").generatePoints([SdirEff] * 3)
+ SdirEff = int(np.ceil(int(np.ceil(R / nDer)) ** (1. / 3))) ** 3
+ pts = QS(murange, "CHEBYSHEV").generatePoints(SdirEff)
elif sampling == "quadrature_total":
pts = QST(murange, "CHEBYSHEV").generatePoints(int(np.ceil(R / nDer)))
else: # if sampling == "random":
pts = RS(murange, "HALTON").generatePoints(int(np.ceil(R / nDer)))
params['sampler'] = MS(murange, points = pts)
approx = method(solver, mu0 = mu0, approxParameters = params, verbosity = verb)
-if samples == "standard": approx.samplingEngine.allowRepeatedSamples = False
approx.setupApprox()
if show_sample:
approx.plotApprox(mutar, name = 'u_app', what = "REAL")
approx.plotHF(mutar, name = 'u_HF', what = "REAL")
approx.plotErr(mutar, name = 'err', what = "REAL")
# approx.plotRes(mutar, name = 'res', what = "REAL")
appErr = approx.normErr(mutar)
solNorm = approx.normHF(mutar)
resNorm = approx.normRes(mutar)
RHSNorm = approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
fig = plt.figure(figsize = (8, 6))
ax = Axes3D(fig)
ax.scatter(approx.trainedModel.data.mus(0), approx.trainedModel.data.mus(1),
approx.trainedModel.data.mus(2), '.')
ax.set_xlim3d(murangeEff[0][0], murangeEff[1][0])
ax.set_ylim3d(murangeEff[0][1], murangeEff[1][1])
ax.set_zlim3d(murangeEff[0][2], murangeEff[1][2])
plt.show()
plt.close()
approx.verbosity = 0
approx.trainedModel.verbosity = 0
if algo == "rational" and approx.N > 0:
from plot_zero_set_3 import plotZeroSet3
# muZeroVals, Qvals = plotZeroSet3(murange, murangeEff, approx, mu0, 200,
# [None, mu0[1], mu0[2]], [1., 1., 1.])
# muZeroVals, Qvals = plotZeroSet3(murange, murangeEff, approx, mu0, 200,
# [None, None, mu0[2]], [1., 1., 1.])
# muZeroVals, Qvals = plotZeroSet3(murange, murangeEff, approx, mu0, 200,
# [None, mu0[1], None], [1., 1., 1.])
plotZeroSet3(murange, murangeEff, approx, mu0, 25, [None, None, None],
[1., 1., 1.], imagTol = 1e-2)
if show_norm:
- solver._solveBatchSize = 25
from plot_inf_set_3 import plotInfSet3
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet3(
murange, murangeEff, approx, mu0, 25,
[None, mu0[1], mu0[2]], [1., 1., 1.],
relative = False, normalizeDen = True)
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet3(
murange, murangeEff, approx, mu0, 25,
[None, None, mu0[2]], [1., 1., 1.],
relative = False, normalizeDen = True)
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet3(
murange, murangeEff, approx, mu0, 25,
[None, mu0[1], None], [1., 1., 1.],
relative = False, normalizeDen = True)
diff --git a/examples/3d/pod/plot_inf_set_3.py b/examples/3d/pod/plot_inf_set_3.py
index 4ca96db..900e447 100644
--- a/examples/3d/pod/plot_inf_set_3.py
+++ b/examples/3d/pod/plot_inf_set_3.py
@@ -1,359 +1,360 @@
import warnings
from copy import deepcopy as copy
import numpy as np
from matplotlib import pyplot as plt
def plotInfSet31FromData(mNone, mus, Z, T, R, E, beta, murange, approx, mu0,
exp = 2., normalizeDen = False):
if hasattr(approx, "mus"):
mu2x = approx.mus(mNone[0]) ** exp
else:
mu2x = mu0[0] ** exp
murangeExp = [[murange[0][mNone[0]] ** exp],
[murange[1][mNone[0]] ** exp]]
mu1 = np.real(np.power([m[mNone[0]] for m in mus], exp))
ZTmin, ZTmax = min(np.min(Z), np.min(T)), max(np.max(Z), np.max(T))
Rmin, Rmax = np.min(R), np.max(R)
Emin, Emax = np.min(E), np.max(E)
if not np.isnan(beta[0]):
eta = R / beta / E
betamin, betamax = np.min(beta), np.max(beta)
etamin, etamax = np.min(eta), np.max(eta)
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, Z)
plt.semilogy(mu1, T, '--')
mTMP = mus[0]
mTMP[mNone[0]] = None
for l_ in approx.trainedModel.getPoles(mTMP):
plt.plot([np.real(l_ ** exp)] * 2, [ZTmin, ZTmax], 'b:')
plt.plot(mu2x, [ZTmin] * len(mu2x), 'kx')
plt.plot([murangeExp[0][0]] * 2, [ZTmin, ZTmax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [ZTmin, ZTmax], 'm:')
plt.xlim(mu1[0], mu1[-1])
plt.title("|u(mu)|, |u_app(mu)|")
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, R)
for l_ in approx.trainedModel.getPoles(mTMP):
plt.plot([np.real(l_ ** exp)] * 2, [Rmin, Rmax], 'b:')
plt.plot(mu2x, [Rmax] * len(mu2x), 'kx')
plt.plot([murangeExp[0][0]] * 2, [Rmin, Rmax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [Rmin, Rmax], 'm:')
plt.xlim(mu1[0], mu1[-1])
if normalizeDen:
plt.title("|Q(mu)res(mu)|")
else:
plt.title("|res(mu)|")
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, E)
for l_ in approx.trainedModel.getPoles(mTMP):
plt.plot([np.real(l_ ** exp)] * 2, [Emin, Emax], 'b:')
plt.plot(mu2x, [Emax] * len(mu2x), 'kx')
plt.plot([murangeExp[0][0]] * 2, [Emin, Emax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [Emin, Emax], 'm:')
plt.xlim(mu1[0], mu1[-1])
if normalizeDen:
plt.title("|Q(mu)err(mu)|")
else:
plt.title("|err(mu)|")
plt.grid()
plt.show()
if not np.isnan(beta[0]):
plt.figure(figsize = (15, 7))
plt.jet()
plt.plot(mu1, beta)
for l_ in approx.trainedModel.getPoles(mTMP):
plt.plot([np.real(l_ ** exp)] * 2, [betamin, betamax], 'b:')
plt.plot(mu2x, [betamax] * len(mu2x), 'kx')
plt.plot([murangeExp[0][0]] * 2, [betamin, betamax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [betamin, betamax], 'm:')
plt.xlim(mu1[0], mu1[-1])
plt.title("beta(mu)")
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, R / beta)
plt.semilogy(mu1, E, '--')
for l_ in approx.trainedModel.getPoles(mTMP):
plt.plot([np.real(l_ ** exp)] * 2, [Emin, Emax], 'b:')
plt.plot(mu2x, [Emax] * len(mu2x), 'kx')
plt.plot([murangeExp[0][0]] * 2, [Emin, Emax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [Emin, Emax], 'm:')
plt.xlim(mu1[0], mu1[-1])
if normalizeDen:
plt.title("|Q(mu)res(mu)/beta(mu)|")
else:
plt.title("|res(mu)/beta(mu)|")
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, eta)
for l_ in approx.trainedModel.getPoles(mTMP):
plt.plot([np.real(l_ ** exp)] * 2, [etamin, etamax], 'b:')
plt.plot(mu2x, [etamax] * len(mu2x), 'kx')
plt.plot([murangeExp[0][0]] * 2, [etamin, etamax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [etamin, etamax], 'm:')
plt.xlim(mu1[0], mu1[-1])
plt.title("eta(mu)")
plt.grid()
plt.show()
def plotInfSet32FromData(mNone, mus, Ze, Te, Re, Ee, beta, murange, approx,
mu0, exps = [2., 1.], clip = -1,
normalizeDen = False):
if hasattr(approx, "mus"):
mu2x = approx.mus(mNone[0]) ** exps[0]
mu2y = approx.mus(mNone[1]) ** exps[1]
else:
mu2x, mu2y = mu0[mNone[0]] ** exps[0], mu0[mNone[1]] ** exps[1]
murangeExp = [[murange[0][mNone[0]] ** exps[0],
murange[0][mNone[1]] ** exps[1]],
[murange[1][mNone[0]] ** exps[0],
murange[1][mNone[1]] ** exps[1]]]
mu1s = np.unique([m[mNone[0]] for m in mus])
mu2s = np.unique([m[mNone[1]] for m in mus])
mu1 = np.power(mu1s, exps[0])
mu2 = np.power(mu2s, exps[1])
Mu1, Mu2 = np.meshgrid(np.real(mu1), np.real(mu2))
Z = np.log10(Ze)
T = np.log10(Te)
R = np.log10(Re)
E = np.log10(Ee)
ZTmin, ZTmax = min(np.min(Z), np.min(T)), max(np.max(Z), np.max(T))
Rmin, Rmax = np.min(R), np.max(R)
Emin, Emax = np.min(E), np.max(E)
if not np.isnan(beta[0, 0]):
betamin, betamax = np.min(beta), np.max(beta)
if clip > 0:
ZTmax -= clip * (ZTmax - ZTmin)
cmap = plt.cm.bone
else:
cmap = plt.cm.jet
- warnings.simplefilter("ignore", category = UserWarning)
+ warnings.simplefilter("ignore", category = (UserWarning,
+ np.ComplexWarning))
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, Z, cmap = cmap,
levels = np.linspace(ZTmin, ZTmax, 50))
if clip > 0:
plt.contour(Mu1, Mu2, Z, [ZTmin])
plt.plot(mu2x, mu2y, 'kx')
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
plt.colorbar(p)
plt.title("log10|u(mu)|")
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, T, cmap = cmap,
levels = np.linspace(ZTmin, ZTmax, 50))
if clip > 0:
plt.contour(Mu1, Mu2, T, [ZTmin])
plt.plot(mu2x, mu2y, 'kx')
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
plt.title("log10|u_app(mu)|")
plt.colorbar(p)
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, R, levels = np.linspace(Rmin, Rmax, 50))
plt.plot(mu2x, mu2y, 'kx')
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
if normalizeDen:
plt.title("log10|Q(mu)res(mu)|")
else:
plt.title("log10|res(mu)|")
plt.colorbar(p)
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, E, levels = np.linspace(Emin, Emax, 50))
plt.plot(mu2x, mu2y, 'kx')
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
if normalizeDen:
plt.title("log10|Q(mu)err(mu)|")
else:
plt.title("log10|err(mu)|")
plt.colorbar(p)
plt.grid()
plt.show()
if not np.isnan(beta[0, 0]):
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, beta,
levels = np.linspace(betamin, betamax, 50))
plt.plot(mu2x, mu2y, 'kx')
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
plt.title("beta(mu)")
plt.colorbar(p)
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, R - np.log10(beta),
levels = np.linspace(Emin, Emax, 50))
plt.plot(mu2x, mu2y, 'kx')
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
if normalizeDen:
plt.title("log10|Q(mu)res(mu)/beta(mu)|")
else:
plt.title("log10|res(mu)/beta(mu)|")
plt.colorbar(p)
plt.grid()
plt.show()
plt.figure(figsize = (15, 7))
plt.jet()
p = plt.contourf(Mu1, Mu2, R - np.log10(beta) - E, 50)
plt.plot(mu2x, mu2y, 'kx')
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
plt.title("log10|eta(mu)|")
plt.colorbar(p)
plt.grid()
plt.show()
def plotInfSet3(murange, murangeEff, approx, mu0, nSamples = 200,
marginal = [None, None, .05], exps = [2., 1., 1.], clip = -1,
relative = True, normalizeDen = False, nobeta = False):
mNone = [i for i, m in enumerate(marginal) if m is None]
nNone = len(mNone)
if nNone not in [1, 2]:
raise
if nNone == 1:
exp = exps[mNone[0]]
mu1 = np.linspace(murangeEff[0][mNone[0]] ** exp,
murangeEff[1][mNone[0]] ** exp, nSamples)
mu1s = np.power(mu1, 1. / exp)
mus = []
mBase = copy(marginal)
for m1 in mu1s:
mBase[mNone[0]] = m1
mus += [copy(mBase)]
Z = approx.normHF(mus)
T = approx.normApprox(mus)
R = approx.normRes(mus)
E = approx.normErr(mus)
if relative:
F = approx.normRHS(mus)
R /= F
E /= Z
if normalizeDen:
Qvals = np.abs(approx.trainedModel.getQVal(mus))
R *= Qvals
E *= Qvals
if nobeta:
beta = np.empty(len(mus))
beta[:] = np.nan
else:
- beta = approx.HFEngine.stabilityFactor(approx.getHF(mus), mus)
+ beta = approx.HFEngine.stabilityFactor(mus, approx.getHF(mus))
plotInfSet31FromData(mNone, mus, Z, T, R, E, beta, murange, approx,
mu0, exp, normalizeDen)
return mus, Z, T, R, E, beta
if nNone == 2:
exps = [exps[m] for m in mNone]
mu1 = np.linspace(murangeEff[0][mNone[0]] ** exps[0],
murangeEff[1][mNone[0]] ** exps[0], nSamples)
mu2 = np.linspace(murangeEff[0][mNone[1]] ** exps[1],
murangeEff[1][mNone[1]] ** exps[1], nSamples)
mu1s = np.power(mu1, 1. / exps[0])
mu2s = np.power(mu2, 1. / exps[1])
Mu1, Mu2 = np.meshgrid(np.real(mu1), np.real(mu2))
mus = []
mBase = copy(marginal)
for m2 in mu2s:
mBase[mNone[1]] = m2
for m1 in mu1s:
mBase[mNone[0]] = m1
mus += [copy(mBase)]
Ze = approx.normHF(mus).reshape((nSamples, nSamples))
Te = approx.normApprox(mus).reshape((nSamples, nSamples))
Re = approx.normRes(mus).reshape((nSamples, nSamples))
Ee = approx.normErr(mus).reshape((nSamples, nSamples))
if relative:
Fe = approx.normRHS(mus).reshape((nSamples, nSamples))
Re /= Fe
Ee /= Ze
if normalizeDen:
Qvals = np.abs(approx.trainedModel.getQVal(mus).reshape(
(nSamples, nSamples)))
Re *= Qvals
Ee *= Qvals
if nobeta:
betae = np.empty((nSamples, nSamples))
betae[:, :] = np.nan
else:
- betae = approx.HFEngine.stabilityFactor(approx.getHF(mus), mus)\
+ betae = approx.HFEngine.stabilityFactor(mus, approx.getHF(mus))\
.reshape((nSamples, nSamples))
plotInfSet32FromData(mNone, mus, Ze, Te, Re, Ee, betae, murange,
approx, mu0, exps, clip, normalizeDen)
return mus, Ze, Te, Re, Ee, betae
diff --git a/examples/3d/pod/plot_zero_set_3.py b/examples/3d/pod/plot_zero_set_3.py
index c1db350..f9ae061 100644
--- a/examples/3d/pod/plot_zero_set_3.py
+++ b/examples/3d/pod/plot_zero_set_3.py
@@ -1,170 +1,171 @@
import warnings
from copy import deepcopy as copy
import numpy as np
from matplotlib import pyplot as plt
def plotZeroSet3(murange, murangeEff, approx, mu0, nSamples = 200,
marginal = [None, None, .05], exps = [2., 1., 1.],
clip = -1, polesImTol : float = 1e-5):
mNone = [i for i, m in enumerate(marginal) if m is None]
nNone = len(mNone)
if nNone not in [1, 2, 3]:
raise
if nNone == 1:
exp = exps[mNone[0]]
if hasattr(approx, "mus"):
mu2x = approx.mus(mNone[0]) ** exp
else:
mu2x = mu0[0] ** exp
murangeExp = [[murange[0][mNone[0]] ** exp],
[murange[1][mNone[0]] ** exp]]
mu1 = np.linspace(murangeEff[0][mNone[0]] ** exp,
murangeEff[1][mNone[0]] ** exp, nSamples)
mu1s = np.power(mu1, 1. / exp)
mus = []
mBase = copy(marginal)
for m1 in mu1s:
mBase[mNone[0]] = m1
mus += [copy(mBase)]
mu1 = np.real(mu1)
Z = approx.trainedModel.getQVal(mus)
Zabs = np.abs(Z)
Zmin, Zmax = np.min(Zabs), np.max(Zabs)
plt.figure(figsize = (15, 7))
plt.jet()
plt.semilogy(mu1, Zabs)
for l_ in approx.trainedModel.getPoles(marginal):
plt.plot([np.real(l_ ** exp)] * 2, [Zmin, Zmax], 'b--')
plt.plot(mu2x, [Zmax] * len(mu2x), 'kx')
plt.plot([murangeExp[0][0]] * 2, [Zmin, Zmax], 'm:')
plt.plot([murangeExp[1][0]] * 2, [Zmin, Zmax], 'm:')
plt.xlim(mu1[0], mu1[-1])
plt.title("|Q(mu)|")
plt.grid()
plt.show()
return mus, Z
if nNone == 2:
exps = [exps[m] for m in mNone]
if hasattr(approx, "mus"):
mu2x = approx.mus(mNone[0]) ** exps[0]
mu2y = approx.mus(mNone[1]) ** exps[1]
else:
mu2x, mu2y = mu0[mNone[0]] ** exps[0], mu0[mNone[1]] ** exps[1]
murangeExp = [[murange[0][mNone[0]] ** exps[0],
murange[0][mNone[1]] ** exps[1]],
[murange[1][mNone[0]] ** exps[0],
murange[1][mNone[1]] ** exps[1]]]
mu1 = np.linspace(murangeEff[0][mNone[0]] ** exps[0],
murangeEff[1][mNone[0]] ** exps[0], nSamples)
mu2 = np.linspace(murangeEff[0][mNone[1]] ** exps[1],
murangeEff[1][mNone[1]] ** exps[1], nSamples)
mu1s = np.power(mu1, 1. / exps[0])
mu2s = np.power(mu2, 1. / exps[1])
Mu1, Mu2 = np.meshgrid(np.real(mu1), np.real(mu2))
mus = []
mBase = copy(marginal)
for m2 in mu2s:
mBase[mNone[1]] = m2
for m1 in mu1s:
mBase[mNone[0]] = m1
mus += [copy(mBase)]
poles1, poles2 = [], []
for m in mus:
m[mNone[0]] = None
pls = approx.getPoles(m) ** exps[0]
pls[np.imag(pls) > polesImTol] = np.nan
pls = np.real(pls)
poles1 += list(pls)
poles2 += [m[mNone[1]] ** exps[1]] * len(pls)
try:
Z = approx.trainedModel.getQVal(mus).reshape(Mu1.shape)
Zabs = np.log10(np.abs(Z))
Zabsmin, Zabsmax = np.min(Zabs), np.max(Zabs)
if clip > 0:
Zabsmin += clip * (Zabsmax - Zabsmin)
cmap = plt.cm.bone_r
else:
cmap = plt.cm.jet
except:
Z = None
cmap = plt.cm.jet
- warnings.simplefilter("ignore", category = UserWarning)
+ warnings.simplefilter("ignore", category = (UserWarning,
+ np.ComplexWarning))
plt.figure(figsize = (15, 7))
plt.jet()
if Z is not None:
p = plt.contourf(Mu1, Mu2, Zabs, cmap = cmap,
levels = np.linspace(Zabsmin, Zabsmax, 50))
if clip > 0:
plt.contour(Mu1, Mu2, Zabs, [Zabsmin])
plt.plot(poles1, poles2, 'k.')
plt.plot(mu2x, mu2y, 'kx')
plt.plot([murangeExp[0][0]] * 2,
[murangeExp[0][1], murangeExp[1][1]], 'm:')
plt.plot([murangeExp[0][0], murangeExp[1][0]],
[murangeExp[1][1]] * 2, 'm:')
plt.plot([murangeExp[1][0]] * 2,
[murangeExp[1][1], murangeExp[0][1]], 'm:')
plt.plot([murangeExp[1][0], murangeExp[0][0]],
[murangeExp[0][1]] * 2, 'm:')
if Z is not None:
plt.colorbar(p)
plt.xlim(murangeExp[0][0], murangeExp[1][0])
plt.ylim(murangeExp[0][1], murangeExp[1][1])
plt.title("log10|Q(mu)|")
plt.grid()
plt.show()
return mus, Z
if nNone == 3:
exps = [exps[m] for m in mNone]
murangeExp = [[murange[0][mNone[0]] ** exps[0],
murange[0][mNone[1]] ** exps[1],
murange[0][mNone[2]] ** exps[2]],
[murange[1][mNone[0]] ** exps[0],
murange[1][mNone[1]] ** exps[1],
murange[1][mNone[2]] ** exps[2]]]
mu1 = np.linspace(murangeEff[0][mNone[0]] ** exps[0],
murangeEff[1][mNone[0]] ** exps[0], nSamples)
mu2 = np.linspace(murangeEff[0][mNone[1]] ** exps[1],
murangeEff[1][mNone[1]] ** exps[1], nSamples)
mu3 = np.linspace(murangeEff[0][mNone[2]] ** exps[2],
murangeEff[1][mNone[2]] ** exps[2], nSamples)
mu1s = np.power(mu1, 1. / exps[0])
mu2s = np.power(mu2, 1. / exps[1])
mu3s = np.power(mu3, 1. / exps[2])
Mu1, Mu2, Mu3 = np.meshgrid(np.real(mu1), np.real(mu2), np.real(mu3),
indexing = 'ij')
mus = []
mBase = copy(marginal)
for m2 in mu2s:
mBase[mNone[1]] = m2
for m3 in mu3s:
mBase[mNone[2]] = m3
mus += [copy(mBase)]
poles1, poles2, poles3 = [], [], []
for m in mus:
m[mNone[0]] = None
pls = approx.getPoles(m) ** exps[0]
pls[np.imag(pls) > polesImTol] = np.nan
pls = np.real(pls)
pls[pls < murangeExp[0][0]] = np.nan
pls[pls > murangeExp[1][0]] = np.nan
poles1 += list(pls)
poles2 += [m[mNone[1]] ** exps[1]] * len(pls)
poles3 += [m[mNone[2]] ** exps[2]] * len(pls)
pts = np.empty((len(poles1), 3))
pts[:, 0] = poles1
pts[:, 1] = poles2
pts[:, 2] = poles3
if np.size(pts) > 0:
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize = (8, 6))
ax = Axes3D(fig)
ax.scatter(pts[:, 0], pts[:, 1], pts[:, 2], '.', s = 1)
ax.set_xlim(murangeExp[0][0], murangeExp[1][0])
ax.set_ylim(murangeExp[0][1], murangeExp[1][1])
ax.set_zlim(murangeExp[0][2], murangeExp[1][2])
plt.show()
plt.close()
return pts
diff --git a/examples/3d/pod/scattering1_pod.py b/examples/3d/pod/scattering1_pod.py
index 7ac695f..ac50f5c 100644
--- a/examples/3d/pod/scattering1_pod.py
+++ b/examples/3d/pod/scattering1_pod.py
@@ -1,190 +1,175 @@
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
from rrompy.hfengines.linear_problem.tridimensional import Scattering1d as S1D
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
QuadratureSamplerTotal as QST,
ManualSampler as MS,
RandomSampler as RS)
verb = 50
size = 2
show_sample = True
show_norm = False
clip = -1
#clip = .4
#clip = .6
homogeneize = False
#homogeneize = True
Delta = 0
MN = 15
R = (MN + 3) * (MN + 2) * (MN + 1) // 6
-S = [int(np.ceil(R ** (1. / 3.)))] * 3
+STensorized = (MN + 1) ** 3
PODTol = 1e-8
samples = "centered"
samples = "standard"
samples, nDer = "standard_MMM", 15
algo = "rational"
#algo = "RB"
sampling = "quadrature"
sampling = "quadrature_total"
sampling = "random"
if samples == "standard":
- radial = 0
-# radial = "gaussian"
-# radial = "thinplate"
-# radial = "multiquadric"
+ radial = ""
+# radial = "_gaussian"
+# radial = "_thinplate"
+# radial = "_multiquadric"
rW0 = 5.
- radialWeight = [rW0] * 2
+ radialWeight = [rW0] * 3
assert Delta <= 0
if size == 1:
mu0 = [4., np.pi, 0.]
mutar = [4.05, .95 * np.pi, .2]
murange = [[2., .9 * np.pi, -.5], [6., 1.1 * np.pi, .5]]
if size == 2:
mu0 = [4., np.pi, .375]
mutar = [4.05, .95 * np.pi, .2]
murange = [[2., .9 * np.pi, 0.], [6., 1.1 * np.pi, .75]]
aEff = 1.#25
bEff = 1. - aEff
murangeEff = [[aEff*murange[0][0] + bEff*murange[1][0],
aEff*murange[0][1] + bEff*murange[1][1],
aEff*murange[0][2] + bEff*murange[1][2]],
[aEff*murange[1][0] + bEff*murange[0][0],
aEff*murange[1][1] + bEff*murange[0][1],
aEff*murange[1][2] + bEff*murange[0][2]]]
n = 100
-solver = S1D(mu0 = mu0, n = n, verbosity = verb)
+solver = S1D(mu0 = mu0, n = n, verbosity = verb, homogeneized = homogeneize)
if algo == "rational":
- params = {'N':MN, 'M':MN + Delta, 'S':S, 'POD':True}
+ params = {'N':MN, 'M':MN + Delta, 'S':R, 'POD':True}
if samples == "standard":
- params['polybasis'] = "CHEBYSHEV"
-# params['polybasis'] = "LEGENDRE"
-# params['polybasis'] = "MONOMIAL"
- params['E'] = MN
- params['radialBasis'] = radial
- params['radialBasisWeights'] = radialWeight
+ params['polybasis'] = "CHEBYSHEV" + radial
+# params['polybasis'] = "LEGENDRE" + radial
+# params['polybasis'] = "MONOMIAL" + radial
+ params['radialDirectionalWeights'] = radialWeight
elif samples == "centered":
params['polybasis'] = "MONOMIAL"
- params['S'] = R
else: #MMM
params['S'] = nDer * int(np.ceil(R / nDer))
method = RI
else: #if algo == "RB":
params = {'R':(MN + 3 + Delta) * (MN + 2 + Delta) * (MN + 1 + Delta) // 6,
- 'S':S, 'POD':True, 'PODTolerance':PODTol}
- if samples == "standard":
- pass
- elif samples == "centered":
- params['S'] = R
- else: #MMM
+ 'S':R, 'POD':True, 'PODTolerance':PODTol}
+ if samples == "MMM":
params['S'] = nDer * int(np.ceil(R / nDer))
method = RB
if samples == "standard":
if sampling == "quadrature":
params['sampler'] = QS(murange, "CHEBYSHEV")
# params['sampler'] = QS(murange, "GAUSSLEGENDRE")
# params['sampler'] = QS(murange, "UNIFORM")
- params['S'] = [max(j, MN + 1) for j in params['S']]
+ params['S'] = STensorized
elif sampling == "quadrature_total":
params['sampler'] = QST(murange, "CHEBYSHEV")
- params['S'] = R
else: # if sampling == "random":
params['sampler'] = RS(murange, "HALTON")
- params['S'] = R
elif samples == "centered":
params['sampler'] = MS(murange, points = [mu0])
elif samples == "standard_MMM":
if sampling == "quadrature":
- SdirEff = int(np.ceil(int(np.ceil(R / nDer)) ** (1. / 3)))
- pts = QS(murange, "CHEBYSHEV").generatePoints([SdirEff] * 3)
+ SdirEff = int(np.ceil(int(np.ceil(R / nDer)) ** (1. / 3))) ** 3
+ pts = QS(murange, "CHEBYSHEV").generatePoints(SdirEff)
elif sampling == "quadrature_total":
pts = QST(murange, "CHEBYSHEV").generatePoints(int(np.ceil(R / nDer)))
else: # if sampling == "random":
pts = RS(murange, "HALTON").generatePoints(int(np.ceil(R / nDer)))
params['sampler'] = MS(murange, points = pts)
approx = method(solver, mu0 = mu0, approxParameters = params,
- verbosity = verb, homogeneized = homogeneize)
-if samples == "standard": approx.samplingEngine.allowRepeatedSamples = False
+ verbosity = verb)
approx.setupApprox()
if show_sample:
import fenics as fen
x = fen.SpatialCoordinate(solver.V.mesh())
warps = [x * mutar[1] / solver._L - x, x * solver._L / mutar[1] - x]
- approx.plotApprox(mutar, warps, name = 'u_app',
- homogeneized = False, what = "REAL")
- approx.plotHF(mutar, warps, name = 'u_HF',
- homogeneized = False, what = "REAL")
- approx.plotErr(mutar, warps, name = 'err',
- homogeneized = False, what = "REAL")
-# approx.plotRes(mutar, warps, name = 'res',
-# homogeneized = False, what = "REAL")
- appErr = approx.normErr(mutar, homogeneized = homogeneize)
- solNorm = approx.normHF(mutar, homogeneized = homogeneize)
- resNorm = approx.normRes(mutar, homogeneized = homogeneize)
- RHSNorm = approx.normRHS(mutar, homogeneized = homogeneize)
+ approx.plotApprox(mutar, warps, name = 'u_app', what = "REAL")
+ approx.plotHF(mutar, warps, name = 'u_HF', what = "REAL")
+ approx.plotErr(mutar, warps, name = 'err', what = "REAL")
+# approx.plotRes(mutar, warps, name = 'res', what = "REAL")
+ appErr = approx.normErr(mutar)
+ solNorm = approx.normHF(mutar)
+ resNorm = approx.normRes(mutar)
+ RHSNorm = approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
fig = plt.figure(figsize = (8, 6))
ax = Axes3D(fig)
ax.scatter(approx.trainedModel.data.mus(0), approx.trainedModel.data.mus(1),
approx.trainedModel.data.mus(2), '.')
ax.set_xlim3d(murangeEff[0][0], murangeEff[1][0])
ax.set_ylim3d(murangeEff[0][1], murangeEff[1][1])
ax.set_zlim3d(murangeEff[0][2], murangeEff[1][2])
plt.show()
plt.close()
approx.verbosity = 0
approx.trainedModel.verbosity = 0
if algo == "rational" and approx.N > 0:
from plot_zero_set_3 import plotZeroSet3
muZeroVals, Qvals = plotZeroSet3(murange, murangeEff, approx, mu0, 200,
[None, mu0[1], mu0[2]], [1., 1., 1.],
clip = clip)
muZeroVals, Qvals = plotZeroSet3(murange, murangeEff, approx, mu0, 200,
[None, None, mu0[2]], [1., 1., 1.],
clip = clip)
muZeroVals, Qvals = plotZeroSet3(murange, murangeEff, approx, mu0, 200,
[None, mu0[1], None], [1., 1., 1.],
clip = clip)
plotZeroSet3(murange, murangeEff, approx, mu0, 100, [None, None, None],
[1., 1., 1.], clip = clip, imagTol = 1e-2)
if show_norm:
- solver._solveBatchSize = 25
from plot_inf_set_3 import plotInfSet3
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet3(
murange, murangeEff, approx, mu0, 25,
[None, mu0[1], mu0[2]], [1., 1., 1.],
clip = clip, relative = False,
normalizeDen = True)
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet3(
murange, murangeEff, approx, mu0, 25,
[None, None, mu0[2]], [1., 1., 1.],
clip = clip, relative = False,
normalizeDen = True)
muInfVals, normEx, normApp, normRes, normErr, beta = plotInfSet3(
murange, murangeEff, approx, mu0, 25,
[None, mu0[1], None], [1., 1., 1.],
clip = clip, relative = False,
normalizeDen = True)
print(approx.getPoles([None, np.pi, 0.]))
diff --git a/examples/airfoil/greedy.py b/examples/airfoil/greedy.py
index 1f23b37..ada4d7e 100644
--- a/examples/airfoil/greedy.py
+++ b/examples/airfoil/greedy.py
@@ -1,109 +1,107 @@
import numpy as np
from airfoil_engine import AirfoilScatteringEngine
from rrompy.reduction_methods.greedy import RationalInterpolantGreedy as RI
from rrompy.reduction_methods.greedy import ReducedBasisGreedy as RB
from rrompy.solver.fenics import L2NormMatrix
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
verb = 5
timed = False
algo = "RI"
#algo = "RB"
polyBasis = "LEGENDRE"
#polyBasis = "CHEBYSHEV"
#polyBasis = "MONOMIAL"
homog = True
homog = False
k0s = np.linspace(5, 10, 100)
k0 = np.mean(k0s)
kl, kr = min(k0s), max(k0s)
params = {'S':5, 'sampler':QS([kl, kr], "UNIFORM"), 'nTestPoints':500,
'greedyTol':1e-2, 'polybasis':polyBasis,
- 'errorEstimatorKind':'BASIC'}
+ 'errorEstimatorKind':'INTERPOLATORY'}
#########
kappa = 10
theta = np.pi * - 45 / 180.
solver = AirfoilScatteringEngine(kappa, theta, verbosity = verb,
- degree_threshold = 8)
+ degree_threshold = 8, homogeneized = homog)
#########
if algo == "RI":
- approx = RI(solver, mu0 = k0, approxParameters = params, verbosity = verb,
- homogeneized = homog)
+ approx = RI(solver, mu0 = k0, approxParameters = params, verbosity = verb)
else:
params.pop("polybasis")
params.pop("errorEstimatorKind")
- approx = RB(solver, mu0 = k0, approxParameters = params, verbosity = verb,
- homogeneized = homog)
+ approx = RB(solver, mu0 = k0, approxParameters = params, verbosity = verb)
approx.initEstimatorNormEngine(L2NormMatrix(solver.V))
if timed:
from time import clock
start_time = clock()
approx.greedy()
print("Time: ", clock() - start_time)
else:
approx.greedy(True)
approx.samplingEngine.verbosity = 0
approx.verbosity = 0
kl, kr = np.real(kl), np.real(kr)
from matplotlib import pyplot as plt
normApp = np.zeros(len(k0s))
norm = np.zeros_like(normApp)
res = np.zeros_like(normApp)
err = np.zeros_like(normApp)
for j in range(len(k0s)):
normApp[j] = approx.normApprox(k0s[j])
norm[j] = approx.normHF(k0s[j])
res[j] = (approx.estimatorNormEngine.norm(
- approx.getRes(k0s[j], homogeneized = homog, duality = False))
+ approx.getRes(k0s[j], duality = False))
/ approx.estimatorNormEngine.norm(
- approx.getRHS(k0s[j], homogeneized = homog, duality = False)))
+ approx.getRHS(k0s[j], duality = False)))
err[j] = approx.normErr(k0s[j]) / approx.normHF(k0s[j])
resApp = approx.errorEstimator(k0s)
plt.figure()
plt.plot(k0s, norm)
plt.plot(k0s, normApp, '--')
plt.plot(np.real(approx.mus.data),
1.05*np.max(norm)*np.ones_like(approx.mus.data, dtype = float), 'rx')
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
plt.figure()
plt.semilogy(k0s, res)
plt.semilogy(k0s, resApp, '--')
plt.semilogy(np.real(approx.mus.data),
4.*np.max(resApp)*np.ones_like(approx.mus.data, dtype = float),
'rx')
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
plt.figure()
plt.semilogy(k0s, err)
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
polesApp = approx.getPoles()
mask = (np.real(polesApp) < kl) | (np.real(polesApp) > kr)
print("Outliers:", polesApp[mask])
polesApp = polesApp[~mask]
plt.figure()
plt.plot(np.real(polesApp), np.imag(polesApp), 'kx')
plt.axis('equal')
plt.grid()
plt.show()
plt.close()
diff --git a/examples/airfoil/solver.py b/examples/airfoil/solver.py
index c292d3a..ff31e73 100644
--- a/examples/airfoil/solver.py
+++ b/examples/airfoil/solver.py
@@ -1,40 +1,41 @@
import numpy as np
import fenics as fen
from airfoil_engine import AirfoilScatteringEngine
verb = 0
####################
homog = True
homog = False
####################
k0 = 5e2 * 2 * np.pi / 340
kappa = 5e2 * 2 * np.pi / 340
theta = np.pi * - 45 / 180.
mesh = fen.Mesh('../data/mesh/airfoil2412_1.xml')
solver = AirfoilScatteringEngine(kappa, theta, verbosity = verb,
- degree_threshold = 8)
+ degree_threshold = 8,
+ homogeneized = homog)
-uinc = solver.liftDirichletData(k0)
+uinc = solver.liftDirichletData()
if homog:
- uhtot = solver.solve(kappa, homogeneized = homog)[0]
+ uhtot = solver.solve(kappa)[0]
uh = uhtot + uinc
else:
- uh = solver.solve(kappa, homogeneized = homog)[0]
+ uh = solver.solve(kappa)[0]
uhtot = uh - uinc
print(solver.norm(uh))
print(solver.norm(uhtot))
solver.plot(fen.project(solver.diffusivity[0], solver.V).vector(),
what = 'Real', name = 'a')
solver.plot(uinc, what = 'Real', name = 'u_inc')
solver.plot(uh, what = 'ABS')
solver.plot(uhtot, what = 'ABS', name = 'u + u_inc')
solver.outParaviewTimeDomain(uh, omega = kappa, forceNewFile = False,
filename = "out/out_{}_".format(kappa))
solver.outParaviewTimeDomain(uhtot, omega = kappa, forceNewFile = False,
filename = "out/outT_{}_".format(kappa))
diff --git a/examples/all_forcing/all_forcing_engine.py b/examples/all_forcing/all_forcing_engine.py
index 85bc985..0074346 100644
--- a/examples/all_forcing/all_forcing_engine.py
+++ b/examples/all_forcing/all_forcing_engine.py
@@ -1,49 +1,43 @@
import numpy as np
import fenics as fen
from rrompy.hfengines.linear_problem import LaplaceBaseProblemEngine as LBPE
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.solver.fenics import fenics2Vector
class AllForcingEngine(LBPE):
def __init__(self, mu0:float, n : int = 30,
- degree_threshold : int = np.inf,
- verbosity : int = 10, timestamp : bool = True):
+ degree_threshold : int = np.inf, verbosity : int = 10,
+ timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = False, verbosity = verbosity,
+ timestamp = timestamp)
mesh = fen.RectangleMesh(fen.Point(-5., -5.), fen.Point(5., 5.), n, n)
self.V = fen.FunctionSpace(mesh, "P", 1)
self.nAs, self.nbs = 1, 4
x, y = fen.SpatialCoordinate(mesh)[:]
scaling = (2. * np.pi) ** -1.
r2 = x ** 2. + y ** 2.
self.forcingCoeffs = [
scaling * fen.exp(- (r2 + 1. - 2. * x + 1. - 2. * y) / 2. / 4.) / 2.,
scaling * fen.exp(- (r2 + 1. + 2. * x + 1. + 2. * y) / 2. / 16.) / 4.,
- scaling * fen.exp(- (r2 + 1. + 2. * x + 1. - 2. * y) / 2. / 9.) / 30.,
scaling * fen.exp(- (r2 + 1. - 2. * x + 1. + 2. * y) / 2. / 25.) / 120.]
- def b(self, mu = [], der = 0, homogeneized = False):
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = der[0]
- nbsTot = self.nbsH if homogeneized else self.nbs
- bs = self.bsH if homogeneized else self.bs
- if homogeneized and self.mu0 != self.mu0BC:
- self.liftDirichletData(self.mu0)
- for j in range(derI, nbsTot):
- if bs[j] is None:
+ def buildb(self):
+ """Build terms of operator of linear system."""
+ if self.thbs[0] is None:
+ self.thbs = (self.getMonomialWeights(self.nbs)
+ + [None] * (self.homogeneized * self.nAs))
+ for j in range(self.nbs):
+ if self.bs[j] is None:
vbMng(self, "INIT", "Assembling forcing term b{}.".format(j),
20)
parsRe = self.iterReduceQuadratureDegree([(
self.forcingCoeffs[j],
"forcingCoefficient")])
u0Re = self.DirichletDatum[0]
L0Re = fen.dot(self.forcingCoeffs[j], self.v) * fen.dx
DBCR = fen.DirichletBC(self.V, u0Re, self.DirichletBoundary)
- b = fenics2Vector(L0Re, parsRe, DBCR, 1)
- if homogeneized:
- self.bsH[j] = b
- else:
- self.bs[j] = b
+ self.bs[j] = fenics2Vector(L0Re, parsRe, DBCR, 1)
vbMng(self, "DEL", "Done assembling forcing term.", 20)
- return self._assembleb(mu, der, derI, homogeneized)
+ self.setbHomogeneized()
diff --git a/examples/all_forcing/greedy.py b/examples/all_forcing/greedy.py
index b32a4cc..3351a66 100644
--- a/examples/all_forcing/greedy.py
+++ b/examples/all_forcing/greedy.py
@@ -1,96 +1,96 @@
import numpy as np
from all_forcing_engine import AllForcingEngine
from rrompy.reduction_methods.greedy import RationalInterpolantGreedy as RI
from rrompy.reduction_methods.greedy import ReducedBasisGreedy as RB
from rrompy.solver.fenics import L2NormMatrix
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
verb = 5
timed = False
algo = "RI"
#algo = "RB"
polyBasis = "LEGENDRE"
#polyBasis = "CHEBYSHEV"
#polyBasis = "MONOMIAL"
if timed: verb = 0
z0s = np.linspace(-3., 3., 100)
z0 = np.mean(z0s)
zl, zr = min(z0s), max(z0s)
n = 30
solver = AllForcingEngine(mu0 = z0, n = n, degree_threshold = 8, verbosity = 0)
params = {'sampler':QS([zl, zr], "UNIFORM"), 'nTestPoints':500,
'greedyTol':1e-2, 'S':2, 'polybasis':polyBasis,
-# 'errorEstimatorKind':'BARE'}
-# 'errorEstimatorKind':'BASIC'}
- 'errorEstimatorKind':'EXACT'}
+# 'errorEstimatorKind':'DIAGONAL'}
+# 'errorEstimatorKind':'INTERPOLATORY'}
+ 'errorEstimatorKind':'AFFINE'}
if algo == "RI":
approx = RI(solver, mu0 = solver.mu0, approxParameters = params,
verbosity = verb)
else:
params.pop("polybasis")
params.pop("errorEstimatorKind")
approx = RB(solver, mu0 = solver.mu0, approxParameters = params,
verbosity = verb)
approx.initEstimatorNormEngine(L2NormMatrix(solver.V))
if timed:
from time import clock
start_time = clock()
approx.greedy()
print("Time: ", clock() - start_time)
else:
approx.greedy(True)
polesApp = approx.getPoles()
print("Poles:\n", polesApp)
approx.samplingEngine.verbosity = 0
approx.trainedModel.verbosity = 0
approx.verbosity = 0
zl, zr = np.real(zl), np.real(zr)
from matplotlib import pyplot as plt
normApp = np.zeros(len(z0s))
norm = np.zeros_like(normApp)
res = np.zeros_like(normApp)
err = np.zeros_like(normApp)
for j in range(len(z0s)):
normApp[j] = approx.normApprox(z0s[j])
norm[j] = approx.normHF(z0s[j])
res[j] = (approx.estimatorNormEngine.norm(
approx.getRes(z0s[j], duality = False))
/ approx.estimatorNormEngine.norm(
approx.getRHS(z0s[j], duality = False)))
err[j] = approx.normErr(z0s[j]) / norm[j]
resApp = approx.errorEstimator(z0s)
plt.figure()
plt.semilogy(z0s, norm)
plt.semilogy(z0s, normApp, '--')
plt.semilogy(np.real(approx.mus.data),
1.05*np.max(norm)*np.ones_like(approx.mus.data, dtype = float),
'rx')
plt.xlim([zl, zr])
plt.grid()
plt.show()
plt.close()
plt.figure()
plt.semilogy(z0s, res)
plt.semilogy(z0s, resApp, '--')
plt.semilogy(np.real(approx.mus.data),
approx.greedyTol*np.ones_like(approx.mus.data, dtype = float),
'rx')
plt.xlim([zl, zr])
plt.grid()
plt.show()
plt.close()
plt.figure()
plt.semilogy(z0s, err)
plt.xlim([zl, zr])
plt.grid()
plt.show()
plt.close()
diff --git a/examples/base/helmholtz_resonator.py b/examples/base/helmholtz_resonator.py
index d5d1d9a..9a9e441 100644
--- a/examples/base/helmholtz_resonator.py
+++ b/examples/base/helmholtz_resonator.py
@@ -1,40 +1,44 @@
from matplotlib import pyplot as plt
import fenics as fen
import mshr
import ufl
from rrompy.hfengines.linear_problem import HelmholtzProblemEngine as HPE
p = plt.jet()
n = 50
boundary = mshr.Polygon([fen.Point(0, 0), fen.Point(6, 0), fen.Point(6, 1),
fen.Point(1.3, 1), fen.Point(1.3, 1.2),
fen.Point(1.65, 1.2), fen.Point(1.65, 2.2),
fen.Point(.65, 2.2), fen.Point(.65, 1.2),
fen.Point(1, 1.2), fen.Point(1, 1), fen.Point(0, 1)])
mesh = mshr.generate_mesh(boundary, n)
-for k in range(10):
+for k in range(1):
kappa = .25 + .05 * k
ZR = 10.
x, y = fen.SpatialCoordinate(mesh)[:]
solver = HPE(kappa)
solver.V = fen.FunctionSpace(mesh, "P", 3)
solver.RobinBoundary = (lambda x, on_b: on_b and (fen.near(x[0], 6.)
- or fen.near(x[1], 2.25)))
+ or fen.near(x[1], 2.2)))
solver.NeumannBoundary = "REST"
solver.signR = + 1.
solver.NeumannDatum = [fen.Constant(0.),
ufl.conditional(ufl.And(ufl.gt(y, 0.), ufl.lt(y, 1.)),
fen.Constant(kappa), fen.Constant(0.))]
solver.RobinDatumH = [fen.Constant(0.),
ufl.conditional(ufl.gt(y, 1.25),
fen.Constant(kappa / ZR),
fen.Constant(kappa))]
uh = solver.solve(kappa)[0]
solver.plot(uh, name = "k={}".format(kappa))
print(solver.norm(uh))
+from rrompy.hfengines.base import MarginalProxyEngine
+
+ms = MarginalProxyEngine(solver, [None])
+print(ms.A(1))
\ No newline at end of file
diff --git a/examples/base/matrix_solver.py b/examples/base/matrix_solver.py
index 5db946c..4ebd883 100644
--- a/examples/base/matrix_solver.py
+++ b/examples/base/matrix_solver.py
@@ -1,30 +1,32 @@
import numpy as np
import scipy.sparse as sp
from rrompy.hfengines.base import MatrixEngineBase as MEB
test = 2
N = 100
verb = 0
solver = MEB(verbosity = verb)
solver.npar = 1
solver.nAs = 2
mu = 5.001
if test == 1:
solver.As = [sp.spdiags([np.arange(1, 1 + N)], [0], N, N),
- sp.eye(N)]
elif test == 2:
solver.setSolver("SOLVE")
fftB = np.fft.fft(np.eye(N)) * N**-.5
solver.As = [fftB.dot(np.multiply(np.arange(1, 1 + N), fftB.conj()).T),
- np.eye(N)]
-
solver.nbs = 1
solver.bs = [np.random.randn(N) + 1.j * np.random.randn(N)]
+solver._affinePoly = True
+solver.thAs = solver.getMonomialWeights(solver.nAs)
+solver.thbs = solver.getMonomialWeights(solver.nbs)
uh = solver.solve(mu)[0]
print(solver.norm(uh))
solver.plot(uh)
-solver.plot(solver.residual(uh, mu)[0], 'res')
+solver.plot(solver.residual(mu, uh)[0], 'res')
diff --git a/examples/base/solver.py b/examples/base/solver.py
index f0487f4..a0be1bd 100644
--- a/examples/base/solver.py
+++ b/examples/base/solver.py
@@ -1,75 +1,75 @@
import numpy as np
from rrompy.hfengines.linear_problem import \
HelmholtzSquareBubbleProblemEngine as HSBPE
from rrompy.hfengines.linear_problem import \
HelmholtzSquareTransmissionProblemEngine as HSTPE
from rrompy.hfengines.linear_problem import \
HelmholtzBoxScatteringProblemEngine as HBSPE
from rrompy.hfengines.linear_problem import \
HelmholtzCavityScatteringProblemEngine as HCSPE
-testNo = 4
+testNo = 2
verb = 0
if testNo == 1:
solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 20,
verbosity = verb)
mu = 12.**.5
solver.setSolver("BICG", {"tol" : 1e-15})
uh = solver.solve(mu)[0]
solver.plotmesh()
print(solver.norm(uh))
solver.plot(uh)
- solver.plot(solver.residual(uh, mu)[0], 'res')
+ solver.plot(solver.residual(mu, uh)[0], name = 'res')
###########
elif testNo in [2, -2]:
solver = HSTPE(nT = 1, nB = 2, theta = np.pi * 20 / 180, kappa = 4.,
n = 50, verbosity = verb)
mu = 4.
- uref = solver.liftDirichletData(mu)
+ uref = solver.liftDirichletData()
if testNo > 0:
uh = solver.solve(mu)[0]
utot = uh - uref
else:
- utot = solver.solve(mu, homogeneized = True)[0]
+ utot = solver.solve(mu)[0]
uh = utot + uref
print(solver.norm(uh))
print(solver.norm(uref))
solver.plot(uh)
solver.plot(uref, name = 'u_Dir')
solver.plot(utot, name = 'u_tot')
- solver.plot(solver.residual(uh, mu)[0], 'res')
- solver.plot(solver.residual(utot, mu, homogeneized = True)[0], 'res_tot')
+ solver.plot(solver.residual(mu, uh)[0], name = 'res')
+ solver.plot(solver.residual(mu, utot)[0], name = 'res_tot')
###########
elif testNo in [3, -3]:
solver = HBSPE(R = 5, kappa = 12**.5, theta = - np.pi * 60 / 180, n = 30,
- verbosity = verb)
+ verbosity = verb, homogeneized = (testNo < 0))
mu = 12**.5
- uref = solver.liftDirichletData(mu)
+ uref = solver.liftDirichletData()
if testNo > 0:
uh = solver.solve(mu)[0]
utot = uh - uref
else:
- utot = solver.solve(mu, homogeneized = True)[0]
+ utot = solver.solve(mu)[0]
uh = utot + uref
solver.plotmesh()
print(solver.norm(uh))
print(solver.norm(utot))
solver.plot(uh)
solver.plot(utot, name = 'u_tot')
- solver.plot(solver.residual(uh, mu)[0], 'res')
- solver.plot(solver.residual(utot, mu, homogeneized = True)[0], 'res_tot')
+ solver.plot(solver.residual(mu, uh)[0], 'res')
+ solver.plot(solver.residual(mu, utot)[0], 'res_tot')
###########
elif testNo == 4:
solver = HCSPE(kappa = 5, n = 30, verbosity = verb)
mu = 10
uh = solver.solve(mu)[0]
solver.plotmesh()
print(solver.norm(uh))
solver.plot(uh)
- solver.plot(solver.residual(uh, mu)[0], 'res')
+ solver.plot(solver.residual(mu, uh)[0], 'res')
diff --git a/examples/diapason/diapason_engine.py b/examples/diapason/diapason_engine.py
index 355781d..645509a 100644
--- a/examples/diapason/diapason_engine.py
+++ b/examples/diapason/diapason_engine.py
@@ -1,131 +1,134 @@
import numpy as np
import fenics as fen
import ufl
from rrompy.hfengines.vector_linear_problem import \
LinearElasticityHelmholtzProblemEngine as LEHPE
from rrompy.hfengines.vector_linear_problem import \
LinearElasticityHelmholtzProblemEngineDamped as LEHPED
class DiapasonEngine(LEHPE):
def __init__(self, kappa:float, c:float, rho:float, E:float, nu:float,
T:float, theta:float, phi:float, meshNo : int = 1,
deg : int = 1, degree_threshold : int = np.inf,
- verbosity : int = 10, timestamp : bool = True):
+ homogeneized : bool = False, verbosity : int = 10,
+ timestamp : bool = True):
super().__init__(mu0 = kappa, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
mesh = fen.Mesh("../data/mesh/diapason_{}.xml".format(meshNo))
subdomains = fen.MeshFunction("size_t", mesh,
("../data/mesh/diapason_{}_physical_"
"region.xml").format(meshNo))
meshBall = fen.SubMesh(mesh, subdomains, 2)
meshFork = fen.SubMesh(mesh, subdomains, 1)
Hball = np.max(meshBall.coordinates()[:, 1]) #.00257
Ltot = np.max(mesh.coordinates()[:, 1]) #.1022
Lhandle = np.max(meshFork.coordinates()[:, 1]) #.026
Lrod = Ltot - Lhandle #.0762
L2var = (Lrod / 4.) ** 2.
Ehandle_ratio = 3.
rhohandle_ratio = 1.5
kWave = (np.cos(theta) * np.cos(phi), np.sin(phi),
np.sin(theta) * np.cos(phi))
x, y, z = fen.SpatialCoordinate(mesh)[:]
yCorr = y - Ltot
compPlane = kWave[0] * x + kWave[1] * y + kWave[2] * z
xPlane, yPlane, zPlane = (xx - compPlane * xx for xx in (x, y, z))
xOrtho, yOrtho, zOrtho = (compPlane * xx for xx in (x, y, z))
forcingBase = (T / (2. * np.pi * L2var)**.5
* fen.exp(- (xPlane**2. + yPlane**2. + zPlane**2.)
/ (2.*L2var)))
forcingWeight = np.real(kappa) / c * (xOrtho + yOrtho + zOrtho)
neumannDatum = [ufl.as_vector(tuple(forcingBase
* fen.cos(forcingWeight)
* kWavedir for kWavedir in kWave)),
ufl.as_vector(tuple(forcingBase
* fen.sin(forcingWeight)
* kWavedir for kWavedir in kWave))]
lambda_ = E * nu / (1. + nu) / (1. - 2. * nu)
mu_ = E / (1. + nu)
lambda_eff = ufl.conditional(ufl.ge(y, Lhandle), fen.Constant(lambda_),
fen.Constant(Ehandle_ratio * lambda_))
mu_eff = ufl.conditional(ufl.ge(y, Lhandle), fen.Constant(mu_),
fen.Constant(Ehandle_ratio * mu_))
rho_eff = ufl.conditional(ufl.ge(y, Lhandle), fen.Constant(rho),
fen.Constant(rhohandle_ratio * rho))
self.lambda_ = lambda_eff
self.mu_ = mu_eff
self.rho_ = rho_eff
self.V = fen.VectorFunctionSpace(mesh, "P", deg)
self.DirichletBoundary = lambda x, on_b: on_b and x[1] < Hball
self.NeumannBoundary = "REST"
self.forcingTerm = neumannDatum
class DiapasonEngineDamped(LEHPED):
def __init__(self, kappa:float, c:float, rho:float, E:float, nu:float,
T:float, theta:float, phi:float, dampingEta:float,
meshNo : int = 1, deg : int = 1,
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = kappa, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
self.eta = dampingEta
mesh = fen.Mesh("../data/mesh/diapason_{}.xml".format(meshNo))
subdomains = fen.MeshFunction("size_t", mesh,
("../data/mesh/diapason_{}_physical_"
"region.xml").format(meshNo))
meshBall = fen.SubMesh(mesh, subdomains, 2)
meshFork = fen.SubMesh(mesh, subdomains, 1)
Hball = np.max(meshBall.coordinates()[:, 1]) #.00257
Ltot = np.max(mesh.coordinates()[:, 1]) #.1022
Lhandle = np.max(meshFork.coordinates()[:, 1]) #.026
Lrod = Ltot - Lhandle #.0762
L2var = (Lrod / 4.) ** 2.
Ehandle_ratio = 3.
rhohandle_ratio = 1.5
kWave = (np.cos(theta) * np.cos(phi), np.sin(phi),
np.sin(theta) * np.cos(phi))
x, y, z = fen.SpatialCoordinate(mesh)[:]
yCorr = y - Ltot
compPlane = kWave[0] * x + kWave[1] * y + kWave[2] * z
xPlane, yPlane, zPlane = (xx - compPlane * xx for xx in (x, y, z))
xOrtho, yOrtho, zOrtho = (compPlane * xx for xx in (x, y, z))
forcingBase = (T / (2. * np.pi * L2var)**.5
* fen.exp(- (xPlane**2. + yPlane**2. + zPlane**2.)
/ (2.*L2var)))
forcingWeight = np.real(kappa) / c * (xOrtho + yOrtho + zOrtho)
neumannDatum = [ufl.as_vector(tuple(forcingBase
* fen.cos(forcingWeight)
* kWavedir for kWavedir in kWave)),
ufl.as_vector(tuple(forcingBase
* fen.sin(forcingWeight)
* kWavedir for kWavedir in kWave))]
lambda_ = E * nu / (1. + nu) / (1. - 2. * nu)
mu_ = E / (1. + nu)
lambda_eff = ufl.conditional(ufl.ge(y, Lhandle), fen.Constant(lambda_),
fen.Constant(Ehandle_ratio * lambda_))
mu_eff = ufl.conditional(ufl.ge(y, Lhandle), fen.Constant(mu_),
fen.Constant(Ehandle_ratio * mu_))
rho_eff = ufl.conditional(ufl.ge(y, Lhandle), fen.Constant(rho),
fen.Constant(rhohandle_ratio * rho))
self.lambda_ = lambda_eff
self.mu_ = mu_eff
self.rho_ = rho_eff
self.V = fen.VectorFunctionSpace(mesh, "P", deg)
self.DirichletBoundary = lambda x, on_b: on_b and x[1] < Hball
self.NeumannBoundary = "REST"
self.forcingTerm = neumannDatum
diff --git a/examples/diapason/greedy.py b/examples/diapason/greedy.py
index 3121583..7debb24 100644
--- a/examples/diapason/greedy.py
+++ b/examples/diapason/greedy.py
@@ -1,129 +1,129 @@
import numpy as np
from diapason_engine import DiapasonEngine, DiapasonEngineDamped
from rrompy.reduction_methods.greedy import RationalInterpolantGreedy as RI
from rrompy.reduction_methods.greedy import ReducedBasisGreedy as RB
from rrompy.solver.fenics import L2NormMatrix
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
verb = 5
timed = False
algo = "RI"
#algo = "RB"
polyBasis = "LEGENDRE"
#polyBasis = "CHEBYSHEV"
#polyBasis = "MONOMIAL"
if timed: verb = 0
dampingEta = 0 * 1e4 / 2. / np.pi
k0s = np.linspace(2.5e2, 7.5e3, 100)
#k0s = np.linspace(2.5e3, 1.5e4, 100)
#k0s = np.linspace(5.0e4, 1.0e5, 100)
k0s = np.linspace(2.0e5, 2.5e5, 100)
kl, kr = min(k0s), max(k0s)
theta = 20. * np.pi / 180.
phi = 10. * np.pi / 180.
c = 3.e2
rho = 8e3 * (2. * np.pi) ** 2.
E = 1.93e11
nu = .3
T = 1e6
###
if np.isclose(dampingEta, 0.):
solver = DiapasonEngine(kappa = np.mean(np.power(k0s, 2.)) ** .5, c = c,
rho = rho, E = E, nu = nu, T = T, theta = theta,
phi = phi, meshNo = 1, degree_threshold = 8,
verbosity = 0)
else:
solver = DiapasonEngineDamped(kappa = np.mean(k0s), c = c, rho = rho,
E = E, nu = nu, T = T, theta = theta,
phi = phi, dampingEta = dampingEta,
meshNo = 1, degree_threshold = 8,
verbosity = 0)
params = {'sampler':QS([kl, kr], "UNIFORM"),#, solver.rescalingExp),
'nTestPoints':500, 'greedyTol':1e-2, 'S':5, 'polybasis':polyBasis,
-# 'errorEstimatorKind':'BARE'}
-# 'errorEstimatorKind':'BASIC'}
- 'errorEstimatorKind':'EXACT'}
+# 'errorEstimatorKind':'DIAGONAL'}
+# 'errorEstimatorKind':'INTERPOLATORY'}
+ 'errorEstimatorKind':'AFFINE'}
if algo == "RI":
approx = RI(solver, mu0 = solver.mu0, approxParameters = params,
verbosity = verb)
else:
params.pop("polybasis")
params.pop("errorEstimatorKind")
approx = RB(solver, mu0 = solver.mu0, approxParameters = params,
verbosity = verb)
approx.initEstimatorNormEngine(L2NormMatrix(solver.V))
if timed:
from time import clock
start_time = clock()
approx.greedy()
print("Time: ", clock() - start_time)
else:
approx.greedy(True)
polesApp = approx.getPoles()
print("Poles:\n", polesApp)
approx.samplingEngine.verbosity = 0
approx.trainedModel.verbosity = 0
approx.verbosity = 0
kl, kr = np.real(kl), np.real(kr)
from matplotlib import pyplot as plt
normApp = np.zeros(len(k0s))
norm = np.zeros_like(normApp)
res = np.zeros_like(normApp)
err = np.zeros_like(normApp)
for j in range(len(k0s)):
normApp[j] = approx.normApprox(k0s[j])
norm[j] = approx.normHF(k0s[j])
res[j] = (approx.estimatorNormEngine.norm(
approx.getRes(k0s[j], duality = False))
/ approx.estimatorNormEngine.norm(
approx.getRHS(k0s[j], duality = False)))
err[j] = approx.normErr(k0s[j]) / norm[j]
resApp = approx.errorEstimator(k0s)
plt.figure()
plt.semilogy(k0s, norm)
plt.semilogy(k0s, normApp, '--')
plt.semilogy(np.real(approx.mus.data),
1.05*np.max(norm)*np.ones_like(approx.mus.data, dtype = float),
'rx')
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
plt.figure()
plt.semilogy(k0s, res)
plt.semilogy(k0s, resApp, '--')
plt.semilogy(np.real(approx.mus.data),
approx.greedyTol*np.ones_like(approx.mus.data, dtype = float),
'rx')
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
plt.figure()
plt.semilogy(k0s, err)
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
mask = (np.real(polesApp) < kl) | (np.real(polesApp) > kr)
print("Outliers:", polesApp[mask])
polesAppEff = polesApp[~mask]
plt.figure()
plt.plot(np.real(polesAppEff), np.imag(polesAppEff), 'kx')
plt.axis('equal')
plt.grid()
plt.show()
plt.close()
diff --git a/examples/from_papers/greedy_internalBox.py b/examples/from_papers/greedy_internalBox.py
index caa2d7f..adc9ea4 100644
--- a/examples/from_papers/greedy_internalBox.py
+++ b/examples/from_papers/greedy_internalBox.py
@@ -1,114 +1,117 @@
import numpy as np
import fenics as fen
from rrompy.hfengines.linear_problem import HelmholtzProblemEngine as HPE
from rrompy.reduction_methods.greedy import RationalInterpolantGreedy as RI
from rrompy.reduction_methods.greedy import ReducedBasisGreedy as RB
from rrompy.solver.fenics import L2NormMatrix
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
-dim = 3
+dim = 2
verb = 5
timed = False
algo = "RI"
#algo = "RB"
polyBasis = "LEGENDRE"
-#polyBasis = "CHEBYSHEV"
+polyBasis = "CHEBYSHEV"
#polyBasis = "MONOMIAL"
k0s = np.power(np.linspace(500 ** 2., 2250 ** 2., 200), .5)
k0 = np.mean(np.power(k0s, 2.)) ** .5
kl, kr = min(k0s), max(k0s)
params = {'sampler':QS([kl, kr], "UNIFORM", 2.), 'nTestPoints':500,
'greedyTol':1e-2, 'S':2, 'polybasis':polyBasis,
- 'errorEstimatorKind':'BASIC'}
+# 'errorEstimatorKind':'AFFINE'}
+ 'errorEstimatorKind':'DISCREPANCY'}
+# 'errorEstimatorKind':'INTERPOLATORY'}
+# 'errorEstimatorKind':'LOCALL2'}
if dim == 2:
mesh = fen.RectangleMesh(fen.Point(0., 0.), fen.Point(.1, .15), 10, 15)
x, y = fen.SpatialCoordinate(mesh)[:]
f = fen.exp(- 1e2 * (x + y))
else:#if dim == 3:
mesh = fen.BoxMesh(fen.Point(0., 0., 0.), fen.Point(.1, .15, .25), 4, 6,10)
x, y, z = fen.SpatialCoordinate(mesh)[:]
f = fen.exp(- 1e2 * (x + y + z))
solver = HPE(np.real(k0), verbosity = verb)
solver.V = fen.FunctionSpace(mesh, "P", 3)
solver.refractionIndex = fen.Constant(1. / 54.6)
solver.forcingTerm = f
solver.NeumannBoundary = "ALL"
#########
if algo == "RI":
approx = RI(solver, mu0 = k0, approxParameters = params, verbosity = verb)
else:
params.pop("polybasis")
params.pop("errorEstimatorKind")
approx = RB(solver, mu0 = k0, approxParameters = params, verbosity = verb)
approx.initEstimatorNormEngine(L2NormMatrix(solver.V))
if timed:
from time import clock
start_time = clock()
approx.greedy()
print("Time: ", clock() - start_time)
else:
approx.greedy(True)
approx.samplingEngine.verbosity = 0
approx.verbosity = 0
kl, kr = np.real(kl), np.real(kr)
from matplotlib import pyplot as plt
normApp = np.zeros(len(k0s))
norm = np.zeros_like(normApp)
res = np.zeros_like(normApp)
err = np.zeros_like(normApp)
for j in range(len(k0s)):
normApp[j] = approx.normApprox(k0s[j])
norm[j] = approx.normHF(k0s[j])
res[j] = (approx.estimatorNormEngine.norm(
approx.getRes(k0s[j], duality = False))
/ approx.estimatorNormEngine.norm(
approx.getRHS(k0s[j], duality = False)))
err[j] = approx.normErr(k0s[j]) / approx.normHF(k0s[j])
resApp = approx.errorEstimator(k0s)
plt.figure()
plt.plot(k0s, norm)
plt.plot(k0s, normApp, '--')
plt.plot(np.real(approx.mus(0)),
1.05*np.max(norm)*np.ones(approx.mus.shape, dtype = float), 'rx')
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
plt.figure()
plt.semilogy(k0s, res)
plt.semilogy(k0s, resApp, '--')
plt.semilogy(np.real(approx.mus(0)),
4.*np.max(resApp)*np.ones(approx.mus.shape, dtype = float), 'rx')
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
plt.figure()
plt.semilogy(k0s, err)
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
polesApp = approx.getPoles()
mask = (np.real(polesApp) < kl) | (np.real(polesApp) > kr)
print("Outliers:", polesApp[mask])
polesApp = polesApp[~mask]
plt.figure()
plt.plot(np.real(polesApp), np.imag(polesApp), 'kx')
plt.axis('equal')
plt.grid()
plt.show()
plt.close()
diff --git a/examples/from_papers/greedy_scatteringAirfoil.py b/examples/from_papers/greedy_scatteringAirfoil.py
index ade4b37..46c8187 100644
--- a/examples/from_papers/greedy_scatteringAirfoil.py
+++ b/examples/from_papers/greedy_scatteringAirfoil.py
@@ -1,153 +1,151 @@
import numpy as np
import fenics as fen
import ufl
from rrompy.hfengines.linear_problem import \
HelmholtzBoxScatteringProblemEngine as HSP
from rrompy.reduction_methods.greedy import RationalInterpolantGreedy as RI
from rrompy.reduction_methods.greedy import ReducedBasisGreedy as RB
from rrompy.solver.fenics import fenONE, L2NormMatrix
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
verb = 2
timed = False
algo = "RI"
#algo = "RB"
polyBasis = "LEGENDRE"
#polyBasis = "CHEBYSHEV"
#polyBasis = "MONOMIAL"
homog = True
homog = False
k0s = np.linspace(5, 20, 25)
k0 = np.mean(k0s)
kl, kr = min(k0s), max(k0s)
params = {'sampler':QS([kl, kr], "UNIFORM"), 'nTestPoints':500,
'greedyTol':1e-2, 'S':10, 'polybasis':polyBasis,
- 'errorEstimatorKind':'BARE'}
-# 'errorEstimatorKind':'BASIC'}
-# 'errorEstimatorKind':'EXACT'}
+ 'errorEstimatorKind':'DIAGONAL'}
+# 'errorEstimatorKind':'INTERPOLATORY'}
+# 'errorEstimatorKind':'AFFINE'}
#########
PI = np.pi
R = 2
def Dboundary(x, on_boundary):
return on_boundary and (x[0]**2+x[1]**2)**.5 < .95 * R
kappa = 10
theta = PI * - 45 / 180.
mu = 1.1
epsilon = .1
mesh = fen.Mesh('../data/mesh/airfoil.xml')
c, s = np.cos(theta), np.sin(theta)
x, y = fen.SpatialCoordinate(mesh)[:]
u0R = - fen.cos(kappa * (c * x + s * y))
u0I = - fen.sin(kappa * (c * x + s * y))
checkReal = x**2-x+y**2
rhop5 = ((x**2+y**2)/((x-1)**2+y**2))**.25
phiroot1 = fen.atan(-y/(x**2-x+y**2)) / 2
phiroot2 = fen.atan(-y/(x**2-x+y**2)) / 2 - PI * ufl.sign(-y/(x**2-x+y**2)) / 2
kappam1 = (((rhop5*fen.cos(phiroot1)+.5)**2.+(rhop5*fen.sin(phiroot1))**2.)/
((rhop5*fen.cos(phiroot1)-1.)**2.+(rhop5*fen.sin(phiroot1))**2.)
)**.5 - mu
kappam2 = (((rhop5*fen.cos(phiroot2)+.5)**2.+(rhop5*fen.sin(phiroot2))**2.)/
((rhop5*fen.cos(phiroot2)-1.)**2.+(rhop5*fen.sin(phiroot2))**2.)
)**.5 - mu
Heps1 = .9 * .5 * (1 + kappam1/epsilon + fen.sin(PI*kappam1/epsilon) / PI) + .1
Heps2 = .9 * .5 * (1 + kappam2/epsilon + fen.sin(PI*kappam2/epsilon) / PI) + .1
cTT = ufl.conditional(ufl.le(kappam1, epsilon), Heps1, fenONE)
c_F = fen.Constant(.1)
cFT = ufl.conditional(ufl.le(kappam2, epsilon), Heps2, fenONE)
c_F = fen.Constant(.1)
cT = ufl.conditional(ufl.ge(kappam1, - epsilon), cTT, c_F)
cF = ufl.conditional(ufl.ge(kappam2, - epsilon), cFT, c_F)
a = ufl.conditional(ufl.ge(checkReal, 0.), cT, cF)
solver = HSP(R, np.real(k0), theta, n = 1, verbosity = verb,
- degree_threshold = 8)
+ degree_threshold = 8, homogeneized = homog)
solver.omega = np.real(k0)
solver.V = fen.FunctionSpace(mesh, "P", 2)
solver.diffusivity = a
solver.DirichletBoundary = Dboundary
solver.RobinBoundary = "REST"
solver.DirichletDatum = [u0R, u0I]
#########
if algo == "RI":
- approx = RI(solver, mu0 = k0, approxParameters = params, verbosity = verb,
- homogeneized = homog)
+ approx = RI(solver, mu0 = k0, approxParameters = params, verbosity = verb)
else:
params.pop("polybasis")
params.pop("errorEstimatorKind")
- approx = RB(solver, mu0 = k0, approxParameters = params, verbosity = verb,
- homogeneized = homog)
+ approx = RB(solver, mu0 = k0, approxParameters = params, verbosity = verb)
approx.initEstimatorNormEngine(L2NormMatrix(solver.V))
if timed:
from time import clock
start_time = clock()
approx.greedy()
print("Time: ", clock() - start_time)
else:
approx.greedy(True)
approx.samplingEngine.verbosity = 0
approx.verbosity = 0
kl, kr = np.real(kl), np.real(kr)
from matplotlib import pyplot as plt
normApp = np.zeros(len(k0s))
norm = np.zeros_like(normApp)
res = np.zeros_like(normApp)
err = np.zeros_like(normApp)
for j in range(len(k0s)):
normApp[j] = approx.normApprox(k0s[j])
norm[j] = approx.normHF(k0s[j])
res[j] = (approx.estimatorNormEngine.norm(
- approx.getRes(k0s[j], homogeneized = homog, duality = False))
+ approx.getRes(k0s[j], duality = False))
/ approx.estimatorNormEngine.norm(
- approx.getRHS(k0s[j], homogeneized = homog, duality = False)))
+ approx.getRHS(k0s[j], duality = False)))
err[j] = approx.normErr(k0s[j]) / approx.normHF(k0s[j])
resApp = approx.errorEstimator(k0s)
plt.figure()
plt.plot(k0s, norm)
plt.plot(k0s, normApp, '--')
plt.plot(np.real(approx.mus(0)),
1.05*np.max(norm)*np.ones(approx.mus.shape, dtype = float), 'rx')
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
plt.figure()
plt.semilogy(k0s, res)
plt.semilogy(k0s, resApp, '--')
plt.semilogy(np.real(approx.mus(0)),
4.*np.max(resApp)*np.ones(approx.mus.shape, dtype = float), 'rx')
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
plt.figure()
plt.semilogy(k0s, err)
plt.xlim([kl, kr])
plt.grid()
plt.show()
plt.close()
polesApp = approx.getPoles()
mask = (np.real(polesApp) < kl) | (np.real(polesApp) > kr)
print("Outliers:", polesApp[mask])
polesApp = polesApp[~mask]
plt.figure()
plt.plot(np.real(polesApp), np.imag(polesApp), 'kx')
plt.axis('equal')
plt.grid()
plt.show()
plt.close()
diff --git a/examples/from_papers/pod_scatteringAirfoil.py b/examples/from_papers/pod_scatteringAirfoil.py
index d0cf6b4..dbb8297 100644
--- a/examples/from_papers/pod_scatteringAirfoil.py
+++ b/examples/from_papers/pod_scatteringAirfoil.py
@@ -1,132 +1,130 @@
import numpy as np
import fenics as fen
import ufl
from rrompy.hfengines.linear_problem import \
HelmholtzBoxScatteringProblemEngine as HSP
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
from rrompy.solver.fenics import fenONE
from operator import itemgetter
def subdict(d, ks):
return dict(zip(ks, itemgetter(*ks)(d)))
verb = 0
####################
homog = True
#homog = False
####################
test = "solve"
test = "approx"
plotSamples = True
k0 = 10
kLeft, kRight = 8 + 0.j, 12 + 0.j
ktar = 11
ktars = np.linspace(8, 12, 21) + 0.j
PI = np.pi
R = 2
def Dboundary(x, on_boundary):
return on_boundary and (x[0]**2+x[1]**2)**.5 < .95 * R
kappa = 10
theta = PI * - 45 / 180.
mu = 1.1
epsilon = .1
mesh = fen.Mesh('../data/mesh/airfoil.xml')
c, s = np.cos(theta), np.sin(theta)
x, y = fen.SpatialCoordinate(mesh)[:]
u0R = - fen.cos(kappa * (c * x + s * y))
u0I = - fen.sin(kappa * (c * x + s * y))
checkReal = x**2-x+y**2
rhop5 = ((x**2+y**2)/((x-1)**2+y**2))**.25
phiroot1 = fen.atan(-y/(x**2-x+y**2)) / 2
phiroot2 = fen.atan(-y/(x**2-x+y**2)) / 2 - PI * ufl.sign(-y/(x**2-x+y**2)) / 2
kappam1 = (((rhop5*fen.cos(phiroot1)+.5)**2.+(rhop5*fen.sin(phiroot1))**2.)/
((rhop5*fen.cos(phiroot1)-1.)**2.+(rhop5*fen.sin(phiroot1))**2.)
)**.5 - mu
kappam2 = (((rhop5*fen.cos(phiroot2)+.5)**2.+(rhop5*fen.sin(phiroot2))**2.)/
((rhop5*fen.cos(phiroot2)-1.)**2.+(rhop5*fen.sin(phiroot2))**2.)
)**.5 - mu
Heps1 = .9 * .5 * (1 + kappam1/epsilon + fen.sin(PI*kappam1/epsilon) / PI) + .1
Heps2 = .9 * .5 * (1 + kappam2/epsilon + fen.sin(PI*kappam2/epsilon) / PI) + .1
cTT = ufl.conditional(ufl.le(kappam1, epsilon), Heps1, fenONE)
c_F = fen.Constant(.1)
cFT = ufl.conditional(ufl.le(kappam2, epsilon), Heps2, fenONE)
c_F = fen.Constant(.1)
cT = ufl.conditional(ufl.ge(kappam1, - epsilon), cTT, c_F)
cF = ufl.conditional(ufl.ge(kappam2, - epsilon), cFT, c_F)
a = ufl.conditional(ufl.ge(checkReal, 0.), cT, cF)
###
solver = HSP(R, np.abs(k0), theta, n = 1, verbosity = verb,
- degree_threshold = 8)
+ degree_threshold = 8, homogeneized = homog)
solver.V = fen.FunctionSpace(mesh, "P", 3)
solver.diffusivity = a
solver.DirichletBoundary = Dboundary
solver.RobinBoundary = "REST"
solver.DirichletDatum = [u0R, u0I]
###
if test == "solve":
- uinc = solver.liftDirichletData(k0)
+ uinc = solver.liftDirichletData()
if homog:
- uhtot = solver.solve(k0, homogeneized = homog)[0]
+ uhtot = solver.solve(k0)[0]
uh = uhtot + uinc
else:
- uh = solver.solve(k0, homogeneized = homog)[0]
+ uh = solver.solve(k0)[0]
uhtot = uh - uinc
print(solver.norm(uh))
print(solver.norm(uhtot))
solver.plot(fen.project(a, solver.V).vector(), what = 'Real',
name = 'a')
solver.plot(uinc, what = 'Real', name = 'u_inc')
solver.plot(uh, what = 'ABS')
solver.plot(uhtot, what = 'ABS', name = 'u + u_inc')
elif test == "approx":
params = {'N':8, 'M':8, 'R':9, 'S':9, 'POD':True,
'polybasis':"CHEBYSHEV",
'sampler':QS([kLeft, kRight], "CHEBYSHEV")}
parRI = subdict(params, ['N', 'M', 'S', 'POD', 'polybasis',
'sampler'])
parRB = subdict(params, ['R', 'S', 'POD', 'sampler'])
approxRI = RI(solver, mu0 = np.mean([kLeft, kRight]),
- approxParameters = parRI, verbosity = verb,
- homogeneized = homog)
+ approxParameters = parRI, verbosity = verb)
approxRB = RB(solver, mu0 = np.mean([kLeft, kRight]),
- approxParameters = parRB, verbosity = verb,
- homogeneized = homog)
+ approxParameters = parRB, verbosity = verb)
approxRI.setupApprox()
approxRB.setupApprox()
if plotSamples:
approxRI.plotSamples()
approxRI.plotHF(ktar, name = 'u_HF')
approxRI.plotApprox(ktar, name = 'u_RI''')
approxRI.plotErr(ktar, name = 'err_RI''')
approxRI.plotRes(ktar, name = 'res_RI''')
approxRB.plotApprox(ktar, name = 'u_RB')
approxRB.plotErr(ktar, name = 'err_RB')
approxRB.plotRes(ktar, name = 'res_RB')
HFNorm, RHSNorm = approxRI.normHF(ktar), approxRI.normRHS(ktar)
RIRes, RIErr = approxRI.normRes(ktar), approxRI.normErr(ktar)
RBRes, RBErr = approxRB.normRes(ktar), approxRB.normErr(ktar)
print('HFNorm:\t{}\nRHSNorm:\t{}'.format(HFNorm, RHSNorm))
print('RIRes:\t{}\nRIErr:\t{}'.format(RIRes, RIErr))
print('RBRes:\t{}\nRBErr:\t{}'.format(RBRes, RBErr))
print('\nPoles RI'':')
print(approxRI.getPoles())
diff --git a/examples/pod/RationalHermiteInterpolant.py b/examples/pod/RationalHermiteInterpolant.py
index d62aed4..87d8f60 100644
--- a/examples/pod/RationalHermiteInterpolant.py
+++ b/examples/pod/RationalHermiteInterpolant.py
@@ -1,133 +1,133 @@
import numpy as np
from rrompy.hfengines.linear_problem import \
HelmholtzSquareBubbleProblemEngine as HSBPE
from rrompy.hfengines.linear_problem import \
HelmholtzSquareTransmissionProblemEngine as HSTPE
from rrompy.hfengines.linear_problem import \
HelmholtzBoxScatteringProblemEngine as HBSPE
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
ManualSampler as MS)
testNo = 3
verb = 100
polyBasis = "CHEBYSHEV"
#polyBasis = "LEGENDRE"
#polyBasis = "MONOMIAL"
rep = "REPEAT"
#rep = "TILE"
homog = True
#homog = False
if testNo == 1:
k0s = np.power([10 + 0.j, 14 + 0.j], .5)
k0 = np.mean(np.power(k0s, 2.)) ** .5
samplerBase = QS(k0s, "CHEBYSHEV", 2.)
S = 8
if rep == "REPEAT":
points = np.repeat(samplerBase.generatePoints(2).data,
int(np.ceil(S / 2)))
else: # if rep == "TILE":
points = np.tile(samplerBase.generatePoints(2).data,
int(np.ceil(S / 2)))
params = {'N':7, 'M':6, 'S':S, 'POD':True, 'polybasis':polyBasis,
'sampler':MS(k0s, points = points, 2.)}
ktar = (11 + .5j) ** .5
solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40,
verbosity = verb)
solver.omega = np.real(k0)
approx = RI(solver, mu0 = k0, approxParameters = params,
verbosity = verb)
approx.setupApprox()
approx.plotApprox(ktar, name = 'u_Pade''')
approx.plotHF(ktar, name = 'u_HF')
approx.plotErr(ktar, name = 'err')
approx.plotRes(ktar, name = 'res')
appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
print('\nPoles Pade'':')
print(approx.getPoles())
############
elif testNo == 2:
k0s = [3.85 + 0.j, 4.15 + 0.j]
k0 = np.mean(k0s)
ktar = 4 + 0.j
samplerBase = QS(k0s, "CHEBYSHEV", 2.)
S = 10
if rep == "REPEAT":
points = np.repeat(samplerBase.generatePoints(5).data,
int(np.ceil(S / 5)))
else: # if rep == "TILE":
points = np.tile(samplerBase.generatePoints(5).data,
int(np.ceil(S / 5)))
params = {'N':8, 'M':9, 'S':S, 'POD':True, 'polybasis':polyBasis,
'sampler':MS(k0s, points = points, 2.)}
solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 4., n = 50,
- verbosity = verb)
+ verbosity = verb, homogeneized = homog)
solver.omega = np.real(k0)
approx = RI(solver, mu0 = k0, approxParameters = params,
- verbosity = verb, homogeneized = homog)
+ verbosity = verb)
approx.setupApprox()
# approx.plotSamples()
approx.plotApprox(ktar, name = 'u_Pade''')
approx.plotHF(ktar, name = 'u_HF')
approx.plotErr(ktar, name = 'err')
approx.plotRes(ktar, name = 'res')
appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
print('\nPoles Pade'':')
print(approx.getPoles())
############
elif testNo == 3:
k0s = [2., 5.]
k0 = np.mean(k0s)
ktar = 4.5 - 0.j
samplerBase = QS(k0s, "CHEBYSHEV")
S = 15
if rep == "REPEAT":
points = np.repeat(samplerBase.generatePoints(5).data,
int(np.ceil(S / 5)))
else: # if rep == "TILE":
points = np.tile(samplerBase.generatePoints(5).data,
int(np.ceil(S / 5)))
params = {'N':14, 'M':14, 'S':S, 'POD':True, 'polybasis':polyBasis,
'sampler':MS(k0s, points = points)}
solver = HBSPE(R = 7, kappa = 3, theta = - np.pi * 75 / 180, n = 40,
- verbosity = verb)
+ verbosity = verb, homogeneized = homog)
solver.omega = np.real(k0)
approx = RI(solver, mu0 = k0, approxParameters = params,
- verbosity = verb, homogeneized = homog)
+ verbosity = verb)
approx.setupApprox()
# approx.plotSamples()
approx.plotApprox(ktar, name = 'u_Pade''')
approx.plotHF(ktar, name = 'u_HF')
approx.plotErr(ktar, name = 'err')
approx.plotRes(ktar, name = 'res')
appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
print('\nPoles Pade'':')
print(approx.getPoles())
diff --git a/examples/pod/RationalInterpolant.py b/examples/pod/RationalInterpolant.py
index 51f7069..68e9b72 100644
--- a/examples/pod/RationalInterpolant.py
+++ b/examples/pod/RationalInterpolant.py
@@ -1,121 +1,121 @@
import numpy as np
from rrompy.hfengines.linear_problem import \
HelmholtzSquareBubbleProblemEngine as HSBPE
from rrompy.hfengines.linear_problem import \
HelmholtzSquareTransmissionProblemEngine as HSTPE
from rrompy.hfengines.linear_problem import \
HelmholtzBoxScatteringProblemEngine as HBSPE
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
testNo = 3
verb = 100
polyBasis = "CHEBYSHEV"
polyBasis = "LEGENDRE"
#polyBasis = "MONOMIAL"
homog = True
#homog = False
loadName = "RationalInterpolantModel.pkl"
if testNo in [1, -1]:
if testNo > 0:
k0s = np.power([10 + 0.j, 14 + 0.j], .5)
k0 = np.mean(np.power(k0s, 2.)) ** .5
params = {'N':4, 'M':3, 'S':5, 'POD':True, 'polybasis':polyBasis,
'sampler':QS(k0s, "CHEBYSHEV", 2.)}
ktar = (11 + .5j) ** .5
solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40,
verbosity = verb)
if testNo > 0:
solver.omega = np.real(k0)
approx = RI(solver, mu0 = k0, approxParameters = params,
verbosity = verb)
approx.setupApprox()
# approx.plotSamples()
else:
approx = RI(solver, mu0 = 0,
approxParameters = {'S':1, 'muBounds':[0, 1]},
verbosity = verb)
approx.loadTrainedModel(loadName)
approx.plotApprox(ktar, name = 'u_Pade''')
approx.plotHF(ktar, name = 'u_HF')
approx.plotErr(ktar, name = 'err')
approx.plotRes(ktar, name = 'res')
appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
print('\nPoles Pade'':')
print(approx.getPoles())
if testNo > 0:
approx.storeTrainedModel("RationalInterpolantModel",
forceNewFile = False)
print(approx.trainedModel.data.__dict__)
############
elif testNo == 2:
k0s = [3.85 + 0.j, 4.15 + 0.j]
k0 = np.mean(k0s)
ktar = 4 + 0.j
params = {'N':8, 'M':9, 'S':10, 'POD':True, 'polybasis':polyBasis,
'sampler':QS(k0s, "CHEBYSHEV", 2.)}
solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 4., n = 50,
- verbosity = verb)
+ verbosity = verb, homogeneized = homog)
solver.omega = np.real(k0)
approx = RI(solver, mu0 = k0, approxParameters = params,
- verbosity = verb, homogeneized = homog)
+ verbosity = verb)
approx.setupApprox()
# approx.plotSamples()
approx.plotApprox(ktar, name = 'u_Pade''')
approx.plotHF(ktar, name = 'u_HF')
approx.plotErr(ktar, name = 'err')
approx.plotRes(ktar, name = 'res')
appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
print('\nPoles Pade'':')
print(approx.getPoles())
############
elif testNo == 3:
k0s = [2., 5.]
k0 = np.mean(k0s)
ktar = 4.5 - 0.j
params = {'N':10, 'M':9, 'S':15, 'POD':True, 'polybasis':polyBasis,
'sampler':QS(k0s, "CHEBYSHEV")}
solver = HBSPE(R = 7, kappa = 3, theta = - np.pi * 75 / 180, n = 40,
- verbosity = verb)
+ verbosity = verb, homogeneized = homog)
solver.omega = np.real(k0)
approx = RI(solver, mu0 = k0, approxParameters = params,
- verbosity = verb, homogeneized = homog)
+ verbosity = verb)
approx.setupApprox()
# approx.plotSamples()
approx.plotApprox(ktar, name = 'u_Pade''')
approx.plotHF(ktar, name = 'u_HF')
approx.plotErr(ktar, name = 'err')
approx.plotRes(ktar, name = 'res')
appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
print('\nPoles Pade'':')
print(approx.getPoles())
diff --git a/examples/pod/ReducedBasis.py b/examples/pod/ReducedBasis.py
index f48f6bd..327d5fd 100644
--- a/examples/pod/ReducedBasis.py
+++ b/examples/pod/ReducedBasis.py
@@ -1,108 +1,108 @@
import numpy as np
from rrompy.hfengines.linear_problem import \
HelmholtzSquareBubbleProblemEngine as HSBPE
from rrompy.hfengines.linear_problem import \
HelmholtzSquareTransmissionProblemEngine as HSTPE
from rrompy.hfengines.linear_problem import \
HelmholtzBoxScatteringProblemEngine as HBSPE
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
testNo = 1
verb = 100
homog = True
#homog = False
loadName = "ReducedBasisModel.pkl"
if testNo in [1, -1]:
if testNo > 0:
k0s = np.power([10 + 0.j, 14 + 0.j], .5)
k0 = np.mean(np.power(k0s, 2.)) ** .5
params = {'S':5, 'R':4, 'POD':True,
'sampler':QS(k0s, "CHEBYSHEV", 2.)}
ktar = (11 + .5j) ** .5
solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40,
verbosity = verb)
if testNo > 0:
approx = RB(solver, mu0 = k0, approxParameters = params,
verbosity = verb)
approx.setupApprox()
# approx.plotSamples()
else:
approx = RB(solver, mu0 = 0,
approxParameters = {'S':1, 'muBounds':[0, 1]},
verbosity = verb)
approx.loadTrainedModel(loadName)
approx.plotApprox(ktar, name = 'u_RB')
approx.plotHF(ktar, name = 'u_HF')
approx.plotErr(ktar, name = 'err')
approx.plotRes(ktar, name = 'res')
appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
if testNo > 0:
approx.storeTrainedModel("ReducedBasisModel", forceNewFile = False)
print(approx.trainedModel.data.__dict__)
############
elif testNo == 2:
k0s = [3.85 + 0.j, 4.15 + 0.j]
k0 = np.mean(k0s)
ktar = 4 + .15j
params = {'S':10, 'R':9, 'POD':True,
'sampler':QS(k0s, "CHEBYSHEV", 2.)}
solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 4., n = 50,
- verbosity = verb)
+ verbosity = verb, homogeneized = homog)
solver.omega = np.real(k0)
approx = RB(solver, mu0 = k0, approxParameters = params,
- verbosity = verb, homogeneized = homog)
+ verbosity = verb)
approx.setupApprox()
# approx.plotSamples()
approx.plotApprox(ktar, name = 'u_RB')
approx.plotHF(ktar, name = 'u_HF')
approx.plotErr(ktar, name = 'err')
approx.plotRes(ktar, name = 'res')
appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
############
elif testNo == 3:
k0s = [2., 5.]
k0 = np.mean(k0s)
ktar = 4.5 - 0.j
params = {'S':15, 'R':10, 'POD':True, 'sampler':QS(k0s, "CHEBYSHEV")}
solver = HBSPE(R = 7, kappa = 3, theta = - np.pi * 75 / 180, n = 40,
- verbosity = verb)
+ verbosity = verb, homogeneized = homog)
solver.omega = np.real(k0)
approx = RB(solver, mu0 = k0, approxParameters = params,
- verbosity = verb, homogeneized = homog)
+ verbosity = verb)
approx.setupApprox()
# approx.plotSamples()
approx.plotApprox(ktar, name = 'u_RB')
approx.plotHF(ktar, name = 'u_HF')
approx.plotErr(ktar, name = 'err')
approx.plotRes(ktar, name = 'res')
appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
diff --git a/examples/pod/matrix_pod.py b/examples/pod/matrix_pod.py
index 8fbd742..3160c56 100644
--- a/examples/pod/matrix_pod.py
+++ b/examples/pod/matrix_pod.py
@@ -1,68 +1,71 @@
import numpy as np
import scipy.sparse as sp
from matplotlib import pyplot as plt
from rrompy.hfengines.base import MatrixEngineBase as MEB
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
test = 2
method = "RationalInterpolant"
#method = "ReducedBasis"
verb = 0
N = 100
solver = MEB(verbosity = verb)
solver.npar = 1
solver.nAs = 2
if test == 1:
solver.As = [sp.spdiags([np.arange(1, 1 + N)], [0], N, N),
- sp.eye(N)]
elif test == 2:
solver.setSolver("SOLVE")
fftB = np.fft.fft(np.eye(N)) * N**-.5
solver.As = [fftB.dot(np.multiply(np.arange(1, 1 + N), fftB.conj()).T),
- np.eye(N)]
np.random.seed(420)
solver.nbs = 1
solver.bs = [np.random.randn(N) + 1.j * np.random.randn(N)]
+solver._affinePoly = True
+solver.thAs = solver.getMonomialWeights(solver.nAs)
+solver.thbs = solver.getMonomialWeights(solver.nbs)
mu0 = 10.25
mutar = 12.5
murange = [5.25, 15.25]
if method == "RationalInterpolant":
params = {'N':10, 'M':9, 'S':11, 'POD':True, 'polybasis':"CHEBYSHEV",
'sampler':QS(murange, "CHEBYSHEV")}
approx = RI(solver, mu0 = mu0, approxParameters = params,
verbosity = verb)
elif method == "ReducedBasis":
params = {'R':10, 'S':11, 'POD':True, 'sampler':QS(murange, "CHEBYSHEV")}
approx = RB(solver, mu0 = mu0, approxParameters = params,
verbosity = verb)
approx.setupApprox()
approx.plotApprox(mutar, name = 'u_app')
approx.plotHF(mutar, name = 'u_HF')
approx.plotErr(mutar, name = 'err')
approx.plotRes(mutar, name = 'res')
appErr, solNorm = approx.normErr(mutar), approx.normHF(mutar)
resNorm, RHSNorm = approx.normRes(mutar), approx.normRHS(mutar)
print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
np.divide(appErr, solNorm)))
print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
np.divide(resNorm, RHSNorm)))
polesTrue = np.arange(1, 1 + N)
polesTrue = polesTrue[polesTrue >= murange[0]]
polesTrue = polesTrue[polesTrue <= murange[1]]
polesApp = approx.getPoles()
mask = (np.real(polesApp) < murange[0]) | (np.real(polesApp) > murange[1])
print("Outliers:", polesApp[mask])
polesApp = polesApp[~mask]
plt.figure()
plt.plot(np.real(polesApp), np.imag(polesApp), 'kx')
plt.plot(polesTrue, np.zeros_like(polesTrue), 'm.')
plt.axis('equal')
plt.grid()
plt.show()
plt.close()
diff --git a/examples/pod/with_error_plot.py b/examples/pod/with_error_plot.py
new file mode 100644
index 0000000..c436d68
--- /dev/null
+++ b/examples/pod/with_error_plot.py
@@ -0,0 +1,111 @@
+import numpy as np
+from rrompy.hfengines.linear_problem import \
+ HelmholtzSquareBubbleProblemEngine as HSBPE
+from rrompy.reduction_methods.standard import RationalInterpolant as RI
+from rrompy.reduction_methods.standard import RationalMovingLeastSquares as RIM
+from rrompy.reduction_methods.standard import ReducedBasis as RB
+from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
+
+verb = 100
+sol = "single"
+sol = "sweep"
+algo = "RI"
+algo = "RIM"
+#algo = "RB"
+polyBasis = "LEGENDRE"
+polyBasis = "CHEBYSHEV"
+#polyBasis = "MONOMIAL"
+radialBasis = "GAUSSIAN"
+#radialBasis = "THINPLATE"
+#radialBasis = "MULTIQUADRIC"
+#radialBasis = "NEARESTNEIGHBOR"
+radialBasisDen = "GAUSSIAN"
+radialBasisDen = "THINPLATE"
+radialBasisDen = "MULTIQUADRIC"
+radialBasisDen = "NEARESTNEIGHBOR"
+
+k0sC = np.power([7 + 0.j, 55 + 0.j], .5)
+k0 = np.mean(k0sC ** 2.) ** .5
+ktar = 14 ** .5
+
+n = 20
+solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40,
+ verbosity = verb)
+
+params = {'N':1, 'M':1, 'S':30, 'POD':True, 'polybasis':polyBasis,
+ 'sampler':QS(k0sC, "CHEBYSHEV", 2.)}
+
+if algo == "RI":
+ approx = RI(solver, mu0 = k0, approxParameters = params, verbosity = verb)
+elif algo == "RIM":
+ params["radialBasis"] = radialBasis
+ params["radialDirectionalWeights"] = [.75 * params["S"]]
+ params["radialBasisDen"] = radialBasisDen
+ params["nNearestNeighborDen"] = params["N"] + 1
+ approx = RIM(solver, mu0 = k0, approxParameters = params, verbosity = verb)
+else:
+ params.pop("N")
+ params.pop("M")
+ params.pop("polybasis")
+ approx = RB(solver, mu0 = k0, approxParameters = params, verbosity = verb)
+
+approx.setupApprox()
+if sol == "single":
+ approx.plotSamples(what = "REAL")
+ approx.plotApprox(ktar, what = "REAL", name = "uApp")
+ approx.plotHF(ktar, what = "REAL", name = "uHF")
+ approx.plotErr(ktar, what = "REAL", name = "err")
+ approx.plotRes(ktar, what = "REAL", name = "res")
+
+ appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+ resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
+ print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
+ np.divide(appErr, solNorm)))
+ print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+ np.divide(resNorm, RHSNorm)))
+poles = approx.getPoles()
+try:
+ print('Poles:', poles ** 2.)
+except: pass
+
+if sol == "sweep":
+ z0s = np.real(np.linspace(k0sC[0] ** 2., k0sC[1] ** 2., 100))
+ k0s = z0s ** .5
+ zl, zr = min(z0s), max(z0s)
+ approx.samplingEngine.verbosity = 0
+ approx.trainedModel.verbosity = 0
+ approx.verbosity = 0
+ from matplotlib import pyplot as plt
+# normRHS = approx.normRHS(k0s)
+ norm = approx.normHF(k0s)
+ normApp = approx.normApprox(k0s)
+# res = approx.normRes(k0s) / normRHS
+# err = approx.normErr(k0s) / norm
+
+ plt.figure()
+ plt.semilogy(z0s, norm)
+ plt.semilogy(z0s, normApp, '--')
+ plt.semilogy(np.real(approx.mus.data) ** 2.,
+ 1.05*np.max(norm)*np.ones_like(approx.mus.data, dtype = float),
+ 'rx')
+ plt.xlim([zl, zr])
+ plt.grid()
+ plt.show()
+ plt.close()
+
+# plt.figure()
+# plt.semilogy(z0s, res)
+# plt.xlim([zl, zr])
+# plt.grid()
+# plt.show()
+# plt.close()
+#
+# plt.figure()
+# plt.semilogy(z0s, err)
+# plt.xlim([zl, zr])
+# plt.grid()
+# plt.show()
+# plt.close()
+
+#for j, k in enumerate(k0s):
+# print(k ** 2., approx.getPoles(mu = k) ** 2., norm[j], normApp[j])
diff --git a/rrompy/hfengines/base/boundary_conditions.py b/rrompy/hfengines/base/boundary_conditions.py
index 4ed01fe..a62fb01 100644
--- a/rrompy/hfengines/base/boundary_conditions.py
+++ b/rrompy/hfengines/base/boundary_conditions.py
@@ -1,129 +1,129 @@
# 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 copy
from fenics import SubDomain, AutoSubDomain
from rrompy.utilities.base.types import GenExpr
from rrompy.solver.fenics import bdrFalse
from rrompy.utilities.exception_manager import RROMPyException
__all__ = ['BoundaryConditions']
class BoundaryConditions:
"""
Boundary conditions manager.
Attributes:
DirichletBoundary: Callable returning True when on Dirichlet boundary.
NeumannBoundary: Callable returning True when on Neumann boundary.
RobinBoundary: Callable returning True when on Robin boundary.
"""
allowedKinds = ["Dirichlet", "Neumann", "Robin"]
def __init__(self, kind : str = None):
if kind is None: return
kind = kind[0].upper() + kind[1:].lower()
if kind in self.allowedKinds:
- getattr(self.__class__, kind + "Boundary", None).fset(self, "ALL")
+ self._complementaryManagementAll(kind)
else:
raise RROMPyException("BC kind not recognized.")
def name(self) -> str:
return self.__class__.__name__
def __str__(self) -> str:
return self.name()
def __deepcopy__(self, memo):
return copy(self)
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
def _generalManagement(self, kind:str, value:GenExpr):
if isinstance(value, (str,)):
value = value.upper()
if value.upper() == "ALL":
self._complementaryManagementAll(kind)
elif value.upper() == "REST":
self._complementaryManagementRest(kind)
else:
raise RROMPyException("Wildcard not recognized.")
elif callable(value):
self._standardManagementCallable(kind, value)
elif isinstance(value, (SubDomain,)):
self._standardManagement(kind, value)
else:
raise RROMPyException(kind + "Boundary type not recognized.")
def _complementaryManagementAll(self, kind:str):
if kind not in self.allowedKinds:
raise RROMPyException("BC kind not recognized.")
for k in self.allowedKinds:
if k != kind:
self._standardManagementCallable(k, bdrFalse)
self._complementaryManagementRest(kind)
def _complementaryManagementRest(self, kind:str):
if kind not in self.allowedKinds:
raise RROMPyException("BC kind not recognized.")
otherBCs = []
for k in self.allowedKinds:
if k != kind:
if hasattr(self, "_" + k + "Rest"):
self._standardManagementCallable(k, bdrFalse)
otherBCs += [getattr(self, k + "Boundary")]
restCall = lambda x, on_boundary: (on_boundary
and not any([bc.inside(x, on_boundary) for bc in otherBCs]))
self._standardManagementCallable(kind, restCall)
super().__setattr__("_" + kind + "Rest", 1)
def _standardManagementCallable(self, kind:str, bc:callable):
bcSD = AutoSubDomain(bc)
self._standardManagement(kind, bcSD)
def _standardManagement(self, kind:str, bc:SubDomain):
super().__setattr__("_" + kind + "Boundary", bc)
if hasattr(self, "_" + kind + "Rest"):
super().__delattr__("_" + kind + "Rest")
@property
def DirichletBoundary(self):
"""Function handle to DirichletBoundary."""
return self._DirichletBoundary
@DirichletBoundary.setter
def DirichletBoundary(self, DirichletBoundary):
self._generalManagement("Dirichlet", DirichletBoundary)
@property
def NeumannBoundary(self):
"""Function handle to NeumannBoundary."""
return self._NeumannBoundary
@NeumannBoundary.setter
def NeumannBoundary(self, NeumannBoundary):
self._generalManagement("Neumann", NeumannBoundary)
@property
def RobinBoundary(self):
"""Function handle to RobinBoundary."""
return self._RobinBoundary
@RobinBoundary.setter
def RobinBoundary(self, RobinBoundary):
self._generalManagement("Robin", RobinBoundary)
diff --git a/rrompy/hfengines/base/marginal_proxy_engine.py b/rrompy/hfengines/base/marginal_proxy_engine.py
index f4fc5ae..2837328 100644
--- a/rrompy/hfengines/base/marginal_proxy_engine.py
+++ b/rrompy/hfengines/base/marginal_proxy_engine.py
@@ -1,387 +1,138 @@
# 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 inspect
import numpy as np
-import scipy.sparse as scsp
-from copy import deepcopy as copy, copy as softcopy
-from rrompy.utilities.base.types import (Np1D, Np2D, ScOp, List, ListAny,
- paramVal, paramList, HFEng, sampList)
+from copy import copy as softcopy
+from rrompy.utilities.base.types import Np1D, paramVal, paramList, HFEng
from rrompy.utilities.base import freepar as fp
-from rrompy.utilities.numerical import multibinom, marginalizePolyList
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD, hashIdxToDerivative as hashI)
-from rrompy.utilities.exception_manager import RROMPyAssert
+from rrompy.utilities.exception_manager import RROMPyException
from rrompy.parameter import checkParameter, checkParameterList
-from rrompy.sampling import sampleList, emptySampleList
-from rrompy.solver.scipy import tensorizeLS, detensorizeLS
-
__all__ = ['MarginalProxyEngine']
-
+
class MarginalProxyEngine:
"""
Marginalized should prescribe fixed value for the marginalized parameters
and leave freepar/None elsewhere.
"""
+ _allowedMuDependencies = ["A", "b", "checkParameter", "checkParameterList",
+ "_assembleObject", "solve", "residual",
+ "stabilityFactor"]
+
def __init__(self, HFEngine:HFEng, marginalized:Np1D):
self.baseHF = HFEngine
self.marg = marginalized
- self._setupAs()
- self._setupbs()
+ for name in HFEngine.__dir_base__():
+ att = getattr(HFEngine, name)
+ if inspect.ismethod(att):
+ attargs = inspect.getfullargspec(att).args
+ if "mu" not in attargs:
+ setattr(self.__class__, name, getattr(HFEngine, name))
+ else:
+ if name not in self._allowedMuDependencies:
+ raise RROMPyException(("Function {} depends on mu "
+ "and was not accounted for. "
+ "Must override.").format(name))
+ @property
+ def affinePoly(self):
+ return self.nparFixed == 0 and self.baseHF.affinePoly
+
@property
def freeLocations(self):
- return tuple([x for x in range(self.nparBase) if self.marg[x] == fp])
+ return tuple([x for x in range(self.baseHF.npar) \
+ if self.marg[x] == fp])
@property
def fixedLocations(self):
- return tuple([x for x in range(self.nparBase) if self.marg[x] != fp])
+ return tuple([x for x in range(self.baseHF.npar) \
+ if self.marg[x] != fp])
+
+ @property
+ def _freeLocationsInsert(self):
+ return np.cumsum([m == fp for m in self.marg])[self.fixedLocations]
@property
def muFixed(self):
muF = checkParameter([m for m in self.marg if m != fp])
- if self.nparBase - self.npar > 0: muF = muF[0]
+ if self.baseHF.npar - self.nparFree > 0: muF = muF[0]
return muF
@property
- def rescalingExp(self):
- return [self.baseHF.rescalingExp[x] for x in self.freeLocations]
-
- @property
- def rescalingExpFixed(self):
- return [self.baseHF.rescalingExp[x] for x in self.fixedLocations]
+ def nparFree(self):
+ """Value of nparFree."""
+ return len(self.freeLocations)
@property
- def V(self):
- return self.baseHF.V
+ def nparFixed(self):
+ """Value of nparFixed."""
+ return len(self.fixedLocations)
def name(self) -> str:
return "{}-proxy for {}".format(self.freeLocations, self.baseHF.name())
def __str__(self) -> str:
return self.name()
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
def __dir_base__(self):
return [x for x in self.__dir__() if x[:2] != "__"]
def __deepcopy__(self, memo):
return softcopy(self)
- @property
- def npar(self):
- """Value of npar."""
- return len(self.freeLocations)
-
- @property
- def nparBase(self):
- """Value of npar."""
- return self.baseHF.npar
-
- @property
- def nAs(self):
- """Value of nAs."""
- return self._nAs
-
- @property
- def nbs(self):
- """Value of nbs."""
- return self._nbs
-
- @property
- def nbsH(self) -> int:
- return max(self.nbs, self.nAs)
-
- def spacedim(self):
- return self.As[0].shape[1]
-
- def checkParameter(self, mu:paramList):
- return checkParameter(mu, self.npar)
-
- def checkParameterList(self, mu:paramList):
- return checkParameterList(mu, self.npar)
-
- def buildEnergyNormForm(self):
- self.baseHF.buildEnergyNormForm()
- self.energyNormMatrix = self.baseHF.energyNormMatrix
-
- def buildEnergyNormDualForm(self):
- self.baseHF.buildEnergyNormDualForm()
- self.energyNormDualMatrix = self.baseHF.energyNormDualMatrix
-
- def buildDualityPairingForm(self):
- self.baseHF.buildDualityPairingForm()
- self.dualityMatrix = self.baseHF.dualityMatrix
-
- def buildEnergyNormPartialDualForm(self):
- self.baseHF.buildEnergyNormPartialDualForm()
- self.energyNormPartialDualMatrix = (
- self.baseHF.energyNormPartialDualMatrix)
-
- def innerProduct(self, u:Np2D, v:Np2D, onlyDiag : bool = False,
- dual : bool = False, duality : bool = True) -> Np2D:
- return self.baseHF.innerProduct(u, v, onlyDiag, dual, duality)
-
- def norm(self, u:Np2D, dual : bool = False, duality : bool = True) -> Np1D:
- return self.baseHF.norm(u, dual, duality)
-
- def checkAInBounds(self, derI : int = 0):
- """Check if derivative index is oob for operator of linear system."""
- if derI < 0 or derI >= self.nAs:
- d = self.spacedim()
- return scsp.csr_matrix((np.zeros(0), np.zeros(0), np.zeros(d + 1)),
- shape = (d, d), dtype = np.complex)
-
- def checkbInBounds(self, derI : int = 0, homogeneized : bool = False):
- """Check if derivative index is oob for RHS of linear system."""
- nbs = self.nbsH if homogeneized else self.nbs
- if derI < 0 or derI >= nbs:
- return np.zeros(self.spacedim(), dtype = np.complex)
-
- def _assembleA(self, mu : paramVal = [], der : List[int] = 0,
- derI : int = None) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if self.npar > 0: mu = mu[0]
- if not hasattr(der, "__len__"): der = [der] * self.npar
- if derI is None: derI = hashD(der)
- Anull = self.checkAInBounds(derI)
- if Anull is not None: return Anull
- rExp = self.rescalingExp
- A = copy(self.As[derI])
- for j in range(derI + 1, self.nAs):
- derIdx = hashI(j, self.npar)
- diffIdx = [x - y for (x, y) in zip(derIdx, der)]
- if np.all([x >= 0 for x in diffIdx]):
- A = A + (np.prod((mu ** rExp) ** diffIdx)
- * multibinom(derIdx, diffIdx) * self.As[j])
- return A
-
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """
- Assemble terms of operator of linear system and return it (or its
- derivative) at a given parameter.
- """
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- return self._assembleA(mu, der, derI)
-
- def _setupAs(self):
- mVals = [fp] * self.nparBase
- muFixedEff = self.muFixed ** self.rescalingExpFixed
- for i, mFE in zip(self.fixedLocations, muFixedEff):
- mVals[i] = mFE
- self.As = marginalizePolyList(self.baseHF.As, mVals, "auto")
- self._nAs = len(self.As)
+ def completeMu(self, mu:paramVal) -> paramVal:
+ mu = checkParameter(mu, self.nparFree)
+ return np.insert(mu.data, self._freeLocationsInsert, self.muFixed,
+ axis = 1)
- def affineLinearSystemA(self, mu : paramVal = [],
- sclF : ListAny = None) -> List[Np2D]:
- """
- Assemble affine blocks of operator of linear system (just linear
- blocks).
- """
- if sclF is None: sclF = [1.] * self.npar
- As = [None] * self.nAs
- for j in range(self.nAs):
- derIdx = hashI(j, self.npar)
- mult = np.prod([s ** d for (s, d) in zip(sclF, derIdx)])
- As[j] = mult * self.A(mu, derIdx)
- return As
-
- def _assembleb(self, mu : paramVal = [], der : List[int] = 0,
- derI : int = None, homogeneized : bool = False) -> ScOp:
- """Assemble (derivative of) (homogeneized) RHS of linear system."""
- mu = self.checkParameter(mu)
- if self.npar > 0: mu = mu[0]
- if not hasattr(der, "__len__"): der = [der] * self.npar
- if derI is None: derI = hashD(der)
- bnull = self.checkbInBounds(derI, homogeneized)
- if bnull is not None: return bnull
- bs = self.bsH if homogeneized else self.bs
- rExp = self.rescalingExp
- b = copy(bs[derI])
- for j in range(derI + 1, len(bs)):
- derIdx = hashI(j, self.npar)
- diffIdx = [x - y for (x, y) in zip(derIdx, der)]
- if np.all([x >= 0 for x in diffIdx]):
- b = b + (np.prod((mu ** rExp) ** diffIdx)
- * multibinom(derIdx, diffIdx) * bs[j])
- return b
-
- def b(self, mu : paramVal = [], der : List[int] = 0,
- homogeneized : bool = False) -> Np1D:
- """
- Assemble terms of (homogeneized) RHS of linear system and return it (or
- its derivative) at a given parameter.
- """
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- return self._assembleb(mu, der, derI, homogeneized)
-
- def _setupbs(self):
- mVals = [fp] * self.nparBase
- muFixedEff = self.muFixed ** self.rescalingExpFixed
- for i, mFE in zip(self.fixedLocations, muFixedEff):
- mVals[i] = mFE
- self.bs = marginalizePolyList(self.baseHF.bs, mVals, "auto")
- self._nbs = len(self.bs)
-
- def affineLinearSystemb(self, mu : paramVal = [], sclF : ListAny = None,
- homogeneized : bool = False) -> List[Np1D]:
- """
- Assemble affine blocks of RHS of linear system (just linear blocks).
- """
- if sclF is None: sclF = [1.] * self.npar
- nbs = self.nbsH if homogeneized else self.nbs
- bs = [None] * nbs
- for j in range(nbs):
- derIdx = hashI(j, self.npar)
- mult = np.prod([s ** d for (s, d) in zip(sclF, derIdx)])
- bs[j] = mult * self.b(mu, derIdx, homogeneized)
- return bs
-
- def solve(self, mu : paramList = [], RHS : sampList = None,
- homogeneized : bool = False) -> sampList:
- """
- Find solution of linear system.
-
- Args:
- mu: parameter value.
- RHS: RHS of linear system. If None, defaults to that of parametric
- system. Defaults to None.
- """
- mu = self.checkParameterList(mu)[0]
- if mu.shape[0] == 0: mu.reset((1, self.npar), mu.dtype)
- sol = emptySampleList()
- if len(mu) > 0:
- if RHS is None:
- RHS = [self.b(m, homogeneized = homogeneized) for m in mu]
- RHS = sampleList(RHS)
- mult = 0 if len(RHS) == 1 else 1
- RROMPyAssert(mult * (len(mu) - 1) + 1, len(RHS), "Sample size")
- u = self.baseHF._solver(self.A(mu[0]), RHS[0],
- self.baseHF._solverArgs)
- sol.reset((len(u), len(mu)), dtype = u.dtype)
- sol[0] = u
- for j in range(1, len(mu), self.baseHF._solveBatchSize):
- if self.baseHF._solveBatchSize != 1:
- iRange = list(range(j, min(j + self.baseHF._solveBatchSize,
- len(mu))))
- As = [self.A(mu[i]) for i in iRange]
- bs = [RHS[mult * i] for i in iRange]
- A, b = tensorizeLS(As, bs)
- else:
- A, b = self.A(mu[j]), RHS[mult * j]
- solStack = self.baseHF._solver(A, b, self.baseHF._solverArgs)
- if self.baseHF._solveBatchSize != 1:
- sol[iRange] = detensorizeLS(solStack, len(iRange))
- else:
- sol[j] = solStack
- return sol
-
- def residual(self, u:sampList, mu : paramList = [],
- homogeneized : bool = False,
- duality : bool = True) -> sampList:
- """
- Find residual of linear system for given approximate solution.
-
- Args:
- u: numpy complex array with function dofs. If None, set to 0.
- mu: parameter value.
- """
- mu = self.checkParameterList(mu)[0]
- if mu.shape[0] == 0: mu.reset((1, self.npar), mu.dtype)
- if u is not None:
- u = sampleList(u)
- mult = 0 if len(u) == 1 else 1
- RROMPyAssert(mult * (len(mu) - 1) + 1, len(u), "Sample size")
- res = emptySampleList()
- if duality and not hasattr(self, "dualityMatrix"):
- self.buildDualityPairingForm()
- for j in range(len(mu)):
- b = self.b(mu[j], homogeneized = homogeneized)
- if u is None:
- r = b
- else:
- r = b - self.A(mu[j]).dot(u[mult * j])
- if j == 0:
- res.reset((len(r), len(mu)), dtype = r.dtype)
- if duality:
- r = self.dualityMatrix.dot(r)
- res[j] = r
- return res
+ def completeMuList(self, mu:paramList) -> paramList:
+ mu = checkParameterList(mu, self.nparFree)[0]
+ return np.insert(mu.data, self._freeLocationsInsert, self.muFixed,
+ axis = 1)
- def _rayleighQuotient(self, *args, **kwargs) -> float:
- return self.baseHF._rayleighQuotient(*args, **kwargs)
+ def A(self, mu : paramVal = [], *args, **kwargs):
+ return self.baseHF.A(self.completeMu(mu), *args, **kwargs)
- def stabilityFactor(self, u:sampList, mu : paramList = [],
- nIterP : int = 10, nIterR : int = 10) -> sampList:
- """
- Find stability factor of matrix of linear system using iterative
- inverse power iteration- and Rayleigh quotient-based procedure.
+ def b(self, mu : paramVal = [], *args, **kwargs):
+ return self.baseHF.b(self.completeMu(mu), *args, **kwargs)
- Args:
- u: numpy complex arrays with function dofs.
- mu: parameter values.
- nIterP: number of iterations of power method.
- nIterR: number of iterations of Rayleigh quotient method.
- """
- mu = self.checkParameterList(mu)[0]
- if mu.shape[0] == 0: mu.reset((1, self.npar), mu.dtype)
- u = sampleList(u)
- mult = 0 if len(u) == 1 else 1
- RROMPyAssert(mult * (len(mu) - 1) + 1, len(u), "Sample size")
- stabFact = np.empty(len(mu), dtype = float)
- if not hasattr(self, "energyNormMatrix"):
- self.buildEnergyNormForm()
- for j in range(len(mu)):
- stabFact[j] = self._rayleighQuotient(self.A(mu[j]), u[mult * j],
- self.energyNormMatrix,
- 0., nIterP, nIterR)
- return stabFact
+ def checkParameter(self, mu : paramVal = [], *args, **kwargs):
+ return self.baseHF.checkParameter(self.completeMu(mu), *args, **kwargs)
- def plot(self, *args, **kwargs):
- """
- Do some nice plots of the complex-valued function with given dofs.
+ def checkParameterList(self, mu : paramList = [], *args, **kwargs):
+ return self.baseHF.checkParameterList(self.completeMuList(mu),
+ *args, **kwargs)
- """
- self.baseHF.plot(*args, **kwargs)
+ def _assembleObject(self, mu : paramVal = [], *args, **kwargs):
+ return self.baseHF._assembleObject(self.completeMu(mu),
+ *args, **kwargs)
- def plotmesh(self, *args, **kwargs):
- """
- Do a nice plot of the mesh.
- """
- self.baseHF.plotmesh(*args, **kwargs)
+ def solve(self, mu : paramList = [], *args, **kwargs):
+ return self.baseHF.solve(self.completeMuList(mu), *args, **kwargs)
- def outParaview(self, *args, **kwargs):
- """
- Output complex-valued function with given dofs to ParaView file.
- """
- self.baseHF.outParaview(*args, **kwargs)
+ def residual(self, mu : paramList = [], *args, **kwargs):
+ return self.baseHF.residual(self.completeMuList(mu), *args, **kwargs)
- def outParaviewTimeDomain(self, *args, **kwargs):
- """
- Output complex-valued function with given dofs to ParaView file,
- converted to time domain.
- """
- self.baseHF.outParaviewTimeDomain(*args, **kwargs)
+ def stabilityFactor(self, mu : paramList = [], *args, **kwargs):
+ return self.baseHF.stabilityFactor(self.completeMuList(mu),
+ *args, **kwargs)
diff --git a/rrompy/hfengines/base/matrix_engine_base.py b/rrompy/hfengines/base/matrix_engine_base.py
index 5effc6c..c6c63fe 100644
--- a/rrompy/hfengines/base/matrix_engine_base.py
+++ b/rrompy/hfengines/base/matrix_engine_base.py
@@ -1,517 +1,479 @@
# 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 abc import abstractmethod
import numpy as np
import scipy.sparse as scsp
from matplotlib import pyplot as plt
from copy import deepcopy as copy, copy as softcopy
-from rrompy.utilities.base.types import (Np1D, Np2D, ScOp, strLst, Tuple, List,
- ListAny, DictAny, paramVal, paramList,
- sampList)
+from rrompy.utilities.base.types import (Np1D, Np2D, ScOp, strLst, TupleAny,
+ List, ListAny, DictAny, paramVal,
+ paramList, sampList)
from rrompy.utilities.base import (purgeList, getNewFilename,
verbosityManager as vbMng)
-from rrompy.utilities.numerical import multibinom
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD, hashIdxToDerivative as hashI)
+from rrompy.utilities.expression import (expressionEvaluator, createMonomial,
+ createMonomialList)
+from rrompy.utilities.numerical import (hashDerivativeToIdx as hashD,
+ solve, dot)
from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
from rrompy.parameter import checkParameter, checkParameterList
from rrompy.sampling import sampleList, emptySampleList
from rrompy.solver import setupSolver, Np2DLikeEye
-from rrompy.solver.scipy import tensorizeLS, detensorizeLS
__all__ = ['MatrixEngineBase']
class MatrixEngineBase:
"""
Generic solver for parametric matrix problems.
Attributes:
verbosity: Verbosity level.
As: Scipy sparse array representation (in CSC format) of As.
bs: Numpy array representation of bs.
- bsH: Numpy array representation of homogeneized bs.
energyNormMatrix: Scipy sparse matrix representing inner product.
energyNormDualMatrix: Scipy sparse matrix representing dual inner
product.
dualityMatrix: Scipy sparse matrix representing duality.
energyNormPartialDualMatrix: Scipy sparse matrix representing dual
inner product without duality.
"""
-
- _solveBatchSize = 1
def __init__(self, verbosity : int = 10, timestamp : bool = True):
self.verbosity = verbosity
self.timestamp = timestamp
+ self._affinePoly = True
self.nAs, self.nbs = 1, 1
self.setSolver("SPSOLVE", {"use_umfpack" : False})
self.npar = 0
def name(self) -> str:
return self.__class__.__name__
def __str__(self) -> str:
return self.name()
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
def __dir_base__(self):
return [x for x in self.__dir__() if x[:2] != "__"]
def __deepcopy__(self, memo):
return softcopy(self)
@property
def npar(self):
"""Value of npar."""
return self._npar
@npar.setter
def npar(self, npar):
nparOld = self._npar if hasattr(self, "_npar") else -1
if npar != nparOld:
self.rescalingExp = [1.] * npar
self._npar = npar
@property
def nAs(self):
"""Value of nAs."""
return self._nAs
@nAs.setter
def nAs(self, nAs):
self._nAs = nAs
self.resetAs()
@property
def nbs(self):
"""Value of nbs."""
return self._nbs
@nbs.setter
def nbs(self, nbs):
self._nbs = nbs
self.resetbs()
@property
- def nbsH(self) -> int:
- return max(self.nbs, self.nAs)
+ def affinePoly(self):
+ return self._affinePoly
def spacedim(self):
return self.As[0].shape[1]
- def checkParameter(self, mu:paramList):
+ def checkParameter(self, mu:paramVal):
return checkParameter(mu, self.npar)
def checkParameterList(self, mu:paramList):
return checkParameterList(mu, self.npar)
def buildEnergyNormForm(self): # eye
"""
Build sparse matrix (in CSR format) representative of scalar product.
"""
vbMng(self, "INIT", "Assembling energy matrix.", 20)
- self.energyNormMatrix = Np2DLikeEye()
+ self.energyNormMatrix = Np2DLikeEye(self.spacedim())
vbMng(self, "DEL", "Done assembling energy matrix.", 20)
def buildEnergyNormDualForm(self):
"""
Build sparse matrix (in CSR format) representative of dual scalar
product.
"""
if not hasattr(self, "energyNormMatrix"):
self.buildEnergyNormForm()
vbMng(self, "INIT", "Assembling energy dual matrix.", 20)
self.energyNormDualMatrix = self.energyNormMatrix
vbMng(self, "DEL", "Done assembling energy dual matrix.", 20)
def buildDualityPairingForm(self):
"""Build sparse matrix (in CSR format) representative of duality."""
if not hasattr(self, "energyNormMatrix"):
self.buildEnergyNormForm()
vbMng(self, "INIT", "Assembling duality matrix.", 20)
self.dualityMatrix = self.energyNormMatrix
vbMng(self, "DEL", "Done assembling duality matrix.", 20)
def buildEnergyNormPartialDualForm(self):
"""
Build sparse matrix (in CSR format) representative of dual scalar
product without duality.
"""
if not hasattr(self, "energyNormDualMatrix"):
self.buildEnergyNormDualForm()
vbMng(self, "INIT", "Assembling energy partial dual matrix.", 20)
self.energyNormPartialDualMatrix = self.energyNormDualMatrix
vbMng(self, "DEL", "Done assembling energy partial dual matrix.", 20)
def innerProduct(self, u:Np2D, v:Np2D, onlyDiag : bool = False,
dual : bool = False, duality : bool = True) -> Np2D:
"""Scalar product."""
if dual:
if duality:
if not hasattr(self, "energyNormDualMatrix"):
self.buildEnergyNormDualForm()
energyMat = self.energyNormDualMatrix
else:
if not hasattr(self, "energyNormPartialDualMatrix"):
self.buildEnergyNormPartialDualForm()
energyMat = self.energyNormPartialDualMatrix
else:
if not hasattr(self, "energyNormMatrix"):
self.buildEnergyNormForm()
energyMat = self.energyNormMatrix
if not isinstance(u, (np.ndarray,)): u = u.data
if not isinstance(v, (np.ndarray,)): v = v.data
if onlyDiag:
- return np.sum(energyMat.dot(u) * v.conj(), axis = 0)
- return v.T.conj().dot(energyMat.dot(u))
+ return np.sum(dot(energyMat, u) * v.conj(), axis = 0)
+ return dot(dot(energyMat, u).T, v.conj()).T
def norm(self, u:Np2D, dual : bool = False, duality : bool = True) -> Np1D:
return np.abs(self.innerProduct(u, u, onlyDiag = True, dual = dual,
duality = duality)) ** .5
def checkAInBounds(self, derI : int = 0):
"""Check if derivative index is oob for operator of linear system."""
- if derI < 0 or derI >= self.nAs:
+ if derI < 0:
d = self.spacedim()
return scsp.csr_matrix((np.zeros(0), np.zeros(0), np.zeros(d + 1)),
shape = (d, d), dtype = np.complex)
- def checkbInBounds(self, derI : int = 0, homogeneized : bool = False):
+ def checkbInBounds(self, derI : int = 0):
"""Check if derivative index is oob for RHS of linear system."""
- nbs = self.nbsH if homogeneized else self.nbs
- if derI < 0 or derI >= nbs:
+ if derI < 0:
return np.zeros(self.spacedim(), dtype = np.complex)
def resetAs(self):
"""Reset (derivatives of) operator of linear system."""
self.setAs([None] * self.nAs)
- if hasattr(self, "_nbs"): self.resetbsH()
+ self.setthAs([None] * self.nAs)
def resetbs(self):
"""Reset (derivatives of) RHS of linear system."""
self.setbs([None] * self.nbs)
- if hasattr(self, "_nAs"): self.resetbsH()
+ self.setthbs([None] * self.nbs)
+
+ def getMonomialSingleWeight(self, deg:List[int]):
+ return createMonomial(deg, True)
- def resetbsH(self):
- """Reset (derivatives of) homogeneized RHS of linear system."""
- self.setbsH([None] * self.nbsH)
+ def getMonomialWeights(self, n:int):
+ return createMonomialList(n, self.npar, True)
def setAs(self, As:List[Np2D]):
"""Assign terms of operator of linear system."""
if len(As) != self.nAs:
raise RROMPyException(("Expected number {} of terms of As not "
"matching given list length {}.").format(self.nAs,
len(As)))
self.As = [copy(A) for A in As]
+ def setthAs(self, thAs:List[List[TupleAny]]):
+ """Assign terms of operator of linear system."""
+ if len(thAs) != self.nAs:
+ raise RROMPyException(("Expected number {} of terms of thAs not "
+ "matching given list length {}.").format(self.nAs,
+ len(thAs)))
+ self.thAs = copy(thAs)
+
def setbs(self, bs:List[Np1D]):
"""Assign terms of RHS of linear system."""
if len(bs) != self.nbs:
raise RROMPyException(("Expected number {} of terms of bs not "
"matching given list length {}.").format(self.nbs,
len(bs)))
self.bs = [copy(b) for b in bs]
- def setbsH(self, bsH:List[Np1D]):
- """Assign terms of homogeneized RHS of linear system."""
- if len(bsH) != self.nbsH:
- raise RROMPyException(("Expected number {} of terms of bsH not "
- "matching given list length {}.").format(self.nbsH,
- len(bsH)))
- self.bsH = [copy(bH) for bH in bsH]
-
- def _assembleA(self, mu : paramVal = [], der : List[int] = 0,
- derI : int = None) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
+ def setthbs(self, thbs:List[List[TupleAny]]):
+ """Assign terms of RHS of linear system."""
+ if len(thbs) != self.nbs:
+ raise RROMPyException(("Expected number {} of terms of thbs not "
+ "matching given list length {}.").format(self.nbs,
+ len(thbs)))
+ self.thbs = copy(thbs)
+
+ def _assembleObject(self, mu:paramVal, objs:ListAny, th:ListAny,
+ derI:int) -> ScOp:
+ """Assemble (derivative of) object from list of derivatives."""
mu = self.checkParameter(mu)
- if self.npar > 0: mu = mu[0]
- if not hasattr(der, "__len__"): der = [der] * self.npar
- if derI is None: derI = hashD(der)
- Anull = self.checkAInBounds(derI)
- if Anull is not None: return Anull
rExp = self.rescalingExp
- A = copy(self.As[derI])
- for j in range(derI + 1, self.nAs):
- derIdx = hashI(j, self.npar)
- diffIdx = [x - y for (x, y) in zip(derIdx, der)]
- if np.all([x >= 0 for x in diffIdx]):
- A = A + (np.prod((mu ** rExp) ** diffIdx)
- * multibinom(derIdx, diffIdx) * self.As[j])
- return A
+ muE = mu ** rExp
+ obj = None
+ for j in range(len(objs)):
+ if len(th[j]) <= derI and th[j][-1] is not None:
+ raise RROMPyException(("Cannot assemble operator. Non enough "
+ "derivatives of theta provided."))
+ if len(th[j]) > derI and th[j][derI] is not None:
+ expr = expressionEvaluator(th[j][derI], muE)
+ if hasattr(expr, "__len__"):
+ if len(expr) > 1:
+ raise RROMPyException(("Size mismatch in value of "
+ "theta function. Only scalars "
+ "allowed."))
+ expr = expr[0]
+ if obj is None:
+ obj = expr * objs[j]
+ else:
+ obj = obj + expr * objs[j]
+ return obj
@abstractmethod
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.thAs[0] is None: self.thAs = self.getMonomialWeights(self.nAs)
+ for j in range(self.nAs):
+ if self.As[j] is None: self.As[j] = self.checkAInBounds(-1)
+
def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
"""
Assemble terms of operator of linear system and return it (or its
derivative) at a given parameter.
"""
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- for j in range(derI, self.nAs):
- if self.As[j] is None: self.As[j] = self.checkAInBounds(-1)
- return self._assembleA(mu, der, derI)
-
- def affineLinearSystemA(self, mu : paramVal = [],
- sclF : ListAny = None) -> List[Np2D]:
- """
- Assemble affine blocks of operator of linear system (just linear
- blocks).
- """
- if sclF is None: sclF = [1.] * self.npar
- As = [None] * self.nAs
- for j in range(self.nAs):
- derIdx = hashI(j, self.npar)
- mult = np.prod([s ** d for (s, d) in zip(sclF, derIdx)])
- As[j] = mult * self.A(mu, derIdx)
- return As
-
- def _assembleb(self, mu : paramVal = [], der : List[int] = 0,
- derI : int = None, homogeneized : bool = False) -> ScOp:
- """Assemble (derivative of) (homogeneized) RHS of linear system."""
- mu = self.checkParameter(mu)
- if self.npar > 0: mu = mu[0]
- if not hasattr(der, "__len__"): der = [der] * self.npar
- if derI is None: derI = hashD(der)
- bnull = self.checkbInBounds(derI, homogeneized)
- if bnull is not None: return bnull
- bs = self.bsH if homogeneized else self.bs
- rExp = self.rescalingExp
- b = copy(bs[derI])
- for j in range(derI + 1, len(bs)):
- derIdx = hashI(j, self.npar)
- diffIdx = [x - y for (x, y) in zip(derIdx, der)]
- if np.all([x >= 0 for x in diffIdx]):
- b = b + (np.prod((mu ** rExp) ** diffIdx)
- * multibinom(derIdx, diffIdx) * bs[j])
- return b
+ derI = hashD(der) if hasattr(der, "__len__") else der
+ Anull = self.checkAInBounds(derI)
+ if Anull is not None: return Anull
+ self.buildA()
+ assembledA = self._assembleObject(mu, self.As, self.thAs, derI)
+ if assembledA is None: return self.checkAInBounds(-1)
+ return assembledA
@abstractmethod
- def b(self, mu : paramVal = [], der : List[int] = 0,
- homogeneized : bool = False) -> Np1D:
- """
- Assemble terms of (homogeneized) RHS of linear system and return it (or
- its derivative) at a given parameter.
- """
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- if homogeneized:
- for j in range(derI, self.nbsH):
- if self.bsH[j] is None: self.bsH[j] = self.checkbInBounds(-1)
- else:
- for j in range(derI, self.nbs):
- if self.bs[j] is None: self.bs[j] = self.checkbInBounds(-1)
- return self._assembleb(mu, der, derI, homogeneized)
+ def buildb(self):
+ """Build terms of operator of linear system."""
+ if self.thbs[0] is None: self.thbs = self.getMonomialWeights(self.nbs)
+ for j in range(self.nbs):
+ if self.bs[j] is None: self.bs[j] = self.checkbInBounds(-1)
- def affineLinearSystemb(self, mu : paramVal = [], sclF : ListAny = None,
- homogeneized : bool = False) -> List[Np1D]:
+ def b(self, mu : paramVal = [], der : List[int] = 0) -> Np1D:
"""
- Assemble affine blocks of RHS of linear system (just linear blocks).
+ Assemble terms of RHS of linear system and return it (or its
+ derivative) at a given parameter.
"""
- if sclF is None: sclF = [1.] * self.npar
- nbs = self.nbsH if homogeneized else self.nbs
- bs = [None] * nbs
- for j in range(nbs):
- derIdx = hashI(j, self.npar)
- mult = np.prod([s ** d for (s, d) in zip(sclF, derIdx)])
- bs[j] = mult * self.b(mu, derIdx, homogeneized)
- return bs
+ derI = hashD(der) if hasattr(der, "__len__") else der
+ bnull = self.checkbInBounds(derI)
+ if bnull is not None: return bnull
+ self.buildb()
+ assembledb = self._assembleObject(mu, self.bs, self.thbs, derI)
+ if assembledb is None: return self.checkbInBounds(-1)
+ return assembledb
def setSolver(self, solverType:str, solverArgs : DictAny = {}):
"""Choose solver type and parameters."""
self._solver, self._solverArgs = setupSolver(solverType, solverArgs)
- def solve(self, mu : paramList = [], RHS : sampList = None,
- homogeneized : bool = False) -> sampList:
+ def solve(self, mu : paramList = [], RHS : sampList = None) -> sampList:
"""
Find solution of linear system.
Args:
mu: parameter value.
RHS: RHS of linear system. If None, defaults to that of parametric
system. Defaults to None.
"""
mu = self.checkParameterList(mu)[0]
if mu.shape[0] == 0: mu.reset((1, self.npar), mu.dtype)
sol = emptySampleList()
if len(mu) > 0:
if RHS is None:
- RHS = [self.b(m, homogeneized = homogeneized) for m in mu]
+ RHS = [self.b(m) for m in mu]
RHS = sampleList(RHS)
mult = 0 if len(RHS) == 1 else 1
RROMPyAssert(mult * (len(mu) - 1) + 1, len(RHS), "Sample size")
- u = self._solver(self.A(mu[0]), RHS[0], self._solverArgs)
- sol.reset((len(u), len(mu)), dtype = u.dtype)
- sol[0] = u
- for j in range(1, len(mu), self._solveBatchSize):
- if self._solveBatchSize != 1:
- iRange = list(range(j, min(j + self._solveBatchSize,
- len(mu))))
- As = [self.A(mu[i]) for i in iRange]
- bs = [RHS[mult * i] for i in iRange]
- A, b = tensorizeLS(As, bs)
- else:
- A, b = self.A(mu[j]), RHS[mult * j]
- solStack = self._solver(A, b, self._solverArgs)
- if self._solveBatchSize != 1:
- sol[iRange] = detensorizeLS(solStack, len(iRange))
- else:
- sol[j] = solStack
+ for j in range(len(mu)):
+ u = solve(self.A(mu[j]), RHS[mult * j], self._solver,
+ self._solverArgs)
+ if j == 0:
+ sol.reset((len(u), len(mu)), dtype = u.dtype)
+ sol[j] = u
return sol
- def residual(self, u:sampList, mu : paramList = [],
- homogeneized : bool = False,
+ def residual(self, mu : paramList = [], u : sampList = None,
duality : bool = True) -> sampList:
"""
Find residual of linear system for given approximate solution.
Args:
- u: numpy complex array with function dofs. If None, set to 0.
mu: parameter value.
+ u: numpy complex array with function dofs. If None, set to 0.
"""
mu = self.checkParameterList(mu)[0]
if mu.shape[0] == 0: mu.reset((1, self.npar), mu.dtype)
if u is not None:
u = sampleList(u)
mult = 0 if len(u) == 1 else 1
RROMPyAssert(mult * (len(mu) - 1) + 1, len(u), "Sample size")
res = emptySampleList()
if duality and not hasattr(self, "dualityMatrix"):
self.buildDualityPairingForm()
for j in range(len(mu)):
- b = self.b(mu[j], homogeneized = homogeneized)
- if u is None:
- r = b
- else:
- r = b - self.A(mu[j]).dot(u[mult * j])
+ r = self.b(mu[j])
+ if u is not None:
+ r = r - dot(self.A(mu[j]), u[mult * j])
if j == 0:
res.reset((len(r), len(mu)), dtype = r.dtype)
if duality:
- r = self.dualityMatrix.dot(r)
+ r = dot(self.dualityMatrix, r)
res[j] = r
return res
def _rayleighQuotient(self, A:Np2D, v0:Np1D, M:Np2D, sigma : float = 0.,
nIterP : int = 10, nIterR : int = 10) -> float:
nIterP = min(nIterP, len(v0) // 2)
nIterR = min(nIterR, (len(v0) + 1) // 2)
- v0 /= v0.T.conj().dot(M.dot(v0)) ** .5
+ v0 /= dot(dot(M, v0).T, v0.conj()) ** .5
for j in range(nIterP):
- v0 = self._solver(A - sigma * M, M.dot(v0), self._solverArgs)
- v0 /= v0.T.conj().dot(M.dot(v0)) ** .5
- l0 = v0.T.conj().dot(A.dot(v0))
+ v0 = solve(A - sigma * M, dot(M, v0), self._solver,
+ self._solverArgs)
+ v0 /= dot(dot(M, v0).T, v0.conj()) ** .5
+ l0 = dot(A.dot(v0).T, v0.conj())
for j in range(nIterR):
- v0 = self._solver(A - l0 * M, M.dot(v0), self._solverArgs)
- v0 /= v0.T.conj().dot(M.dot(v0)) ** .5
- l0 = v0.T.conj().dot(A.dot(v0))
+ v0 = solve(A - l0 * M, dot(M, v0), self._solver, self._solverArgs)
+ v0 /= dot(dot(M, v0).T, v0.conj()) ** .5
+ l0 = dot(A.dot(v0).T, v0.conj())
if np.isnan(l0): l0 = np.finfo(float).eps
return np.abs(l0)
- def stabilityFactor(self, u:sampList, mu : paramList = [],
+ def stabilityFactor(self, mu : paramList = [], u : sampList = None,
nIterP : int = 10, nIterR : int = 10) -> sampList:
"""
Find stability factor of matrix of linear system using iterative
inverse power iteration- and Rayleigh quotient-based procedure.
Args:
- u: numpy complex arrays with function dofs.
mu: parameter values.
+ u: numpy complex arrays with function dofs.
nIterP: number of iterations of power method.
nIterR: number of iterations of Rayleigh quotient method.
"""
mu = self.checkParameterList(mu)[0]
if mu.shape[0] == 0: mu.reset((1, self.npar), mu.dtype)
u = sampleList(u)
mult = 0 if len(u) == 1 else 1
RROMPyAssert(mult * (len(mu) - 1) + 1, len(u), "Sample size")
stabFact = np.empty(len(mu), dtype = float)
if not hasattr(self, "energyNormMatrix"):
self.buildEnergyNormForm()
for j in range(len(mu)):
stabFact[j] = self._rayleighQuotient(self.A(mu[j]), u[mult * j],
self.energyNormMatrix,
0., nIterP, nIterR)
return stabFact
def plot(self, u:Np1D, warping : List[callable] = None, name : str = "u",
save : str = None, what : strLst = 'all',
saveFormat : str = "eps", saveDPI : int = 100, show : bool = True,
pyplotArgs : dict = {}, **figspecs):
"""
Do some nice plots of the complex-valued function with given dofs.
Args:
u: numpy complex array with function dofs.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
show(optional): Whether to show figure. Defaults to True.
pyplotArgs(optional): Optional arguments for pyplot.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
if isinstance(what, (str,)):
if what.upper() == 'ALL':
what = ['ABS', 'PHASE', 'REAL', 'IMAG']
else:
what = [what]
what = purgeList(what, ['ABS', 'PHASE', 'REAL', 'IMAG'],
listname = self.name() + ".what", baselevel = 1)
if len(what) == 0: return
if 'figsize' not in figspecs.keys():
figspecs['figsize'] = (13. * len(what) / 4, 3)
subplotcode = 100 + len(what) * 10
idxs = np.arange(self.spacedim())
if warping is not None:
idxs = warping[0](np.arange(self.spacedim()))
plt.figure(**figspecs)
plt.jet()
if 'ABS' in what:
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
plt.plot(idxs, np.abs(u).flatten(), **pyplotArgs)
plt.title("|{0}|".format(name))
if 'PHASE' in what:
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
plt.plot(idxs, np.angle(u).flatten(), **pyplotArgs)
plt.title("phase({0})".format(name))
if 'REAL' in what:
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
plt.plot(idxs, np.real(u).flatten(), **pyplotArgs)
plt.title("Re({0})".format(name))
if 'IMAG' in what:
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
plt.plot(idxs, np.imag(u).flatten(), **pyplotArgs)
plt.title("Im({0})".format(name))
if save is not None:
save = save.strip()
plt.savefig(getNewFilename("{}_fig_".format(save), saveFormat),
format = saveFormat, dpi = saveDPI)
if show:
plt.show()
plt.close()
diff --git a/rrompy/hfengines/base/problem_engine_base.py b/rrompy/hfengines/base/problem_engine_base.py
index 5144951..bb22b19 100644
--- a/rrompy/hfengines/base/problem_engine_base.py
+++ b/rrompy/hfengines/base/problem_engine_base.py
@@ -1,366 +1,410 @@
# 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 os import path, mkdir
import fenics as fen
import numpy as np
from matplotlib import pyplot as plt
-from copy import deepcopy as copy
-from rrompy.utilities.base.types import (Np1D, strLst, FenFunc, Tuple, List,
- paramVal)
+from rrompy.utilities.base.types import Np1D, strLst, FenFunc, Tuple, List
from rrompy.utilities.base import (purgeList, getNewFilename,
verbosityManager as vbMng)
+from rrompy.utilities.numerical import dot
from rrompy.solver import Np2DLikeEye
from rrompy.solver.fenics import L2NormMatrix, fenplot, interp_project
from .boundary_conditions import BoundaryConditions
from .matrix_engine_base import MatrixEngineBase
from rrompy.utilities.exception_manager import RROMPyException
__all__ = ['ProblemEngineBase']
class ProblemEngineBase(MatrixEngineBase):
"""
Generic solver for parametric problems.
Attributes:
verbosity: Verbosity level.
BCManager: Boundary condition manager.
V: Real FE space.
u: Generic trial functions for variational form evaluation.
v: Generic test functions for variational form evaluation.
As: Scipy sparse array representation (in CSC format) of As.
bs: Numpy array representation of bs.
energyNormMatrix: Scipy sparse matrix representing inner product over
V.
energyNormDualMatrix: Scipy sparse matrix representing inner product
over V'.
dualityMatrix: Scipy sparse matrix representing duality V-V'.
energyNormPartialDualMatrix: Scipy sparse matrix representing dual
inner product between Riesz representers V-V.
- liftedDirichletDatum: Dofs of Dirichlet datum lifting.
- mu0BC: Mu value of last Dirichlet datum lifting.
degree_threshold: Threshold for ufl expression interpolation degree.
"""
_dualityCompress = None
- def __init__(self, degree_threshold : int = np.inf, verbosity : int = 10,
+ def __init__(self, degree_threshold : int = np.inf,
+ homogeneized : bool = False, verbosity : int = 10,
timestamp : bool = True):
+ self.homogeneized = homogeneized
super().__init__(verbosity = verbosity, timestamp = timestamp)
self.BCManager = BoundaryConditions("Dirichlet")
self.V = fen.FunctionSpace(fen.UnitSquareMesh(10, 10), "P", 1)
- self.mu0BC = np.nan
self.degree_threshold = degree_threshold
self.npar = 0
+ @property
+ def homogeneized(self):
+ """Value of homogeneized."""
+ return self._homogeneized
+ @homogeneized.setter
+ def homogeneized(self, homogeneized):
+ if (not hasattr(self, "_homogeneized")
+ or homogeneized != self.homogeneized):
+ self._homogeneized = homogeneized
+ if hasattr(self, "_nbs"): self.resetbs()
+
@property
def V(self):
"""Value of V."""
return self._V
@V.setter
def V(self, V):
self.resetAs()
self.resetbs()
if not type(V).__name__ == 'FunctionSpace':
raise RROMPyException("V type not recognized.")
self._V = V
self.u = fen.TrialFunction(V)
self.v = fen.TestFunction(V)
def spacedim(self):
return self.V.dim()
+ def autoSetDS(self):
+ """Set FEniCS boundary measure based on boundary function handles."""
+ if self.dsToBeSet:
+ vbMng(self, "INIT", "Initializing boundary measures.", 20)
+ mesh = self.V.mesh()
+ NB = self.NeumannBoundary
+ RB = self.RobinBoundary
+ boundary_markers = fen.MeshFunction("size_t", mesh,
+ mesh.topology().dim() - 1)
+ NB.mark(boundary_markers, 0)
+ RB.mark(boundary_markers, 1)
+ self.ds = fen.Measure("ds", domain = mesh,
+ subdomain_data = boundary_markers)
+ self.dsToBeSet = False
+ vbMng(self, "DEL", "Done assembling boundary measures.", 20)
+
def buildEnergyNormForm(self):
"""
Build sparse matrix (in CSR format) representative of scalar product.
"""
vbMng(self, "INIT", "Assembling energy matrix.", 20)
self.energyNormMatrix = L2NormMatrix(self.V)
vbMng(self, "DEL", "Done assembling energy matrix.", 20)
def buildDualityPairingForm(self):
"""Build sparse matrix (in CSR format) representative of duality."""
vbMng(self, "INIT", "Assembling duality matrix.", 20)
- self.dualityMatrix = Np2DLikeEye()
+ self.dualityMatrix = Np2DLikeEye(self.spacedim())
vbMng(self, "DEL", "Done assembling duality matrix.", 20)
- def liftDirichletData(self, mu : paramVal = []) -> Np1D:
+ def liftDirichletData(self) -> Np1D:
"""Lift Dirichlet datum."""
- mu = self.checkParameter(mu)
- if mu != self.mu0BC:
- self.mu0BC = copy(mu)
+ if not hasattr(self, "_liftedDirichletDatum"):
liftRe = interp_project(self.DirichletDatum[0], self.V)
liftIm = interp_project(self.DirichletDatum[1], self.V)
- self.liftedDirichletDatum = (np.array(liftRe.vector())
- + 1.j * np.array(liftIm.vector()))
- return self.liftedDirichletDatum
+ self._liftedDirichletDatum = (np.array(liftRe.vector())
+ + 1.j * np.array(liftIm.vector()))
+ return self._liftedDirichletDatum
def reduceQuadratureDegree(self, fun:FenFunc, name:str):
"""Check whether to reduce compiler parameters to degree threshold."""
if not np.isinf(self.degree_threshold):
from ufl.algorithms.estimate_degrees import (
estimate_total_polynomial_degree as ETPD)
try:
deg = ETPD(fun)
except:
return False
if deg > self.degree_threshold:
vbMng(self, "MAIN",
("Reducing quadrature degree from {} to {} for "
"{}.").format(deg, self.degree_threshold, name), 15)
return True
return False
def iterReduceQuadratureDegree(self, funsNames:List[Tuple[FenFunc, str]]):
"""
Iterate reduceQuadratureDegree over list and define reduce compiler
parameters.
"""
if funsNames is not None:
for fun, name in funsNames:
if self.reduceQuadratureDegree(fun, name):
return {"quadrature_degree" : self.degree_threshold}
return {}
+ def setbHomogeneized(self):
+ if not self.homogeneized: return
+ uLifted = None
+ for j in range(len(self.bs) - self.nbs - 1, -1, -1):
+ if self.bs[self.nbs + j] is None:
+ if uLifted is None: uLifted = - self.liftDirichletData()
+ if self.As[j] is None: self.buildA()
+ vbMng(self, "INIT", "Assembling forcing term bH{}.".format(j),
+ 20)
+ bH = dot(self.As[j], uLifted)
+ thbH = self.thAs[j]
+ for i in range(self.nbs):
+ if self.thbs[i][0] == thbH[0]:
+ self.bs[i] = self.bs[i] + bH
+ _ = self.bs.pop(self.nbs + j)
+ _ = self.thbs.pop(self.nbs + j)
+ break
+ else:
+ self.bs[self.nbs + j], self.thbs[self.nbs + j] = bH, thbH
+ vbMng(self, "DEL", "Done assembling forcing term.", 20)
+
def plot(self, u:Np1D, warping : List[callable] = None, name : str = "u",
save : str = None, what : strLst = 'all',
saveFormat : str = "eps", saveDPI : int = 100, show : bool = True,
fenplotArgs : dict = {}, **figspecs):
"""
Do some nice plots of the complex-valued function with given dofs.
Args:
u: numpy complex array with function dofs.
warping(optional): Domain warping functions.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
show(optional): Whether to show figure. Defaults to True.
fenplotArgs(optional): Optional arguments for fenplot.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
if isinstance(what, (str,)):
if what.upper() == 'ALL':
what = ['ABS', 'PHASE', 'REAL', 'IMAG']
else:
what = [what]
what = purgeList(what, ['ABS', 'PHASE', 'REAL', 'IMAG'],
listname = self.name() + ".what", baselevel = 1)
if len(what) == 0: return
if 'figsize' not in figspecs.keys():
figspecs['figsize'] = (13. * len(what) / 4, 3)
subplotcode = 100 + len(what) * 10
plt.figure(**figspecs)
plt.jet()
if 'ABS' in what:
uAb = fen.Function(self.V)
uAb.vector().set_local(np.abs(u))
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
p = fenplot(uAb, warping = warping, title = "|{0}|".format(name),
**fenplotArgs)
if self.V.mesh().geometric_dimension() > 1:
plt.colorbar(p)
if 'PHASE' in what:
uPh = fen.Function(self.V)
uPh.vector().set_local(np.angle(u))
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
p = fenplot(uPh, warping = warping,
title = "phase({0})".format(name), **fenplotArgs)
if self.V.mesh().geometric_dimension() > 1:
plt.colorbar(p)
if 'REAL' in what:
uRe = fen.Function(self.V)
uRe.vector().set_local(np.real(u))
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
p = fenplot(uRe, warping = warping, title = "Re({0})".format(name),
**fenplotArgs)
if self.V.mesh().geometric_dimension() > 1:
plt.colorbar(p)
if 'IMAG' in what:
uIm = fen.Function(self.V)
uIm.vector().set_local(np.imag(u))
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
p = fenplot(uIm, warping = warping, title = "Im({0})".format(name),
**fenplotArgs)
if self.V.mesh().geometric_dimension() > 1:
plt.colorbar(p)
if save is not None:
save = save.strip()
plt.savefig(getNewFilename("{}_fig_".format(save), saveFormat),
format = saveFormat, dpi = saveDPI)
if show:
plt.show()
plt.close()
def plotmesh(self, warping : List[callable] = None, name : str = "Mesh",
save : str = None, saveFormat : str = "eps",
saveDPI : int = 100, show : bool = True,
fenplotArgs : dict = {}, **figspecs):
"""
Do a nice plot of the mesh.
Args:
u: numpy complex array with function dofs.
warping(optional): Domain warping functions.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
show(optional): Whether to show figure. Defaults to True.
fenplotArgs(optional): Optional arguments for fenplot.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
plt.figure(**figspecs)
fenplot(self.V.mesh(), warping = warping, **fenplotArgs)
if save is not None:
save = save.strip()
plt.savefig(getNewFilename("{}_msh_".format(save), saveFormat),
format = saveFormat, dpi = saveDPI)
if show:
plt.show()
plt.close()
def outParaview(self, u:Np1D, warping : List[callable] = None,
name : str = "u", filename : str = "out",
time : float = 0., what : strLst = 'all',
forceNewFile : bool = True, folder : bool = False,
filePW = None):
"""
Output complex-valued function with given dofs to ParaView file.
Args:
u: numpy complex array with function dofs.
warping(optional): Domain warping functions.
name(optional): Base name to be used for data output.
filename(optional): Name of output file.
time(optional): Timestamp.
what(optional): Which plots to do. If list, can contain 'MESH',
'ABS', 'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard
'ALL'. Defaults to 'ALL'.
forceNewFile(optional): Whether to create new output file.
folder(optional): Whether to create an additional folder layer.
filePW(optional): Fenics File entity (for time series).
"""
if isinstance(what, (str,)):
if what.upper() == 'ALL':
what = ['MESH', 'ABS', 'PHASE', 'REAL', 'IMAG']
else:
what = [what]
what = purgeList(what, ['MESH', 'ABS', 'PHASE', 'REAL', 'IMAG'],
listname = self.name() + ".what", baselevel = 1)
if len(what) == 0: return
if filePW is None:
if folder:
if not path.exists(filename + "/"):
mkdir(filename)
idxpath = filename.rfind("/")
filename += "/" + filename[idxpath + 1 :]
if forceNewFile:
filePW = fen.File(getNewFilename(filename, "pvd"))
else:
filePW = fen.File("{}.pvd".format(filename))
if warping is not None:
fen.ALE.move(self.V.mesh(),
interp_project(warping[0], self.V.mesh()))
if what == ['MESH']:
filePW << (self.V.mesh(), time)
if 'ABS' in what:
uAb = fen.Function(self.V, name = "{}_ABS".format(name))
uAb.vector().set_local(np.abs(u))
filePW << (uAb, time)
if 'PHASE' in what:
uPh = fen.Function(self.V, name = "{}_PHASE".format(name))
uPh.vector().set_local(np.angle(u))
filePW << (uPh, time)
if 'REAL' in what:
uRe = fen.Function(self.V, name = "{}_REAL".format(name))
uRe.vector().set_local(np.real(u))
filePW << (uRe, time)
if 'IMAG' in what:
uIm = fen.Function(self.V, name = "{}_IMAG".format(name))
uIm.vector().set_local(np.imag(u))
filePW << (uIm, time)
if warping is not None:
fen.ALE.move(self.V.mesh(),
interp_project(warping[1], self.V.mesh()))
return filePW
def outParaviewTimeDomain(self, u:Np1D, omega:float,
warping : List[callable] = None,
timeFinal : float = None,
periodResolution : int = 20, name : str = "u",
filename : str = "out",
forceNewFile : bool = True,
folder : bool = False):
"""
Output complex-valued function with given dofs to ParaView file,
converted to time domain.
Args:
u: numpy complex array with function dofs.
omega: frequency.
warping(optional): Domain warping functions.
timeFinal(optional): final time of simulation.
periodResolution(optional): number of time steps per period.
name(optional): Base name to be used for data output.
filename(optional): Name of output file.
forceNewFile(optional): Whether to create new output file.
folder(optional): Whether to create an additional folder layer.
"""
if folder:
if not path.exists(filename + "/"):
mkdir(filename)
idxpath = filename.rfind("/")
filename += "/" + filename[idxpath + 1 :]
if forceNewFile:
filePW = fen.File(getNewFilename(filename, "pvd"))
else:
filePW = fen.File("{}.pvd".format(filename))
omega = np.abs(omega)
t = 0.
dt = 2. * np.pi / omega / periodResolution
if timeFinal is None: timeFinal = 2. * np.pi / omega - dt
if warping is not None:
fen.ALE.move(self.V.mesh(),
interp_project(warping[0], self.V.mesh()))
for j in range(int(np.ceil(timeFinal / dt)) + 1):
ut = fen.Function(self.V, name = name)
ut.vector().set_local(np.real(u) * np.cos(omega * t)
+ np.imag(u) * np.sin(omega * t))
filePW << (ut, t)
t += dt
if warping is not None:
fen.ALE.move(self.V.mesh(),
interp_project(warping[1], self.V.mesh()))
return filePW
diff --git a/rrompy/hfengines/base/vector_problem_engine_base.py b/rrompy/hfengines/base/vector_problem_engine_base.py
index 3cdbbbc..0c57b08 100644
--- a/rrompy/hfengines/base/vector_problem_engine_base.py
+++ b/rrompy/hfengines/base/vector_problem_engine_base.py
@@ -1,224 +1,224 @@
# 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 fenics as fen
import numpy as np
from matplotlib import pyplot as plt
from rrompy.utilities.base.types import Np1D, List, strLst
from rrompy.utilities.base import purgeList, getNewFilename
from rrompy.solver.fenics import fenplot
from .problem_engine_base import ProblemEngineBase
__all__ = ['VectorProblemEngineBase']
class VectorProblemEngineBase(ProblemEngineBase):
"""
Generic solver for parametric vector problems.
Attributes:
verbosity: Verbosity level.
BCManager: Boundary condition manager.
V: Real FE space.
u: Generic trial functions for variational form evaluation.
v: Generic test functions for variational form evaluation.
As: Scipy sparse array representation (in CSC format) of As.
bs: Numpy array representation of bs.
energyNormMatrix: Scipy sparse matrix representing inner product over
V.
energyNormDualMatrix: Scipy sparse matrix representing inner product
over V'.
dualityMatrix: Scipy sparse matrix representing duality V-V'.
energyNormPartialDualMatrix: Scipy sparse matrix representing dual
inner product between Riesz representers V-V.
- liftedDirichletDatum: Dofs of Dirichlet datum lifting.
- mu0BC: Mu value of last Dirichlet datum lifting.
degree_threshold: Threshold for ufl expression interpolation degree.
"""
- def __init__(self, degree_threshold : int = np.inf, verbosity : int = 10,
+ def __init__(self, degree_threshold : int = np.inf,
+ homogeneized : bool = False, verbosity : int = 10,
timestamp : bool = True):
super().__init__(degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
self.V = fen.VectorFunctionSpace(fen.UnitSquareMesh(10, 10), "P", 1)
self.npar = 0
def plot(self, u:Np1D, warping : List[callable] = None, name : str = "u",
save : str = None, what : strLst = 'all',
saveFormat : str = "eps", saveDPI : int = 100, show : bool = True,
fenplotArgs : dict = {}, **figspecs):
"""
Do some nice plots of the complex-valued function with given dofs.
Args:
u: numpy complex array with function dofs.
warping(optional): Domain warping functions.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to.
show(optional): Whether to show figure. Defaults to True.
fenplotArgs(optional): Optional arguments for fenplot.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
if isinstance(what, (str,)):
if what.upper() == 'ALL':
what = ['ABS', 'PHASE', 'REAL', 'IMAG']
else:
what = [what]
what = purgeList(what, ['ABS', 'PHASE', 'REAL', 'IMAG'],
listname = self.name() + ".what", baselevel = 1)
if 'figsize' not in figspecs.keys():
figspecs['figsize'] = (13. * max(len(what), 1) / 4, 3)
if len(what) > 0:
for j in range(self.V.num_sub_spaces()):
subplotcode = 100 + len(what) * 10
II = self.V.sub(j).dofmap().dofs()
Vj = self.V.sub(j).collapse()
plt.figure(**figspecs)
plt.jet()
if 'ABS' in what:
uAb = fen.Function(Vj)
uAb.vector().set_local(np.abs(u[II]))
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
p = fenplot(uAb, warping = warping,
title = "|{}_comp{}|".format(name, j,
**fenplotArgs))
if self.V.mesh().geometric_dimension() > 1:
plt.colorbar(p)
if 'PHASE' in what:
uPh = fen.Function(Vj)
uPh.vector().set_local(np.angle(u[II]))
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
p = fenplot(uPh, warping = warping,
title = "phase({}_comp{})".format(name, j),
**fenplotArgs)
if self.V.mesh().geometric_dimension() > 1:
plt.colorbar(p)
if 'REAL' in what:
uRe = fen.Function(Vj)
uRe.vector().set_local(np.real(u[II]))
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
p = fenplot(uRe, warping = warping,
title = "Re({}_comp{})".format(name, j),
**fenplotArgs)
if self.V.mesh().geometric_dimension() > 1:
plt.colorbar(p)
if 'IMAG' in what:
uIm = fen.Function(Vj)
uIm.vector().set_local(np.imag(u[II]))
subplotcode = subplotcode + 1
plt.subplot(subplotcode)
p = fenplot(uIm, warping = warping,
title = "Im({}_comp{})".format(name, j),
**fenplotArgs)
if self.V.mesh().geometric_dimension() > 1:
plt.colorbar(p)
if save is not None:
save = save.strip()
plt.savefig(getNewFilename("{}_comp{}_fig_".format(save,j),
saveFormat),
format = saveFormat, dpi = saveDPI)
if show:
plt.show()
plt.close()
try:
if len(what) > 1:
figspecs['figsize'] = (2. / len(what) * figspecs['figsize'][0],
figspecs['figsize'][1])
elif len(what) == 0:
figspecs['figsize'] = (2. * figspecs['figsize'][0],
figspecs['figsize'][1])
if len(what) == 0 or 'ABS' in what or 'REAL' in what:
uVRe = fen.Function(self.V)
uVRe.vector().set_local(np.real(u))
plt.figure(**figspecs)
plt.jet()
p = fenplot(uVRe, warping = warping,
title = "{}_Re".format(name),
mode = "displacement", **fenplotArgs)
if self.V.mesh().geometric_dimension() > 1:
plt.colorbar(p)
if save is not None:
save = save.strip()
plt.savefig(getNewFilename("{}_disp_Re_fig_".format(save),
saveFormat),
format = saveFormat, dpi = saveDPI)
plt.show()
plt.close()
if 'ABS' in what or 'IMAG' in what:
uVIm = fen.Function(self.V)
uVIm.vector().set_local(np.imag(u))
plt.figure(**figspecs)
plt.jet()
p = fenplot(uVIm, warping = warping,
title = "{}_Im".format(name),
mode = "displacement", **fenplotArgs)
if self.V.mesh().geometric_dimension() > 1:
plt.colorbar(p)
if save is not None:
save = save.strip()
plt.savefig(getNewFilename("{}_disp_Im_fig_".format(save, j),
saveFormat),
format = saveFormat, dpi = saveDPI)
if show:
plt.show()
plt.close()
except:
pass
def plotmesh(self, warping : List[callable] = None, name : str = "Mesh",
save : str = None, saveFormat : str = "eps",
saveDPI : int = 100, show : bool = True,
fenplotArgs : dict = {}, **figspecs):
"""
Do a nice plot of the mesh.
Args:
u: numpy complex array with function dofs.
warping(optional): Domain warping functions.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
show(optional): Whether to show figure. Defaults to True.
fenplotArgs(optional): Optional arguments for fenplot.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
plt.figure(**figspecs)
fenplot(self.V.mesh(), warping = warping, **fenplotArgs)
if save is not None:
save = save.strip()
plt.savefig(getNewFilename("{}_msh_".format(save), saveFormat),
format = saveFormat, dpi = saveDPI)
if show:
plt.show()
plt.close()
diff --git a/rrompy/hfengines/linear_problem/bidimensional/cookie_engine_single.py b/rrompy/hfengines/linear_problem/bidimensional/cookie_engine_single.py
index d24e1ca..f304d45 100644
--- a/rrompy/hfengines/linear_problem/bidimensional/cookie_engine_single.py
+++ b/rrompy/hfengines/linear_problem/bidimensional/cookie_engine_single.py
@@ -1,125 +1,118 @@
# 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
import fenics as fen
import ufl
from rrompy.utilities.base.types import ScOp, List, paramVal
from rrompy.solver.fenics import fenONE, fenZERO
from rrompy.hfengines.linear_problem.helmholtz_problem_engine import (
HelmholtzProblemEngine)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
+from rrompy.utilities.numerical import hashDerivativeToIdx as hashD
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['CookieEngineSingle']
class CookieEngineSingle(HelmholtzProblemEngine):
def __init__(self, kappa:float, theta:float, n:int, R : int = 1.,
L : int = 2., nX : int = 1, nY : int = 1,
mu0 : paramVal = [12. ** .5, 1.],
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.nAs = 5
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = False
+ self.nAs = 3
self.npar = 2
self.rescalingExp = [2., 2.]
-
mesh = fen.RectangleMesh(fen.Point(0., 0.), fen.Point(L * nX, L * nY),
n * nX, n * nY)
self.V = fen.FunctionSpace(mesh, "P", 1)
-
x, y = fen.SpatialCoordinate(mesh)[:]
cxs = np.linspace(0, L * nX, 2 * nX + 1)[1::2]
cys = np.linspace(0, L * nY, 2 * nY + 1)[1::2]
self.cookieIn = fenZERO
for cx in cxs:
for cy in cys:
self.cookieIn += ufl.conditional(
ufl.le((x-cx)**2. + (y-cy)**2., R**2.),
fenONE, fenZERO)
self.cookieOut = fenONE - self.cookieIn
c, s = np.cos(theta), np.sin(theta)
self.forcingTerm = [fen.cos(kappa * (c * x + s * y)),
fen.sin(kappa * (c * x + s * y))]
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.As[0] is None:
+ self.autoSetDS()
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
aRe, aIm = self.diffusivity
hRe, hIm = self.RobinDatumH
termNames = ["diffusivity", "RobinDatumH"]
parsRe = self.iterReduceQuadratureDegree(zip(
[aRe, hRe],
[x + "Real" for x in termNames]))
parsIm = self.iterReduceQuadratureDegree(zip(
[aIm, hIm],
[x + "Imag" for x in termNames]))
a0Re = (aRe * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
+ hRe * fen.dot(self.u, self.v) * self.ds(1))
a0Im = (aIm * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
+ hIm * fen.dot(self.u, self.v) * self.ds(1))
self.As[0] = (fenics2Sparse(a0Re, parsRe, DirichletBC0, 1)
+ 1.j * fenics2Sparse(a0Im, parsIm, DirichletBC0, 0))
+ self.thAs[0] = self.getMonomialSingleWeight([0, 0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
+ if self.As[1] is None:
vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
["refractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
["refractionIndexSquaredImag"]))
a1Re = - n2Re * self.cookieOut * fen.dot(self.u, self.v) * fen.dx
a1Im = - n2Im * self.cookieOut * fen.dot(self.u, self.v) * fen.dx
self.As[1] = (fenics2Sparse(a1Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a1Im, parsIm, DirichletBC0, 0))
+ self.thAs[1] = self.getMonomialSingleWeight([1, 0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 2 and self.As[2] is None:
- self.As[2] = self.checkAInBounds(-1)
- if derI <= 3 and self.As[3] is None:
- self.As[3] = self.checkAInBounds(-1)
- if derI <= 4 and self.As[4] is None:
- vbMng(self, "INIT", "Assembling operator term A4.", 20)
+ if self.As[2] is None:
+ vbMng(self, "INIT", "Assembling operator term A2.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
["refractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
["refractionIndexSquaredImag"]))
- a4Re = - n2Re * self.cookieIn * fen.dot(self.u, self.v) * fen.dx
- a4Im = - n2Im * self.cookieIn * fen.dot(self.u, self.v) * fen.dx
- self.As[4] = (fenics2Sparse(a4Re, parsRe, DirichletBC0, 0)
- + 1.j * fenics2Sparse(a4Im, parsIm, DirichletBC0, 0))
+ a2Re = - n2Re * self.cookieIn * fen.dot(self.u, self.v) * fen.dx
+ a2Im = - n2Im * self.cookieIn * fen.dot(self.u, self.v) * fen.dx
+ self.As[2] = (fenics2Sparse(a2Re, parsRe, DirichletBC0, 0)
+ + 1.j * fenics2Sparse(a2Im, parsIm, DirichletBC0, 0))
+ self.thAs[2] = self.getMonomialSingleWeight([1, 1])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
-
diff --git a/rrompy/hfengines/linear_problem/bidimensional/helmholtz_square_domain_problem_engine.py b/rrompy/hfengines/linear_problem/bidimensional/helmholtz_square_domain_problem_engine.py
index 343e450..f9d521a 100644
--- a/rrompy/hfengines/linear_problem/bidimensional/helmholtz_square_domain_problem_engine.py
+++ b/rrompy/hfengines/linear_problem/bidimensional/helmholtz_square_domain_problem_engine.py
@@ -1,159 +1,123 @@
# 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 numpy.polynomial.polynomial import polyfit as fit
import fenics as fen
-from rrompy.utilities.base.types import (ScOp, List, Tuple, paramVal, Np1D,
- FenExpr)
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenZERO
from rrompy.hfengines.linear_problem.helmholtz_problem_engine import (
HelmholtzProblemEngine)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD, hashIdxToDerivative as hashI)
from rrompy.solver.fenics import fenics2Sparse, fenics2Vector
__all__ = ['HelmholtzSquareDomainProblemEngine']
class HelmholtzSquareDomainProblemEngine(HelmholtzProblemEngine):
"""
Solver for square Helmholtz problems with parametric laplacian.
- \dxx u - mu_2**2 \dyy u - mu_1**2 * u = f(mu_2) in \Omega = [0,\pi]^2
u = 0 on \partial\Omega
"""
def __init__(self, kappa:float, theta:float, n:int,
mu0 : paramVal = [12. ** .5, 1.],
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.nAs, self.nbs = 6, 11 * 12 // 2
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = False
+ self.nAs, self.nbs = 3, 11
self.npar = 2
self.rescalingExp = [2., 1.]
self._theta = theta
self._kappa = kappa
pi = np.pi
mesh = fen.RectangleMesh(fen.Point(0, 0), fen.Point(pi, pi),
3 * n, 3 * n)
self.V = fen.FunctionSpace(mesh, "P", 1)
- def getForcingTerm(self, mu : paramVal = []) -> Tuple[FenExpr, FenExpr]:
- """Compute forcing term."""
- vbMng(self, "INIT", ("Assembling base expression for forcing term "
- "at {}.").format(mu), 25)
- c, s = np.cos(self._theta), np.sin(self._theta)
- x, y = fen.SpatialCoordinate(self.V.mesh())[:]
- forcingTerm = [fen.cos(self._kappa * (c * x + s / mu * y)),
- fen.sin(self._kappa * (c * x + s / mu * y))]
- vbMng(self, "DEL", "Done assembling base expression.", 25)
- return forcingTerm
-
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- for j in range(2, 5):
- if derI <= j and self.As[j] is None:
- self.As[j] = self.checkAInBounds(-1)
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.As[0] is None:
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
a0Re = fen.dot(self.u.dx(0), self.v.dx(0)) * fen.dx
self.As[0] = fenics2Sparse(a0Re, {}, DirichletBC0, 1)
+ self.thAs[0] = self.getMonomialSingleWeight([0, 0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
+ if self.As[1] is None:
vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
["refractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
["refractionIndexSquaredImag"]))
a1Re = - n2Re * fen.dot(self.u, self.v) * fen.dx
a1Im = - n2Im * fen.dot(self.u, self.v) * fen.dx
self.As[1] = (fenics2Sparse(a1Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a1Im, parsIm, DirichletBC0, 0))
+ self.thAs[1] = self.getMonomialSingleWeight([1, 0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 5 and self.As[5] is None:
- vbMng(self, "INIT", "Assembling operator term A5.", 20)
+ if self.As[2] is None:
+ vbMng(self, "INIT", "Assembling operator term A2.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
- a5Re = fen.dot(self.u.dx(1), self.v.dx(1)) * fen.dx
- self.As[5] = fenics2Sparse(a5Re, {}, DirichletBC0, 0)
+ a2Re = fen.dot(self.u.dx(1), self.v.dx(1)) * fen.dx
+ self.As[2] = fenics2Sparse(a2Re, {}, DirichletBC0, 0)
+ self.thAs[2] = self.getMonomialSingleWeight([0, 2])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
- def b(self, mu : paramVal = [], der : List[int] = 0,
- homogeneized : bool = False) -> Np1D:
- """Assemble (derivative of) RHS of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- nbsTot = self.nbsH if homogeneized else self.nbs
- bs = self.bsH if homogeneized else self.bs
- if homogeneized and self.mu0 != self.mu0BC:
- self.liftDirichletData(self.mu0)
+ def buildb(self):
+ """Build terms of operator of linear system."""
+ if self.thbs[0] is None:
+ self.thbs = [None] * (self.nbs + self.homogeneized * self.nAs)
bDEIMCoeffs = None
- for j in range(derI, nbsTot):
- derH = hashI(j, self.npar)
- if bs[j] is None:
- if np.sum(derH) != derH[-1]:
- if homogeneized:
- self.bsH[j] = self.checkbInBounds(-1)
- Ader = self.A(0, derH)
- self.bsH[j] -= Ader.dot(self.liftedDirichletDatum)
- else:
- self.bs[j] = self.checkbInBounds(-1)
- continue
+ for j in range(self.nbs):
+ if self.bs[j] is None:
vbMng(self, "INIT", "Assembling forcing term b{}.".format(j),
20)
if bDEIMCoeffs is None:
- bDEIM = np.empty((np.sum(hashI(nbsTot, self.npar)),
- self.spacedim()), dtype = np.complex)
+ bDEIM = np.empty((self.nbs, self.spacedim()),
+ dtype = np.complex)
muDEIM = np.linspace(.5, 4., bDEIM.shape[0])
for jj, muD in enumerate(muDEIM):
- fRe, fIm = self.getForcingTerm(muD)
+ c, s = np.cos(self._theta), np.sin(self._theta)
+ x, y = fen.SpatialCoordinate(self.V.mesh())[:]
+ fRe = fen.cos(self._kappa * (c * x + s / muD * y))
+ fIm = fen.sin(self._kappa * (c * x + s / muD * y))
parsRe = self.iterReduceQuadratureDegree(zip([fRe],
["forcingTerm{}Real".format(jj)]))
parsIm = self.iterReduceQuadratureDegree(zip([fIm],
["forcingTerm{}Imag".format(jj)]))
LR = fen.dot(fRe, self.v) * fen.dx
LI = fen.dot(fIm, self.v) * fen.dx
DBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
bDEIM[jj] = (fenics2Vector(LR, parsRe, DBC0, 1)
+ 1.j * fenics2Vector(LI, parsIm, DBC0, 1))
bDEIMCoeffs = fit(muDEIM, bDEIM, len(muDEIM) - 1)
- b = bDEIMCoeffs[derH[-1]]
- if homogeneized:
- Ader = self.A(0, derH)
- b -= Ader.dot(self.liftedDirichletDatum)
- if homogeneized:
- self.bsH[j] = b
- else:
- self.bs[j] = b
+ self.bs[j] = bDEIMCoeffs[j]
+ self.thbs[j] = self.getMonomialSingleWeight([0, j])
vbMng(self, "DEL", "Done assembling forcing term.", 20)
- return self._assembleb(mu, der, derI, homogeneized)
-
+ self.setbHomogeneized()
diff --git a/rrompy/hfengines/linear_problem/bidimensional/helmholtz_square_simplified_domain_problem_engine.py b/rrompy/hfengines/linear_problem/bidimensional/helmholtz_square_simplified_domain_problem_engine.py
index b99b9e4..c0c3476 100644
--- a/rrompy/hfengines/linear_problem/bidimensional/helmholtz_square_simplified_domain_problem_engine.py
+++ b/rrompy/hfengines/linear_problem/bidimensional/helmholtz_square_simplified_domain_problem_engine.py
@@ -1,94 +1,89 @@
# 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
import fenics as fen
-from rrompy.utilities.base.types import ScOp, List, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenZERO
from rrompy.hfengines.linear_problem.helmholtz_problem_engine import (
HelmholtzProblemEngine)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['HelmholtzSquareSimplifiedDomainProblemEngine']
class HelmholtzSquareSimplifiedDomainProblemEngine(HelmholtzProblemEngine):
"""
Solver for square Helmholtz problems with parametric laplacian.
- \dxx u - mu_2**2 \dyy u - mu_1**2 * u = f in \Omega_mu = [0,\pi]^2
u = 0 on \partial\Omega
"""
def __init__(self, kappa:float, theta:float, n:int,
mu0 : paramVal = [12. ** .5, 1.],
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = True
self.nAs = 3
self.npar = 2
self.rescalingExp = [2., 2.]
pi = np.pi
mesh = fen.RectangleMesh(fen.Point(0, 0), fen.Point(pi, pi),
3 * n, 3 * n)
self.V = fen.FunctionSpace(mesh, "P", 1)
c, s = np.cos(theta), np.sin(theta)
x, y = fen.SpatialCoordinate(mesh)[:]
self.forcingTerm = [fen.cos(kappa * (c * x + s * y)),
fen.sin(kappa * (c * x + s * y))]
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.thAs[0] is None: self.thAs = self.getMonomialWeights(self.nAs)
+ if self.As[0] is None:
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
a0Re = fen.dot(self.u.dx(0), self.v.dx(0)) * fen.dx
self.As[0] = fenics2Sparse(a0Re, {}, DirichletBC0, 1)
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
+ if self.As[1] is None:
vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
["refractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
["refractionIndexSquaredImag"]))
a1Re = - n2Re * fen.dot(self.u, self.v) * fen.dx
a1Im = - n2Im * fen.dot(self.u, self.v) * fen.dx
self.As[1] = (fenics2Sparse(a1Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a1Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 2 and self.As[2] is None:
+ if self.As[2] is None:
vbMng(self, "INIT", "Assembling operator term A2.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
a2Re = fen.dot(self.u.dx(1), self.v.dx(1)) * fen.dx
self.As[2] = fenics2Sparse(a2Re, {}, DirichletBC0, 0)
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
-
diff --git a/rrompy/hfengines/linear_problem/bidimensional/laplace_disk_gaussian_2.py b/rrompy/hfengines/linear_problem/bidimensional/laplace_disk_gaussian_2.py
index 73cd317..d3b49c2 100644
--- a/rrompy/hfengines/linear_problem/bidimensional/laplace_disk_gaussian_2.py
+++ b/rrompy/hfengines/linear_problem/bidimensional/laplace_disk_gaussian_2.py
@@ -1,115 +1,98 @@
# 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
import fenics as fen
-from rrompy.utilities.base.types import Np1D, Tuple, List, FenExpr, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.hfengines.linear_problem.laplace_disk_gaussian import (
LaplaceDiskGaussian)
-from rrompy.solver.fenics import fenZERO, fenONE
+from rrompy.solver.fenics import fenZERO
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD, hashIdxToDerivative as hashI)
-from rrompy.utilities.exception_manager import RROMPyException
+ PolynomialInterpolator as PI)
from rrompy.solver.fenics import fenics2Vector
__all__ = ['LaplaceDiskGaussian2']
class LaplaceDiskGaussian2(LaplaceDiskGaussian):
"""
Solver for disk Laplace problems with parametric forcing term center.
- \Delta u = C exp(-.5 * ||\cdot - (mu1, mu2)||^2) in \Omega = B(0, 5)
u = 0 on \partial\Omega.
"""
def __init__(self, n:int, mu0 : paramVal = [0., 0.],
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(n = n, mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.nbs = 1
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self.nbs = 16
self.npar = 2
- def getForcingTerm(self, mu : paramVal = []) -> Tuple[FenExpr, FenExpr]:
- """Compute forcing term."""
- mu = self.checkParameter(mu)
- if mu != self.forcingTermMu:
- vbMng(self, "INIT", "Assembling base expression for forcing term.",
- 25)
- x, y = fen.SpatialCoordinate(self.V.mesh())[:]
- C = np.exp(-.5 * (mu(0, 0) ** 2. + mu(0, 1) ** 2.))
- CR, CI = np.real(C), np.imag(C)
- f0 = (2 * np.pi) ** -.5 * fen.exp(-.5 * (x ** 2. + y ** 2.))
- muxR, muxI = np.real(mu(0, 0)), np.imag(mu(0, 0))
- muyR, muyI = np.real(mu(0, 1)), np.imag(mu(0, 1))
- f1R = fen.exp(muxR * x + muyR * y) * fen.cos(muxI * x + muyI * y)
- f1I = fen.exp(muxR * x + muyR * y) * fen.sin(muxI * x + muyI * y)
- self.forcingTerm = [f0 * (CR * f1R - CI * f1I),
- f0 * (CR * f1I + CI * f1R)]
- self.forcingTermMu = mu
- vbMng(self, "DEL", "Done assembling base expression.", 25)
- return self.forcingTerm
-
- def computebsFactors(self):
- pass
-
- def getExtraFactorB(self, mu : paramVal = [],
- derI : int = 0) -> Tuple[FenExpr, FenExpr]:
- if derI == 0: return [fenONE, fenZERO]
- raise RROMPyException("Not implemented.")
-
- def b(self, mu : paramVal = [], der : List[int] = 0,
- homogeneized : bool = False) -> Np1D:
- """Assemble (derivative of) RHS of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- nbsTot = self.nbsH if homogeneized else self.nbs
- bs = self.bsH if homogeneized else self.bs
- if homogeneized and self.mu0 != self.mu0BC:
- self.liftDirichletData(self.mu0)
- for j in range(derI, nbsTot):
- if bs[j] is None:
+ def buildb(self):
+ """Build terms of operator of linear system."""
+ if self.thbs[0] is None:
+ self.thbs = [None] * (self.nbs + self.homogeneized * self.nAs)
+ bDEIMCoeffs = None
+ for j in range(self.nbs):
+ j1, j2 = j % int(self.nbs ** .5), j // int(self.nbs ** .5)
+ if self.bs[j] is None:
vbMng(self, "INIT", "Assembling forcing term b{}.".format(j),
20)
- if j < self.nbs:
- fRe, fIm = self.getForcingTerm(mu)
- cRe, cIm = self.getExtraFactorB(mu, j)
- cfRe, cfIm = cRe * fRe - cIm * fIm, cRe * fIm + cIm * fRe
- else:
- cfRe, cfIm = fenZERO, fenZERO
- parsRe = self.iterReduceQuadratureDegree(zip([cfRe],
- ["forcingTermDer{}Real".format(j)]))
- parsIm = self.iterReduceQuadratureDegree(zip([cfIm],
- ["forcingTermDer{}Imag".format(j)]))
- L0Re = fen.dot(cfRe, self.v) * fen.dx
- L0Im = fen.dot(cfIm, self.v) * fen.dx
- DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
+ if bDEIMCoeffs is None:
+ bDEIM = np.empty((self.nbs, self.spacedim()),
+ dtype = np.complex)
+ muD1 = np.linspace(-2., 2., int(self.nbs ** .5))
+ muDEIM = np.empty((self.nbs, 2))
+ muDEIM[:, 0] = np.repeat(muD1, int(self.nbs ** .5))
+ muDEIM[:, 1] = np.tile(muD1, int(self.nbs ** .5))
+ for jj, muD in enumerate(muDEIM):
+ x, y = fen.SpatialCoordinate(self.V.mesh())[:]
+ C = np.exp(-.5 * (muD[0] ** 2. + muD[1] ** 2.))
+ CR, CI = np.real(C), np.imag(C)
+ f0 = ((2 * np.pi) ** -.5
+ * fen.exp(-.5 * (x ** 2. + y ** 2.)))
+ muxR, muxI = np.real(muD[0]), np.imag(muD[0])
+ muyR, muyI = np.real(muD[1]), np.imag(muD[1])
+ f1R = (fen.exp(muxR * x + muyR * y)
+ * fen.cos(muxI * x + muyI * y))
+ f1I = (fen.exp(muxR * x + muyR * y)
+ * fen.sin(muxI * x + muyI * y))
+ fRe = f0 * (CR * f1R - CI * f1I) + fenZERO
+ fIm = f0 * (CR * f1I + CI * f1R) + fenZERO
+ parsRe = self.iterReduceQuadratureDegree(zip([fRe],
+ ["forcingTerm{}Real".format(jj)]))
+ parsIm = self.iterReduceQuadratureDegree(zip([fIm],
+ ["forcingTerm{}Imag".format(jj)]))
+ LR = fen.dot(fRe, self.v) * fen.dx
+ LI = fen.dot(fIm, self.v) * fen.dx
+ DBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
- b = (fenics2Vector(L0Re, parsRe, DirichletBC0, 1)
- + 1.j * fenics2Vector(L0Im, parsIm, DirichletBC0, 1))
- if homogeneized:
- Ader = self.A(0, hashI(j, self.npar))
- b -= Ader.dot(self.liftedDirichletDatum)
- if homogeneized:
- self.bsH[j] = b
- else:
- self.bs[j] = b
+ bDEIM[jj] = (fenics2Vector(LR, parsRe, DBC0, 1)
+ + 1.j * fenics2Vector(LI, parsIm, DBC0, 1))
+ p = PI()
+ wellCond, _ = p.setupByInterpolation(muDEIM, bDEIM,
+ int(self.nbs ** .5) - 1,
+ "MONOMIAL", False, False)
+ bDEIMCoeffs = p.coeffs
+ self.bs[j1 + int(self.nbs ** .5) * j2] = bDEIMCoeffs[j1, j2]
+ self.thbs[j1 + int(self.nbs ** .5) * j2] = (
+ self.getMonomialSingleWeight([j1, j2]))
vbMng(self, "DEL", "Done assembling forcing term.", 20)
- return self._assembleb(mu, der, derI, homogeneized)
-
+ self.setbHomogeneized()
diff --git a/rrompy/hfengines/linear_problem/bidimensional/membrane_fracture_engine.py b/rrompy/hfengines/linear_problem/bidimensional/membrane_fracture_engine.py
index dd131a4..ae8bac0 100644
--- a/rrompy/hfengines/linear_problem/bidimensional/membrane_fracture_engine.py
+++ b/rrompy/hfengines/linear_problem/bidimensional/membrane_fracture_engine.py
@@ -1,156 +1,146 @@
# 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
import fenics as fen
import mshr, ufl
-from rrompy.utilities.base.types import ScOp, List, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenZERO, fenONE
from rrompy.hfengines.linear_problem.helmholtz_problem_engine import (
HelmholtzProblemEngine)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['MembraneFractureEngine']
class MembraneFractureEngine(HelmholtzProblemEngine):
def __init__(self, mu0 : paramVal = [20. ** .5, .6], H : float = 1.,
L : float = .75, delta : float = .05, n : int = 50,
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.nAs = 20
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = False
+ self.nAs = 5
self.npar = 2
self.H = H
self.rescalingExp = [2., 1.]
domain = (mshr.Rectangle(fen.Point(0., - H / 2.),
fen.Point(2. * L + delta, H / 2.))
- mshr.Rectangle(fen.Point(L, 0.),
fen.Point(L + delta, H / 2.)))
mesh = mshr.generate_mesh(domain, n)
self.V = fen.FunctionSpace(mesh, "P", 1)
self.NeumannBoundary = lambda x, on_b: (on_b and x[1] >= - H / 4.
and x[0] >= L
and x[0] <= L + delta)
self.DirichletBoundary = "REST"
x, y = fen.SpatialCoordinate(mesh)[:]
self._belowIndicator = ufl.conditional(ufl.le(y, 0.), fenONE, fenZERO)
self._aboveIndicator = fenONE - self._belowIndicator
self.DirichletDatum = [fen.exp(- 10. * (H / 2. + y) / H
- .5 * ((x - .6 * L) / (.1 * L)) ** 2.
) * self._belowIndicator, fenZERO]
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- for j in [1, 3, 4, 6, 7, 10, 11, 12, 15, 16, 17, 18]:
- if derI <= j and self.As[j] is None:
- self.As[j] = self.checkAInBounds(-1)
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.As[0] is None:
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
- a0Re = (self.H ** 4 / 4. * self._aboveIndicator
- * fen.dot(self.u.dx(1), self.v.dx(1)) * fen.dx)
+ a0Re = fenZERO * fen.dot(self.u, self.v) * fen.dx
self.As[0] = fenics2Sparse(a0Re, {}, DirichletBC0, 1)
+ self.thAs[0] = self.getMonomialSingleWeight([0, 0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 2 and self.As[2] is None:
- vbMng(self, "INIT", "Assembling operator term A2.", 20)
+ if self.As[1] is None:
+ vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
- a2Re = (- self.H ** 3 / 2. * self._aboveIndicator
+ a1Re = (self.H ** 3 / 4. * self._aboveIndicator
* fen.dot(self.u.dx(1), self.v.dx(1)) * fen.dx)
- self.As[2] = fenics2Sparse(a2Re, {}, DirichletBC0, 0)
+ self.As[1] = fenics2Sparse(a1Re, {}, DirichletBC0, 0)
+ self.thAs[1] = [('x', '()', 1, '*', -2., '+', self.H),
+ (0.,), (-2.,), None]
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 5 and self.As[5] is None:
- vbMng(self, "INIT", "Assembling operator term A6.", 20)
- DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
- self.DirichletBoundary)
- a5Re = self.H ** 2 * (fen.dot(self.u.dx(0), self.v.dx(0))
- + .25 * fen.dot(self.u.dx(1), self.v.dx(1))) * fen.dx
- self.As[5] = fenics2Sparse(a5Re, {}, DirichletBC0, 0)
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 8 and self.As[8] is None:
- vbMng(self, "INIT", "Assembling operator term A8.", 20)
- DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
- self.DirichletBoundary)
- nRe, nIm = self.refractionIndex
- n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
- parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
- ["refractionIndexSquaredReal"]))
- parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
- ["refractionIndexSquaredImag"]))
- a8Re = - self.H ** 2. * n2Re * fen.dot(self.u, self.v) * fen.dx
- a8Im = - self.H ** 2. * n2Im * fen.dot(self.u, self.v) * fen.dx
- self.As[8] = (fenics2Sparse(a8Re, parsRe, DirichletBC0, 0)
- + 1.j * fenics2Sparse(a8Im, parsIm, DirichletBC0, 0))
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 9 and self.As[9] is None:
- vbMng(self, "INIT", "Assembling operator term A9.", 20)
+ if self.As[2] is None:
+ vbMng(self, "INIT", "Assembling operator term A2.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
- a9Re = - 2. * self.H * fen.dot(self.u.dx(0), self.v.dx(0)) * fen.dx
- self.As[9] = fenics2Sparse(a9Re, {}, DirichletBC0, 0)
+ a2Re = self.H ** 2 * fen.dot(self.u.dx(0), self.v.dx(0)) * fen.dx
+ self.As[2] = fenics2Sparse(a2Re, {}, DirichletBC0, 0)
+ self.thAs[2] = [('x', '()', 1, '*', -1., '+', self.H, '*',
+ ('x', '()', 1), '**', 2.),
+ (0.,), ('x', '()', 1, '**', 2., '*', 4., '-',
+ ('x', '()', 1, '*', 6. * self.H), '+',
+ 2. * self.H ** 2., '*', ('x', '()', 1)),
+ (0.,), (0.,), ('x', '()', 1, '**', 2., '*', 6., '-',
+ ('x', '()', 1, '*', 6. * self.H), '+',
+ self.H ** 2.),
+ (0.,), (0.,), (0.,), ('x', '()', 1, '*', 4.,
+ '-', 2. * self.H),
+ (0.,), (0.,), (0.,), (0.,), (1.,), None]
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 13 and self.As[13] is None:
- vbMng(self, "INIT", "Assembling operator term A13.", 20)
+ if self.As[3] is None:
+ vbMng(self, "INIT", "Assembling operator term A3.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
["refractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
["refractionIndexSquaredImag"]))
- a13Re = 2. * self.H * n2Re * fen.dot(self.u, self.v) * fen.dx
- a13Im = 2. * self.H * n2Im * fen.dot(self.u, self.v) * fen.dx
- self.As[13] = (fenics2Sparse(a13Re, parsRe, DirichletBC0, 0)
- + 1.j * fenics2Sparse(a13Im, parsIm, DirichletBC0, 0))
+ a3Re = - n2Re * fen.dot(self.u, self.v) * fen.dx
+ a3Im = - n2Im * fen.dot(self.u, self.v) * fen.dx
+ self.As[3] = (fenics2Sparse(a3Re, parsRe, DirichletBC0, 0)
+ + 1.j * fenics2Sparse(a3Im, parsIm, DirichletBC0, 0))
+ self.thAs[3] = [('x', '()', 1, '*', -1., '+', self.H, '*',
+ ('x', '()', 1), '**', 2., '*', ('x', '()', 0)),
+ ('x', '()', 1, '*', -1., '+', self.H, '*',
+ ('x', '()', 1), '**', 2.),
+ (2. * self.H ** 2., '-',
+ ('x', '()', 1, '*', 6. * self.H), '+',
+ ('x', '()', 1, '**', 2., '*', 4.), '*',
+ ('x', '()', 1), '*', ('x', '()', 0)),
+ (0.,), ('x', '()', 1, '**', 2., '*', 4., '-',
+ ('x', '()', 1, '*', 6. * self.H), '+',
+ 2. * self.H ** 2., '*', ('x', '()', 1)),
+ ('x', '()', 1, '**', 2., '*', 6., '-',
+ ('x', '()', 1, '*', 6. * self.H), '+',
+ self.H ** 2., '*', ('x', '()', 0)), (0.,), (0.,),
+ ('x', '()', 1, '**', 2., '*', 6., '-',
+ ('x', '()', 1, '*', 6. * self.H), '+',
+ self.H ** 2.),
+ ('x', '()', 1, '*', 4., '-', 2. * self.H, '*',
+ ('x', '()', 0)), (0.,), (0.,), (0.,),
+ ('x', '()', 1, '*', 4., '-', 2. * self.H),
+ ('x', '()', 0), (0.,), (0.,), (0.,), (0.,),
+ (1.,), None]
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 14 and self.As[14] is None:
- vbMng(self, "INIT", "Assembling operator term A14.", 20)
+ if self.As[4] is None:
+ vbMng(self, "INIT", "Assembling operator term A4.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
- a14Re = fen.dot(self.u.dx(0), self.v.dx(0)) * fen.dx
- self.As[14] = fenics2Sparse(a14Re, {}, DirichletBC0, 0)
+ a4Re = .25 * self.H ** 2 * fen.dot(self.u.dx(1),
+ self.v.dx(1)) * fen.dx
+ self.As[4] = fenics2Sparse(a4Re, {}, DirichletBC0, 0)
+ self.thAs[4] = self.getMonomialSingleWeight([0, 2])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 19 and self.As[19] is None:
- vbMng(self, "INIT", "Assembling operator term A19.", 20)
- DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
- self.DirichletBoundary)
- nRe, nIm = self.refractionIndex
- n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
- parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
- ["refractionIndexSquaredReal"]))
- parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
- ["refractionIndexSquaredImag"]))
- a19Re = - n2Re * fen.dot(self.u, self.v) * fen.dx
- a19Im = - n2Im * fen.dot(self.u, self.v) * fen.dx
- self.As[19] = (fenics2Sparse(a19Re, parsRe, DirichletBC0, 0)
- + 1.j * fenics2Sparse(a19Im, parsIm, DirichletBC0, 0))
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
-
diff --git a/rrompy/hfengines/linear_problem/bidimensional/synthetic_bivariate_engine.py b/rrompy/hfengines/linear_problem/bidimensional/synthetic_bivariate_engine.py
index c7315a7..1b1637f 100644
--- a/rrompy/hfengines/linear_problem/bidimensional/synthetic_bivariate_engine.py
+++ b/rrompy/hfengines/linear_problem/bidimensional/synthetic_bivariate_engine.py
@@ -1,111 +1,108 @@
# 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
import fenics as fen
import ufl
-from rrompy.utilities.base.types import ScOp, List, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenONE, fenZERO
from rrompy.hfengines.linear_problem.helmholtz_problem_engine import (
HelmholtzProblemEngine)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['SyntheticBivariateEngine']
class SyntheticBivariateEngine(HelmholtzProblemEngine):
def __init__(self, kappa:float, theta:float, n:int, L : int = 2.,
mu0 : paramVal = [12. ** .5, 15. ** .5],
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = True
self.nAs = 3
self.npar = 2
self.rescalingExp = [2., 2.]
mesh = fen.RectangleMesh(fen.Point(0., 0.), fen.Point(L, L), n, n)
self.V = fen.FunctionSpace(mesh, "P", 1)
x, y = fen.SpatialCoordinate(mesh)[:]
self._above = ufl.conditional(ufl.ge(y, .5 * L), fenONE, fenZERO)
self._below = fenONE - self._above
c, s = np.cos(theta), np.sin(theta)
self.forcingTerm = [fen.cos(kappa * (c * x + s * y)),
fen.sin(kappa * (c * x + s * y))]
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.thAs[0] is None: self.thAs = self.getMonomialWeights(self.nAs)
+ if self.As[0] is None:
+ self.autoSetDS()
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
aRe, aIm = self.diffusivity
hRe, hIm = self.RobinDatumH
termNames = ["diffusivity", "RobinDatumH"]
parsRe = self.iterReduceQuadratureDegree(zip(
[aRe, hRe],
[x + "Real" for x in termNames]))
parsIm = self.iterReduceQuadratureDegree(zip(
[aIm, hIm],
[x + "Imag" for x in termNames]))
a0Re = (aRe * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
+ hRe * fen.dot(self.u, self.v) * self.ds(1))
a0Im = (aIm * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
+ hIm * fen.dot(self.u, self.v) * self.ds(1))
self.As[0] = (fenics2Sparse(a0Re, parsRe, DirichletBC0, 1)
+ 1.j * fenics2Sparse(a0Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
+ if self.As[1] is None:
vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
["refractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
["refractionIndexSquaredImag"]))
a1Re = - n2Re * self._above * fen.dot(self.u, self.v) * fen.dx
a1Im = - n2Im * self._above * fen.dot(self.u, self.v) * fen.dx
self.As[1] = (fenics2Sparse(a1Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a1Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 2 and self.As[2] is None:
+ if self.As[2] is None:
vbMng(self, "INIT", "Assembling operator term A2.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
["refractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
["refractionIndexSquaredImag"]))
a2Re = - n2Re * self._below * fen.dot(self.u, self.v) * fen.dx
a2Im = - n2Im * self._below * fen.dot(self.u, self.v) * fen.dx
self.As[2] = (fenics2Sparse(a2Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a2Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
diff --git a/rrompy/hfengines/linear_problem/helmholtz_box_scattering_problem_engine.py b/rrompy/hfengines/linear_problem/helmholtz_box_scattering_problem_engine.py
index 20a0480..916a8c1 100644
--- a/rrompy/hfengines/linear_problem/helmholtz_box_scattering_problem_engine.py
+++ b/rrompy/hfengines/linear_problem/helmholtz_box_scattering_problem_engine.py
@@ -1,58 +1,58 @@
# 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
import fenics as fen
from .scattering_problem_engine import ScatteringProblemEngine
__all__ = ['HelmholtzBoxScatteringProblemEngine']
class HelmholtzBoxScatteringProblemEngine(ScatteringProblemEngine):
"""
Solver for scattering problem outside a box with parametric wavenumber.
- \Delta u - omega^2 * n^2 * u = 0 in \Omega
u = 0 on \Gamma_D
\partial_nu - i k u = 0 on \Gamma_R
with exact solution a transmitted plane wave.
"""
def __init__(self, R:float, kappa:float, theta:float, n:int,
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = [kappa], degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
-
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
import mshr
scatterer = mshr.Polygon([fen.Point(-1, -.5), fen.Point(1, -.5),
fen.Point(1, .5), fen.Point(.8, .5),
fen.Point(.8, -.3), fen.Point(-.8, -.3),
fen.Point(-.8, .5), fen.Point(-1, .5),])
mesh = mshr.generate_mesh(mshr.Circle(fen.Point(0, 0), R) - scatterer,
3 * n)
self.V = fen.FunctionSpace(mesh, "P", 1)
self.DirichletBoundary = (lambda x, on_boundary:
on_boundary and (x[0]**2+x[1]**2)**.5 < .95 * R)
self.RobinBoundary = "REST"
c, s = np.cos(theta), np.sin(theta)
x, y = fen.SpatialCoordinate(mesh)[:]
u0R = - fen.cos(kappa * (c * x + s * y))
u0I = - fen.sin(kappa * (c * x + s * y))
self.DirichletDatum = [u0R, u0I]
diff --git a/rrompy/hfengines/linear_problem/helmholtz_cavity_scattering_problem_engine.py b/rrompy/hfengines/linear_problem/helmholtz_cavity_scattering_problem_engine.py
index 5efe8ec..48873bd 100644
--- a/rrompy/hfengines/linear_problem/helmholtz_cavity_scattering_problem_engine.py
+++ b/rrompy/hfengines/linear_problem/helmholtz_cavity_scattering_problem_engine.py
@@ -1,59 +1,59 @@
# 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
import fenics as fen
from .scattering_problem_engine import ScatteringProblemEngine
__all__ = ['HelmholtzCavityScatteringProblemEngine']
class HelmholtzCavityScatteringProblemEngine(ScatteringProblemEngine):
"""
Solver for scattering problem inside a cavity with parametric wavenumber.
- \Delta u - omega^2 * n^2 * u = 0 in \Omega
u = 0 on \Gamma_D
\partial_nu - i k u = 0 on \Gamma_R
with exact solution a transmitted plane wave.
"""
def __init__(self, kappa:float, n:int, gamma : float = 0.,
signR : int = -1, degree_threshold : int = np.inf,
- verbosity : int = 10, timestamp : bool = True):
+ homogeneized : bool = False, verbosity : int = 10,
+ timestamp : bool = True):
super().__init__(mu0 = [kappa], degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
-
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
self.signR = signR
pi = np.pi
mesh = fen.RectangleMesh(fen.Point(0, 0), fen.Point(pi, pi),
3 * n, 3 * n)
self.V = fen.FunctionSpace(mesh, "P", 1)
self.RobinBoundary = (lambda x, on_boundary: on_boundary
and np.isclose(x[1], np.pi))
self.DirichletBoundary = "REST"
x, y = fen.SpatialCoordinate(mesh)[:]
C = 4. / pi ** 4.
bR = C * (2 * (x * (pi - x) + y * (2 * pi - y))
+ (kappa * gamma) ** 2. * x * (pi - x) * y * (2 * pi - y))
bI = C * signR * 2 * kappa * (gamma * (pi - 2 * x) * y * (pi - y)
+ 2 * x * (pi - x) * (pi - y))
wR = fen.cos(kappa * signR * (gamma * x + y))
wI = fen.sin(kappa * signR * (gamma * x + y))
self.forcingTerm = [bR * wR + bI * wI, bI * wR - bR * wI]
-
diff --git a/rrompy/hfengines/linear_problem/helmholtz_problem_engine.py b/rrompy/hfengines/linear_problem/helmholtz_problem_engine.py
index ad74541..e470d63 100644
--- a/rrompy/hfengines/linear_problem/helmholtz_problem_engine.py
+++ b/rrompy/hfengines/linear_problem/helmholtz_problem_engine.py
@@ -1,137 +1,132 @@
# 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
import fenics as fen
from .laplace_base_problem_engine import LaplaceBaseProblemEngine
-from rrompy.utilities.base.types import List, ScOp, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenZERO, fenONE
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['HelmholtzProblemEngine']
class HelmholtzProblemEngine(LaplaceBaseProblemEngine):
"""
Solver for generic Helmholtz problems with parametric wavenumber.
- \nabla \cdot (a \nabla u) - omega^2 * n**2 * u = f in \Omega
u = u0 on \Gamma_D
\partial_nu = g1 on \Gamma_N
\partial_nu + h u = g2 on \Gamma_R
Attributes:
+ homogeneized: Whether to homogeneize Dirichlet BCs.
verbosity: Verbosity level.
BCManager: Boundary condition manager.
V: Real FE space.
u: Generic trial functions for variational form evaluation.
v: Generic test functions for variational form evaluation.
As: Scipy sparse array representation (in CSC format) of As.
bs: Numpy array representation of bs.
- bsH: Numpy array representation of homogeneized bs.
energyNormMatrix: Scipy sparse matrix representing inner product over
V.
energyNormDualMatrix: Scipy sparse matrix representing inner product
over V'.
dualityMatrix: Scipy sparse matrix representing duality V-V'.
energyNormPartialDualMatrix: Scipy sparse matrix representing dual
inner product between Riesz representers V-V.
- liftedDirichletDatum: Dofs of Dirichlet datum lifting.
- mu0BC: Mu value of last Dirichlet datum lifting.
degree_threshold: Threshold for ufl expression interpolation degree.
omega: Value of omega.
diffusivity: Value of a.
refractionIndex: Value of n.
forcingTerm: Value of f.
DirichletDatum: Value of u0.
NeumannDatum: Value of g1.
RobinDatumG: Value of g2.
RobinDatumH: Value of h.
DirichletBoundary: Function handle to \Gamma_D.
NeumannBoundary: Function handle to \Gamma_N.
RobinBoundary: Function handle to \Gamma_R.
ds: Boundary measure 2-tuple (resp. for Neumann and Robin boundaries).
A0: Scipy sparse array representation (in CSC format) of A0.
A1: Scipy sparse array representation (in CSC format) of A1.
b0: Numpy array representation of b0.
dsToBeSet: Whether ds needs to be set.
"""
def __init__(self, mu0 : paramVal = [0.], degree_threshold : int = np.inf,
- verbosity : int = 10, timestamp : bool = True):
+ homogeneized : bool = False, verbosity : int = 10,
+ timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = True
self.nAs = 2
self.rescalingExp = [2.]
self.refractionIndex = fenONE
@property
def refractionIndex(self):
"""Value of n."""
return self._refractionIndex
@refractionIndex.setter
def refractionIndex(self, refractionIndex):
self.resetAs()
if not isinstance(refractionIndex, (list, tuple,)):
refractionIndex = [refractionIndex, fenZERO]
self._refractionIndex = refractionIndex
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.thAs[0] is None: self.thAs = self.getMonomialWeights(self.nAs)
+ if self.As[0] is None:
self.autoSetDS()
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
aRe, aIm = self.diffusivity
hRe, hIm = self.RobinDatumH
termNames = ["diffusivity", "RobinDatumH"]
parsRe = self.iterReduceQuadratureDegree(zip(
[aRe, hRe],
[x + "Real" for x in termNames]))
parsIm = self.iterReduceQuadratureDegree(zip(
[aIm, hIm],
[x + "Imag" for x in termNames]))
a0Re = (aRe * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
+ hRe * fen.dot(self.u, self.v) * self.ds(1))
a0Im = (aIm * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
+ hIm * fen.dot(self.u, self.v) * self.ds(1))
self.As[0] = (fenics2Sparse(a0Re, parsRe, DirichletBC0, 1)
+ 1.j * fenics2Sparse(a0Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
+ if self.As[1] is None:
vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
["refractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
["refractionIndexSquaredImag"]))
a1Re = - n2Re * fen.dot(self.u, self.v) * fen.dx
a1Im = - n2Im * fen.dot(self.u, self.v) * fen.dx
self.As[1] = (fenics2Sparse(a1Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a1Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
-
diff --git a/rrompy/hfengines/linear_problem/helmholtz_square_bubble_domain_problem_engine.py b/rrompy/hfengines/linear_problem/helmholtz_square_bubble_domain_problem_engine.py
index a455d2b..a0c2441 100644
--- a/rrompy/hfengines/linear_problem/helmholtz_square_bubble_domain_problem_engine.py
+++ b/rrompy/hfengines/linear_problem/helmholtz_square_bubble_domain_problem_engine.py
@@ -1,160 +1,133 @@
# 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 numpy.polynomial.polynomial import polyfit as fit
import fenics as fen
-from rrompy.utilities.base.types import (Np1D, ScOp, Tuple, List, FenExpr,
- paramVal)
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenZERO
from .helmholtz_problem_engine import HelmholtzProblemEngine
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD, hashIdxToDerivative as hashI)
from rrompy.solver.fenics import fenics2Sparse, fenics2Vector
__all__ = ['HelmholtzSquareBubbleDomainProblemEngine']
class HelmholtzSquareBubbleDomainProblemEngine(HelmholtzProblemEngine):
"""
Solver for square bubble Helmholtz problems with parametric domain heigth.
- \Delta u - kappa^2 * u = f in \Omega_mu = [0,\pi] x [0,\mu\pi]
u = 0 on \Gamma_mu = \partial\Omega_mu
with exact solution square bubble times plane wave.
"""
def __init__(self, kappa:float, theta:float, n:int, mu0 : paramVal = [1.],
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.nAs, self.nbs = 3, 15
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = False
+ self.nAs, self.nbs = 2, 15
self.kappa = kappa
self.theta = theta
- self.forcingTermMu = np.nan
mesh = fen.RectangleMesh(fen.Point(0, 0), fen.Point(np.pi, np.pi),
3 * n, 3 * n)
self.V = fen.FunctionSpace(mesh, "P", 1)
self.rescalingExp = [1.]
- def getForcingTerm(self, mu : paramVal = []) -> Tuple[FenExpr, FenExpr]:
- """Compute forcing term."""
- vbMng(self, "INIT", ("Assembling base expression for forcing term "
- "at {}.").format(mu), 25)
- pi = np.pi
- c, s = np.cos(self.theta), np.sin(self.theta)
- x, y = fen.SpatialCoordinate(self.V.mesh())[:]
- muR, muI = np.real(mu), np.imag(mu)
- mu2R, mu2I = np.real(mu ** 2.), np.imag(mu ** 2.)
- C = 16. / pi ** 4.
- bR = C * (2 * (x * (pi - x) + y * (pi - y))
- + (self.kappa * s) ** 2. * (mu2R - 1.)
- * x * (pi - x) * y * (pi - y))
- bI = C * (2 * self.kappa * (c * (pi - 2 * x) * y * (pi - y)
- + s * x * (pi - x) * (pi - 2 * y))
- + (self.kappa * s) ** 2. * mu2I
- * x * (pi - x) * y * (pi - y))
- wR = (fen.cos(self.kappa * (c * x + s * muR * y))
- * fen.exp(self.kappa * s * muI * y))
- wI = (fen.sin(self.kappa * (c * x + s * muR * y))
- * fen.exp(self.kappa * s * muI * y))
- fRe, fIm = bR * wR + bI * wI, bI * wR - bR * wI
- forcingTerm = [mu2R * fRe - mu2I * fIm + fenZERO,
- mu2R * fIm + mu2I * fRe + fenZERO]
- vbMng(self, "DEL", "Done assembling base expression.", 25)
- return forcingTerm
-
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.As[0] is None:
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
a0Re = fen.dot(self.u.dx(1), self.v.dx(1)) * fen.dx
self.As[0] = fenics2Sparse(a0Re, {}, DirichletBC0, 1)
+ self.thAs[0] = self.getMonomialSingleWeight([0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
- self.As[1] = self.checkAInBounds(-1)
- if derI <= 2 and self.As[2] is None:
+ if self.As[1] is None:
vbMng(self, "INIT", "Assembling operator term A2.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
k2Re, k2Im = np.real(self.omega ** 2), np.imag(self.omega ** 2)
k2n2Re = k2Re * n2Re - k2Im * n2Im
k2n2Im = k2Re * n2Im + k2Im * n2Re
parsRe = self.iterReduceQuadratureDegree(zip([k2n2Re],
["kappaSquaredRefractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([k2n2Im],
["kappaSquaredRefractionIndexSquaredImag"]))
a2Re = (fen.dot(self.u.dx(0), self.v.dx(0))
- k2n2Re * fen.dot(self.u, self.v)) * fen.dx
a2Im = - k2n2Im * fen.dot(self.u, self.v) * fen.dx
- self.As[2] = (fenics2Sparse(a2Re, parsRe, DirichletBC0, 0)
+ self.As[1] = (fenics2Sparse(a2Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a2Im, parsIm, DirichletBC0, 0))
+ self.thAs[1] = self.getMonomialSingleWeight([2])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
- def b(self, mu : paramVal = [], der : List[int] = 0,
- homogeneized : bool = False) -> Np1D:
- """Assemble (derivative of) RHS of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- nbsTot = self.nbsH if homogeneized else self.nbs
- bs = self.bsH if homogeneized else self.bs
- if homogeneized and self.mu0 != self.mu0BC:
- self.liftDirichletData(self.mu0)
+ def buildb(self):
+ """Build terms of operator of linear system."""
+ if self.thbs[0] is None:
+ self.thbs = (self.getMonomialWeights(self.nbs)
+ + [None] * (self.homogeneized * self.nAs))
bDEIMCoeffs = None
- for j in range(derI, nbsTot):
- if bs[j] is None:
+ for j in range(self.nbs):
+ if self.bs[j] is None:
vbMng(self, "INIT", "Assembling forcing term b{}.".format(j),
20)
if bDEIMCoeffs is None:
bDEIM = np.empty((self.nbs, self.spacedim()),
dtype = np.complex)
muDEIM = np.linspace(.5, 4., self.nbs)
for jj, muD in enumerate(muDEIM):
- fRe, fIm = self.getForcingTerm(muD)
+ pi = np.pi
+ c, s = np.cos(self.theta), np.sin(self.theta)
+ x, y = fen.SpatialCoordinate(self.V.mesh())[:]
+ muR, muI = np.real(muD), np.imag(muD)
+ mu2R, mu2I = np.real(muD ** 2.), np.imag(muD ** 2.)
+ C = 16. / pi ** 4.
+ bR = C * (2 * (x * (pi - x) + y * (pi - y))
+ + (self.kappa * s) ** 2. * (mu2R - 1.)
+ * x * (pi - x) * y * (pi - y))
+ bI = C * (2 * self.kappa * (c * (pi - 2 * x) * y
+ * (pi - y) + s * x * (pi - x)
+ * (pi - 2 * y))
+ + (self.kappa * s) ** 2. * mu2I
+ * x * (pi - x) * y * (pi - y))
+ wR = (fen.cos(self.kappa * (c * x + s * muR * y))
+ * fen.exp(self.kappa * s * muI * y))
+ wI = (fen.sin(self.kappa * (c * x + s * muR * y))
+ * fen.exp(self.kappa * s * muI * y))
+ fRe, fIm = bR * wR + bI * wI, bI * wR - bR * wI
+ fRe = mu2R * fRe - mu2I * fIm + fenZERO
+ fIm = mu2R * fIm + mu2I * fRe + fenZERO
parsRe = self.iterReduceQuadratureDegree(zip([fRe],
["forcingTerm{}Real".format(jj)]))
parsIm = self.iterReduceQuadratureDegree(zip([fIm],
["forcingTerm{}Imag".format(jj)]))
LR = fen.dot(fRe, self.v) * fen.dx
LI = fen.dot(fIm, self.v) * fen.dx
DBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
bDEIM[jj] = (fenics2Vector(LR, parsRe, DBC0, 1)
+ 1.j * fenics2Vector(LI, parsIm, DBC0, 1))
bDEIMCoeffs = fit(muDEIM, bDEIM, self.nbs - 1)
- b = bDEIMCoeffs[j]
- if homogeneized:
- Ader = self.A(0, hashI(j, self.npar))
- b -= Ader.dot(self.liftedDirichletDatum)
- if homogeneized:
- self.bsH[j] = b
- else:
- self.bs[j] = b
+ self.bs[j] = bDEIMCoeffs[j]
vbMng(self, "DEL", "Done assembling forcing term.", 20)
- return self._assembleb(mu, der, derI, homogeneized)
-
+ self.setbHomogeneized()
diff --git a/rrompy/hfengines/linear_problem/helmholtz_square_bubble_problem_engine.py b/rrompy/hfengines/linear_problem/helmholtz_square_bubble_problem_engine.py
index 59b81c1..35df096 100644
--- a/rrompy/hfengines/linear_problem/helmholtz_square_bubble_problem_engine.py
+++ b/rrompy/hfengines/linear_problem/helmholtz_square_bubble_problem_engine.py
@@ -1,53 +1,52 @@
# 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
import fenics as fen
from .helmholtz_problem_engine import HelmholtzProblemEngine
__all__ = ['HelmholtzSquareBubbleProblemEngine']
class HelmholtzSquareBubbleProblemEngine(HelmholtzProblemEngine):
"""
Solver for square bubble Helmholtz problems with parametric wavenumber.
- \Delta u - omega^2 * u = f in \Omega
u = 0 on \Gamma_D
with exact solution square bubble times plane wave.
"""
def __init__(self, kappa:float, theta:float, n:int,
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = [kappa], degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
-
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
pi = np.pi
mesh = fen.RectangleMesh(fen.Point(0, 0), fen.Point(pi, pi),
3 * n, 3 * n)
self.V = fen.FunctionSpace(mesh, "P", 1)
c, s = np.cos(theta), np.sin(theta)
x, y = fen.SpatialCoordinate(mesh)[:]
C = 16. / pi ** 4.
bR = C * 2 * (x * (pi - x) + y * (pi - y))
bI = C * 2 * kappa * (c * (pi - 2 * x) * y * (pi - y)
+ s * x * (pi - x) * (pi - 2 * y))
wR = fen.cos(kappa * (c * x + s * y))
wI = fen.sin(kappa * (c * x + s * y))
self.forcingTerm = [bR * wR + bI * wI, bI * wR - bR * wI]
-
diff --git a/rrompy/hfengines/linear_problem/helmholtz_square_transmission_problem_engine.py b/rrompy/hfengines/linear_problem/helmholtz_square_transmission_problem_engine.py
index 5726350..6ea8c5d 100644
--- a/rrompy/hfengines/linear_problem/helmholtz_square_transmission_problem_engine.py
+++ b/rrompy/hfengines/linear_problem/helmholtz_square_transmission_problem_engine.py
@@ -1,74 +1,73 @@
# 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
import fenics as fen
import ufl
from .helmholtz_problem_engine import HelmholtzProblemEngine
__all__ = ['HelmholtzSquareTransmissionProblemEngine']
class HelmholtzSquareTransmissionProblemEngine(HelmholtzProblemEngine):
"""
Solver for square transmission Helmholtz problems with parametric
wavenumber.
- \Delta u - omega^2 * n^2 * u = 0 in \Omega
u = 0 on \Gamma_D
with exact solution a transmitted plane wave.
"""
def __init__(self, nT:float, nB:float, kappa:float, theta:float, n:int,
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = [kappa], degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
-
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
mesh = fen.RectangleMesh(fen.Point(-np.pi/2, -np.pi/2),
fen.Point(np.pi/2, np.pi/2), 3 * n, 3 * n)
self.V = fen.FunctionSpace(mesh, "P", 1)
dx, dy = np.cos(theta), np.sin(theta)
Kx = kappa * nB * dx
Ky = kappa * (nT**2. - (nB * dx)**2. + 0.j)**.5
T = 2 * kappa * nB * dy / (Ky + kappa * nB * dy)
x, y = fen.SpatialCoordinate(mesh)[:]
TR, TI = np.real(T), np.imag(T)
if np.isclose(np.imag(Ky), 0.):
u0RT = (TR * fen.cos(Kx * x + np.real(Ky) * y)
- TI * fen.sin(Kx * x + np.real(Ky) * y))
u0IT = (TR * fen.sin(Kx * x + np.real(Ky) * y)
+ TI * fen.cos(Kx * x + np.real(Ky) * y))
else:
u0RT = fen.exp(- np.imag(Ky) * y) * (TR * fen.cos(Kx * x)
- TI * fen.sin(Kx * x))
u0IT = fen.exp(- np.imag(Ky) * y) * (TR * fen.sin(Kx * x)
+ TI * fen.cos(Kx * x))
u0RB = (fen.cos(kappa * nB * (dx * x + dy * y))
+ (TR - 1) * fen.cos(kappa * nB * (dx*x - dy*y))
- TI * fen.sin(kappa * nB * (dx*x - dy*y)))
u0IB = (fen.sin(kappa * nB * (dx * x + dy * y))
+ (TR - 1) * fen.sin(kappa * nB * (dx*x - dy*y))
+ TI * fen.cos(kappa * nB * (dx*x - dy*y)))
u0R = ufl.conditional(ufl.ge(y, 0.), u0RT, u0RB)
u0I = ufl.conditional(ufl.ge(y, 0.), u0IT, u0IB)
self.refractionIndex = ufl.conditional(ufl.ge(y, 0.),
fen.Constant(nT),
fen.Constant(nB))
self.DirichletDatum = [u0R, u0I]
-
diff --git a/rrompy/hfengines/linear_problem/laplace_base_problem_engine.py b/rrompy/hfengines/linear_problem/laplace_base_problem_engine.py
index 8899593..48f8a21 100644
--- a/rrompy/hfengines/linear_problem/laplace_base_problem_engine.py
+++ b/rrompy/hfengines/linear_problem/laplace_base_problem_engine.py
@@ -1,337 +1,289 @@
# 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
import fenics as fen
from rrompy.hfengines.base.problem_engine_base import ProblemEngineBase
-from rrompy.utilities.base.types import Np1D, List, ScOp, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import (fenZERO, fenONE, L2InverseNormMatrix,
H1NormMatrix, Hminus1NormMatrix)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD, hashIdxToDerivative as hashI)
from rrompy.parameter import checkParameter
from rrompy.solver.fenics import fenics2Sparse, fenics2Vector
__all__ = ['LaplaceBaseProblemEngine']
class LaplaceBaseProblemEngine(ProblemEngineBase):
"""
Solver for generic Laplace problems.
- \nabla \cdot (a \nabla u) = f in \Omega
u = u0 on \Gamma_D
\partial_nu = g1 on \Gamma_N
\partial_nu + h u = g2 on \Gamma_R
Attributes:
+ homogeneized: Whether to homogeneize Dirichlet BCs.
verbosity: Verbosity level.
BCManager: Boundary condition manager.
V: Real FE space.
u: Generic trial functions for variational form evaluation.
v: Generic test functions for variational form evaluation.
As: Scipy sparse array representation (in CSC format) of As.
bs: Numpy array representation of bs.
- bsH: Numpy array representation of homogeneized bs.
energyNormMatrix: Scipy sparse matrix representing inner product over
V.
energyNormDualMatrix: Scipy sparse matrix representing inner product
over V'.
dualityMatrix: Scipy sparse matrix representing duality V-V'.
energyNormPartialDualMatrix: Scipy sparse matrix representing dual
inner product between Riesz representers V-V.
- liftedDirichletDatum: Dofs of Dirichlet datum lifting.
- mu0BC: Mu value of last Dirichlet datum lifting.
degree_threshold: Threshold for ufl expression interpolation degree.
omega: Value of omega.
diffusivity: Value of a.
forcingTerm: Value of f.
DirichletDatum: Value of u0.
NeumannDatum: Value of g1.
RobinDatumG: Value of g2.
RobinDatumH: Value of h.
DirichletBoundary: Function handle to \Gamma_D.
NeumannBoundary: Function handle to \Gamma_N.
RobinBoundary: Function handle to \Gamma_R.
ds: Boundary measure 2-tuple (resp. for Neumann and Robin boundaries).
A0: Scipy sparse array representation (in CSC format) of A0.
b0: Numpy array representation of b0.
dsToBeSet: Whether ds needs to be set.
"""
_energyDualNormCompress = None
def __init__(self, mu0 : paramVal = [], degree_threshold : int = np.inf,
- verbosity : int = 10, timestamp : bool = True):
+ homogeneized : bool = False, verbosity : int = 10,
+ timestamp : bool = True):
super().__init__(degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = True
self.mu0 = checkParameter(mu0)
self.npar = self.mu0.shape[1]
self.omega = np.abs(self.mu0(0, 0)) if self.npar > 0 else 0.
self.diffusivity = fenONE
self.forcingTerm = fenZERO
self.DirichletDatum = fenZERO
self.NeumannDatum = fenZERO
self.RobinDatumG = fenZERO
self.RobinDatumH = fenZERO
@property
def V(self):
"""Value of V."""
return self._V
@V.setter
def V(self, V):
ProblemEngineBase.V.fset(self, V)
self.dsToBeSet = True
@property
def diffusivity(self):
"""Value of a."""
return self._diffusivity
@diffusivity.setter
def diffusivity(self, diffusivity):
self.resetAs()
if not isinstance(diffusivity, (list, tuple,)):
diffusivity = [diffusivity, fenZERO]
self._diffusivity = diffusivity
@property
def forcingTerm(self):
"""Value of f."""
return self._forcingTerm
@forcingTerm.setter
def forcingTerm(self, forcingTerm):
self.resetbs()
if not isinstance(forcingTerm, (list, tuple,)):
forcingTerm = [forcingTerm, fenZERO]
self._forcingTerm = forcingTerm
@property
def DirichletDatum(self):
"""Value of u0."""
return self._DirichletDatum
@DirichletDatum.setter
def DirichletDatum(self, DirichletDatum):
self.resetbs()
if not isinstance(DirichletDatum, (list, tuple,)):
DirichletDatum = [DirichletDatum, fenZERO]
self._DirichletDatum = DirichletDatum
@property
def NeumannDatum(self):
"""Value of g1."""
return self._NeumannDatum
@NeumannDatum.setter
def NeumannDatum(self, NeumannDatum):
self.resetbs()
if not isinstance(NeumannDatum, (list, tuple,)):
NeumannDatum = [NeumannDatum, fenZERO]
self._NeumannDatum = NeumannDatum
@property
def RobinDatumG(self):
"""Value of g2."""
return self._RobinDatumG
@RobinDatumG.setter
def RobinDatumG(self, RobinDatumG):
self.resetbs()
if not isinstance(RobinDatumG, (list, tuple,)):
RobinDatumG = [RobinDatumG, fenZERO]
self._RobinDatumG = RobinDatumG
@property
def RobinDatumH(self):
"""Value of h."""
return self._RobinDatumH
@RobinDatumH.setter
def RobinDatumH(self, RobinDatumH):
self.resetAs()
if not isinstance(RobinDatumH, (list, tuple,)):
RobinDatumH = [RobinDatumH, fenZERO]
self._RobinDatumH = RobinDatumH
@property
def DirichletBoundary(self):
"""Function handle to DirichletBoundary."""
return self.BCManager.DirichletBoundary
@DirichletBoundary.setter
def DirichletBoundary(self, DirichletBoundary):
self.resetAs()
self.resetbs()
self.BCManager.DirichletBoundary = DirichletBoundary
@property
def NeumannBoundary(self):
"""Function handle to NeumannBoundary."""
return self.BCManager.NeumannBoundary
@NeumannBoundary.setter
def NeumannBoundary(self, NeumannBoundary):
self.resetAs()
self.resetbs()
self.dsToBeSet = True
self.BCManager.NeumannBoundary = NeumannBoundary
@property
def RobinBoundary(self):
"""Function handle to RobinBoundary."""
return self.BCManager.RobinBoundary
@RobinBoundary.setter
def RobinBoundary(self, RobinBoundary):
self.resetAs()
self.resetbs()
self.dsToBeSet = True
self.BCManager.RobinBoundary = RobinBoundary
- def autoSetDS(self):
- """Set FEniCS boundary measure based on boundary function handles."""
- if self.dsToBeSet:
- vbMng(self, "INIT", "Initializing boundary measures.", 20)
- mesh = self.V.mesh()
- NB = self.NeumannBoundary
- RB = self.RobinBoundary
- boundary_markers = fen.MeshFunction("size_t", mesh,
- mesh.topology().dim() - 1)
- NB.mark(boundary_markers, 0)
- RB.mark(boundary_markers, 1)
- self.ds = fen.Measure("ds", domain = mesh,
- subdomain_data = boundary_markers)
- self.dsToBeSet = False
- vbMng(self, "DEL", "Done assembling boundary measures.", 20)
-
def buildEnergyNormForm(self):
"""
Build sparse matrix (in CSR format) representative of scalar product.
"""
vbMng(self, "INIT", "Assembling energy matrix.", 20)
self.energyNormMatrix = H1NormMatrix(self.V, np.abs(self.omega)**2)
vbMng(self, "DEL", "Done assembling energy matrix.", 20)
def buildEnergyNormDualForm(self):
"""
Build sparse matrix (in CSR format) representative of dual scalar
product.
"""
vbMng(self, "INIT", "Assembling energy dual matrix.", 20)
self.energyNormDualMatrix = Hminus1NormMatrix(
self.V, np.abs(self.omega)**2,
compressRank = self._energyDualNormCompress)
vbMng(self, "DEL", "Done assembling energy dual matrix.", 20)
def buildDualityPairingForm(self):
"""Build sparse matrix (in CSR format) representative of duality."""
vbMng(self, "INIT", "Assembling duality matrix.", 20)
self.dualityMatrix = L2InverseNormMatrix(
self.V, solverType = self._solver,
solverArgs = self._solverArgs,
compressRank = self._dualityCompress)
vbMng(self, "DEL", "Done assembling duality matrix.", 20)
def buildEnergyNormPartialDualForm(self):
"""
Build sparse matrix (in CSR format) representative of dual scalar
product without duality.
"""
vbMng(self, "INIT", "Assembling energy partial dual matrix.", 20)
self.energyNormPartialDualMatrix = Hminus1NormMatrix(
self.V, np.abs(self.omega)**2,
compressRank = self._energyDualNormCompress,
duality = False)
vbMng(self, "DEL", "Done assembling energy partial dual matrix.", 20)
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.thAs[0] is None: self.thAs = self.getMonomialWeights(self.nAs)
+ if self.As[0] is None:
self.autoSetDS()
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
aRe, aIm = self.diffusivity
hRe, hIm = self.RobinDatumH
termNames = ["diffusivity", "RobinDatumH"]
parsRe = self.iterReduceQuadratureDegree(zip([aRe, hRe],
[x + "Real" for x in termNames]))
parsIm = self.iterReduceQuadratureDegree(zip([aIm, hIm],
[x + "Imag" for x in termNames]))
a0Re = (aRe * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
+ hRe * fen.dot(self.u, self.v) * self.ds(1))
a0Im = (aIm * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
+ hIm * fen.dot(self.u, self.v) * self.ds(1))
self.As[0] = (fenics2Sparse(a0Re, parsRe, DirichletBC0, 1)
+ 1.j * fenics2Sparse(a0Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
- def b(self, mu : paramVal = [], der : List[int] = 0,
- homogeneized : bool = False) -> Np1D:
- """Assemble (derivative of) RHS of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- nbsTot = self.nbsH if homogeneized else self.nbs
- bs = self.bsH if homogeneized else self.bs
- if homogeneized and self.mu0 != self.mu0BC:
- self.liftDirichletData(self.mu0)
- for j in range(derI, nbsTot):
- if bs[j] is None:
- self.autoSetDS()
- vbMng(self, "INIT", "Assembling forcing term b{}.".format(j),
- 20)
- termNames, terms = [], []
- if j == 0:
- u0Re, u0Im = self.DirichletDatum
- fRe, fIm = self.forcingTerm
- g1Re, g1Im = self.NeumannDatum
- g2Re, g2Im = self.RobinDatumG
- termNames += ["forcingTerm", "NeumannDatum", "RobinDatumG"]
- terms += [[fRe, fIm], [g1Re, g1Im], [g2Re, g2Im]]
- else:
- u0Re, u0Im = fenZERO, fenZERO
- fRe, fIm = fenZERO, fenZERO
- g1Re, g1Im = fenZERO, fenZERO
- g2Re, g2Im = fenZERO, fenZERO
- if len(termNames) > 0:
- parsRe = self.iterReduceQuadratureDegree(zip(
- [term[0] for term in terms],
+ def buildb(self):
+ """Build terms of operator of linear system."""
+ if self.thbs[0] is None:
+ self.thbs = (self.getMonomialWeights(self.nbs)
+ + [None] * (self.homogeneized * self.nAs))
+ if self.bs[0] is None:
+ self.autoSetDS()
+ vbMng(self, "INIT", "Assembling forcing term b0.", 20)
+ u0Re, u0Im = self.DirichletDatum
+ fRe, fIm = self.forcingTerm
+ g1Re, g1Im = self.NeumannDatum
+ g2Re, g2Im = self.RobinDatumG
+ termNames = ["forcingTerm", "NeumannDatum", "RobinDatumG"]
+ parsRe = self.iterReduceQuadratureDegree(zip([fRe, g1Re, g2Re],
[x + "Real" for x in termNames]))
- parsIm = self.iterReduceQuadratureDegree(zip(
- [term[1] for term in terms],
+ parsIm = self.iterReduceQuadratureDegree(zip([fIm, g1Im, g2Im],
[x + "Imag" for x in termNames]))
- else:
- parsRe, parsIm = {}, {}
- L0Re = (fen.dot(fRe, self.v) * fen.dx
- + fen.dot(g1Re, self.v) * self.ds(0)
- + fen.dot(g2Re, self.v) * self.ds(1))
- L0Im = (fen.dot(fIm, self.v) * fen.dx
- + fen.dot(g1Im, self.v) * self.ds(0)
- + fen.dot(g2Im, self.v) * self.ds(1))
- DBCR = fen.DirichletBC(self.V, u0Re, self.DirichletBoundary)
- DBCI = fen.DirichletBC(self.V, u0Im, self.DirichletBoundary)
- b = (fenics2Vector(L0Re, parsRe, DBCR, 1)
- + 1.j * fenics2Vector(L0Im, parsIm, DBCI, 1))
- if homogeneized:
- Ader = self.A(0, hashI(j, self.npar))
- b -= Ader.dot(self.liftedDirichletDatum)
- if homogeneized:
- self.bsH[j] = b
- else:
- self.bs[j] = b
- vbMng(self, "DEL", "Done assembling forcing term.", 20)
- return self._assembleb(mu, der, derI, homogeneized)
-
+ L0Re = (fen.dot(fRe, self.v) * fen.dx
+ + fen.dot(g1Re, self.v) * self.ds(0)
+ + fen.dot(g2Re, self.v) * self.ds(1))
+ L0Im = (fen.dot(fIm, self.v) * fen.dx
+ + fen.dot(g1Im, self.v) * self.ds(0)
+ + fen.dot(g2Im, self.v) * self.ds(1))
+ DBCR = fen.DirichletBC(self.V, u0Re, self.DirichletBoundary)
+ DBCI = fen.DirichletBC(self.V, u0Im, self.DirichletBoundary)
+ self.bs[0] = (fenics2Vector(L0Re, parsRe, DBCR, 1)
+ + 1.j * fenics2Vector(L0Im, parsIm, DBCI, 1))
+ vbMng(self, "DEL", "Done assembling forcing term.", 20)
+ self.setbHomogeneized()
diff --git a/rrompy/hfengines/linear_problem/laplace_disk_gaussian.py b/rrompy/hfengines/linear_problem/laplace_disk_gaussian.py
index 5980548..1cd6410 100644
--- a/rrompy/hfengines/linear_problem/laplace_disk_gaussian.py
+++ b/rrompy/hfengines/linear_problem/laplace_disk_gaussian.py
@@ -1,112 +1,88 @@
# 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 numpy.polynomial.polynomial import polyfit as fit
import fenics as fen
-from rrompy.utilities.base.types import Np1D, Tuple, FenExpr, paramVal
+from rrompy.utilities.base.types import paramVal
from .laplace_base_problem_engine import LaplaceBaseProblemEngine
-from rrompy.solver.fenics import fenZERO, fenONE
+from rrompy.solver.fenics import fenZERO
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD, hashIdxToDerivative as hashI)
from rrompy.solver.fenics import fenics2Vector
__all__ = ['LaplaceDiskGaussian']
class LaplaceDiskGaussian(LaplaceBaseProblemEngine):
"""
Solver for disk Laplace problems with parametric forcing term center.
- \Delta u = C exp(-.5 * ||\cdot - (mu, 0)||^2) in \Omega = B(0, 5)
u = 0 on \partial\Omega.
"""
def __init__(self, n:int, mu0 : paramVal = [0.],
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.nbs = 19
- self.forcingTermMu = np.nan
-
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self.nbs = 19
import mshr
mesh = mshr.generate_mesh(mshr.Circle(fen.Point(0., 0.), 5.), 3 * n)
self.V = fen.FunctionSpace(mesh, "P", 1)
- def getForcingTerm(self, mu : paramVal = []) -> Tuple[FenExpr, FenExpr]:
- """Compute forcing term."""
- mu = self.checkParameter(mu)
- vbMng(self, "INIT", ("Assembling base expression for forcing term "
- "at {}.").format(mu), 25)
- x, y = fen.SpatialCoordinate(self.V.mesh())[:]
- C = np.exp(-.5 * mu(0, 0) ** 2.)
- CR, CI = np.real(C), np.imag(C)
- f0 = (2 * np.pi) ** -.5 * fen.exp(-.5 * (x ** 2. + y ** 2.))
- muR, muI = np.real(mu(0, 0)), np.imag(mu(0, 0))
- f1R = fen.exp(muR * x) * fen.cos(muI * x)
- f1I = fen.exp(muR * x) * fen.sin(muI * x)
- forcingTerm = [f0 * (CR * f1R - CI * f1I) + fenZERO,
- f0 * (CR * f1I + CI * f1R) + fenZERO]
- vbMng(self, "DEL", "Done assembling base expression.", 25)
- return forcingTerm
-
- def b(self, mu : paramVal = [], der : int = 0,
- homogeneized : bool = False) -> Np1D:
- """Assemble (derivative of) RHS of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- nbsTot = self.nbsH if homogeneized else self.nbs
- bs = self.bsH if homogeneized else self.bs
- if homogeneized and self.mu0 != self.mu0BC:
- self.liftDirichletData(self.mu0)
+ def buildb(self):
+ """Build terms of operator of linear system."""
+ if self.thbs[0] is None:
+ self.thbs = (self.getMonomialWeights(self.nbs)
+ + [None] * (self.homogeneized * self.nAs))
bDEIMCoeffs = None
- for j in range(derI, nbsTot):
- if bs[j] is None:
+ for j in range(self.nbs):
+ if self.bs[j] is None:
vbMng(self, "INIT", "Assembling forcing term b{}.".format(j),
20)
if bDEIMCoeffs is None:
bDEIM = np.empty((self.nbs, self.spacedim()),
dtype = np.complex)
muDEIM = 3. * np.linspace(0., 1., self.nbs // 2 + 1) ** 2.
muDEIM = np.concatenate((-muDEIM[:0:-1], muDEIM))
for jj, muD in enumerate(muDEIM):
- fRe, fIm = self.getForcingTerm(muD)
+ x, y = fen.SpatialCoordinate(self.V.mesh())[:]
+ C = np.exp(-.5 * muD ** 2.)
+ CR, CI = np.real(C), np.imag(C)
+ f0 = ((2 * np.pi) ** -.5
+ * fen.exp(-.5 * (x ** 2. + y ** 2.)))
+ muR, muI = np.real(muD), np.imag(muD)
+ f1R = fen.exp(muR * x) * fen.cos(muI * x)
+ f1I = fen.exp(muR * x) * fen.sin(muI * x)
+ fRe = f0 * (CR * f1R - CI * f1I) + fenZERO
+ fIm = f0 * (CR * f1I + CI * f1R) + fenZERO
parsRe = self.iterReduceQuadratureDegree(zip([fRe],
["forcingTerm{}Real".format(jj)]))
parsIm = self.iterReduceQuadratureDegree(zip([fIm],
["forcingTerm{}Imag".format(jj)]))
LR = fen.dot(fRe, self.v) * fen.dx
LI = fen.dot(fIm, self.v) * fen.dx
DBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
bDEIM[jj] = (fenics2Vector(LR, parsRe, DBC0, 1)
+ 1.j * fenics2Vector(LI, parsIm, DBC0, 1))
bDEIMCoeffs = (fit(muDEIM / 3., bDEIM, self.nbs - 1).T
* np.power(3., - np.arange(self.nbs))).T
- b = bDEIMCoeffs[j]
- if homogeneized:
- Ader = self.A(0, hashI(j, self.npar))
- b -= Ader.dot(self.liftedDirichletDatum)
- if homogeneized:
- self.bsH[j] = b
- else:
- self.bs[j] = b
+ self.bs[j] = bDEIMCoeffs[j]
vbMng(self, "DEL", "Done assembling forcing term.", 20)
- return self._assembleb(mu, der, derI, homogeneized)
-
+ self.setbHomogeneized()
diff --git a/rrompy/hfengines/linear_problem/membrane_fracture_engine_nodomain.py b/rrompy/hfengines/linear_problem/membrane_fracture_engine_nodomain.py
index 90bcde2..60cd7ea 100644
--- a/rrompy/hfengines/linear_problem/membrane_fracture_engine_nodomain.py
+++ b/rrompy/hfengines/linear_problem/membrane_fracture_engine_nodomain.py
@@ -1,96 +1,92 @@
# 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
import fenics as fen
import mshr, ufl
-from rrompy.utilities.base.types import ScOp, List, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenZERO, fenONE
from rrompy.hfengines.linear_problem.helmholtz_problem_engine import (
HelmholtzProblemEngine)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['MembraneFractureEngineNoDomain']
class MembraneFractureEngineNoDomain(HelmholtzProblemEngine):
def __init__(self, mu0 : paramVal = [20. ** .5, .6], H : float = 1.,
L : float = .75, delta : float = .05, n : int = 50,
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = mu0[0], degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = True
self.npar = 1
self.lFrac = mu0[1]
self.H = H
self.rescalingExp = [2.]
domain = (mshr.Rectangle(fen.Point(0., - H / 2.),
fen.Point(2. * L + delta, H / 2.))
- mshr.Rectangle(fen.Point(L, 0.),
fen.Point(L + delta, H / 2.)))
mesh = mshr.generate_mesh(domain, n)
self.V = fen.FunctionSpace(mesh, "P", 1)
self.NeumannBoundary = lambda x, on_b: (on_b and x[1] >= - H / 4.
and x[0] >= L
and x[0] <= L + delta)
self.DirichletBoundary = "REST"
x, y = fen.SpatialCoordinate(mesh)[:]
self._belowIndicator = ufl.conditional(ufl.le(y, 0.), fenONE, fenZERO)
self._aboveIndicator = fenONE - self._belowIndicator
self.DirichletDatum = [fen.exp(- 10. * (H / 2. + y) / H
- .5 * ((x - .6 * L) / (.1 * L)) ** 2.
) * self._belowIndicator, fenZERO]
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.thAs[0] is None: self.thAs = self.getMonomialWeights(self.nAs)
+ if self.As[0] is None:
self.autoSetDS()
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
a0Re = (fen.dot(self.u.dx(0), self.v.dx(0))
+ self.H ** 4 / 4. * (self.lFrac ** -2. * self._aboveIndicator
+ (self.H - self.lFrac) ** -2. * self._belowIndicator)
* fen.dot(self.u.dx(1), self.v.dx(1))
) * fen.dx
self.As[0] = fenics2Sparse(a0Re, {}, DirichletBC0, 1)
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
+ if self.As[1] is None:
vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
["refractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
["refractionIndexSquaredImag"]))
a1Re = - n2Re * fen.dot(self.u, self.v) * fen.dx
a1Im = - n2Im * fen.dot(self.u, self.v) * fen.dx
self.As[1] = (fenics2Sparse(a1Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a1Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
-
diff --git a/rrompy/hfengines/linear_problem/scattering_problem_engine.py b/rrompy/hfengines/linear_problem/scattering_problem_engine.py
index 38e52e2..57c98ff 100644
--- a/rrompy/hfengines/linear_problem/scattering_problem_engine.py
+++ b/rrompy/hfengines/linear_problem/scattering_problem_engine.py
@@ -1,151 +1,146 @@
# 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 numpy import inf
import fenics as fen
-from rrompy.utilities.base.types import List, ScOp, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenZERO
from rrompy.utilities.base import verbosityManager as vbMng
from .helmholtz_problem_engine import HelmholtzProblemEngine
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.utilities.exception_manager import RROMPyWarning
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['ScatteringProblemEngine']
class ScatteringProblemEngine(HelmholtzProblemEngine):
"""
Solver for scattering problems with parametric wavenumber.
- \nabla \cdot (a \nabla u) - omega^2 * n**2 * u = f in \Omega
u = u0 on \Gamma_D
\partial_nu = g1 on \Gamma_N
\partial_nu +- i omega u = g2 on \Gamma_R
Attributes:
+ homogeneized: Whether to homogeneize Dirichlet BCs.
verbosity: Verbosity level.
BCManager: Boundary condition manager.
V: Real FE space.
u: Generic trial functions for variational form evaluation.
v: Generic test functions for variational form evaluation.
As: Scipy sparse array representation (in CSC format) of As.
bs: Numpy array representation of bs.
- bsH: Numpy array representation of homogeneized bs.
energyNormMatrix: Scipy sparse matrix representing inner product over
V.
energyNormDualMatrix: Scipy sparse matrix representing inner product
over V'.
dualityMatrix: Scipy sparse matrix representing duality V-V'.
energyNormPartialDualMatrix: Scipy sparse matrix representing dual
inner product between Riesz representers V-V.
- liftedDirichletDatum: Dofs of Dirichlet datum lifting.
- mu0BC: Mu value of last Dirichlet datum lifting.
degree_threshold: Threshold for ufl expression interpolation degree.
signR: Sign in ABC.
omega: Value of omega.
diffusivity: Value of a.
forcingTerm: Value of f.
DirichletDatum: Value of u0.
NeumannDatum: Value of g1.
RobinDatumG: Value of g2.
DirichletBoundary: Function handle to \Gamma_D.
NeumannBoundary: Function handle to \Gamma_N.
RobinBoundary: Function handle to \Gamma_R.
ds: Boundary measure 2-tuple (resp. for Neumann and Robin boundaries).
A0: Scipy sparse array representation (in CSC format) of A0.
A1: Scipy sparse array representation (in CSC format) of A1.
A2: Scipy sparse array representation (in CSC format) of A2.
b0: Numpy array representation of b0.
dsToBeSet: Whether ds needs to be set.
"""
def __init__(self, mu0 : paramVal = [0.], degree_threshold : int = inf,
- verbosity : int = 10, timestamp : bool = True):
+ homogeneized : bool = False, verbosity : int = 10,
+ timestamp : bool = True):
self.silenceWarnings = True
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = True
del self.silenceWarnings
self.nAs = 3
self.rescalingExp = [1.]
self.signR = - 1.
@property
def RobinDatumH(self):
"""Value of h."""
return self.signR * self.omega
@RobinDatumH.setter
def RobinDatumH(self, RobinDatumH):
if not hasattr(self, "silenceWarnings"):
RROMPyWarning(("Scattering problems do not allow changes of h. "
"Ignoring assignment."))
return
@property
def signR(self):
"""Value of signR."""
return self._signR
@signR.setter
def signR(self, signR):
self.resetAs()
self._signR = signR
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.thAs[0] is None: self.thAs = self.getMonomialWeights(self.nAs)
+ if self.As[0] is None:
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
aRe, aIm = self.diffusivity
parsRe = self.iterReduceQuadratureDegree(zip([aRe],
["diffusivityReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([aIm],
["diffusivityImag"]))
a0Re = aRe * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
a0Im = aIm * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
self.As[0] = (fenics2Sparse(a0Re, parsRe, DirichletBC0, 1)
+ 1.j * fenics2Sparse(a0Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
+ if self.As[1] is None:
self.autoSetDS()
vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
a1 = fen.dot(self.u, self.v) * self.ds(1)
self.As[1] = (self.signR * 1.j
* fenics2Sparse(a1, {}, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 2 and self.As[2] is None:
+ if self.As[2] is None:
vbMng(self, "INIT", "Assembling operator term A2.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
nRe, nIm = self.refractionIndex
n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
["refractionIndexSquaredReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
["refractionIndexSquaredImag"]))
a2Re = - n2Re * fen.dot(self.u, self.v) * fen.dx
a2Im = - n2Im * fen.dot(self.u, self.v) * fen.dx
self.As[2] = (fenics2Sparse(a2Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a2Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
-
diff --git a/rrompy/hfengines/linear_problem/tridimensional/matrix_dynamical_passive.py b/rrompy/hfengines/linear_problem/tridimensional/matrix_dynamical_passive.py
index 02e840b..fcec560 100644
--- a/rrompy/hfengines/linear_problem/tridimensional/matrix_dynamical_passive.py
+++ b/rrompy/hfengines/linear_problem/tridimensional/matrix_dynamical_passive.py
@@ -1,61 +1,61 @@
# 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
import scipy.sparse as sp
from rrompy.utilities.base.types import ListAny, paramVal
from rrompy.hfengines.base.matrix_engine_base import MatrixEngineBase
from rrompy.parameter import checkParameter
__all__ = ['MatrixDynamicalPassive']
class MatrixDynamicalPassive(MatrixEngineBase):
def __init__(self, mu0 : paramVal = [0., 10.], n : int = 1000,
omega0 : ListAny = [1.], domega0 : ListAny = [1.],
b : float = 10., verbosity : int = 10,
timestamp : bool = True):
super().__init__(verbosity = verbosity, timestamp = timestamp)
-
+ self._affinePoly = True
self.npar = 1 + len(omega0)
self.mu0 = checkParameter(mu0, self.npar)
self.nAs, self.nbs = 1 + self.npar, 1
Asize = 2 + 2 * self.npar + n
dataA0 = np.concatenate((*tuple([tuple([np.imag(o), - np.real(o),
np.real(o), np.imag(o)]) \
for o in omega0]),
[1., -200., 200., 1., 1., -400., 400., 1.],
1. + np.arange(n)))
rowA0 = np.concatenate((np.repeat(np.arange(2 * len(omega0) + 4), 2),
2 + 2 * self.npar + np.arange(n)))
cB0 = np.repeat(np.arange(0, 2 * len(omega0) + 4, 2), 4)
cB1 = np.tile([0, 1], [1, 2 * len(omega0) + 4]).reshape(-1)
colA0 = np.concatenate((cB0 + cB1, 2 + 2 * self.npar + np.arange(n)))
- As = [sp.csr_matrix((dataA0, (rowA0, colA0)), dtype = np.complex,
+ self.As = [sp.csr_matrix((dataA0, (rowA0, colA0)), dtype = np.complex,
shape = (Asize, Asize))]
- As = As + [1.j * sp.eye(Asize, dtype = np.complex)]
+ self.As = self.As + [1.j * sp.eye(Asize, dtype = np.complex)]
for j, do0 in enumerate(domega0):
- As = As + [sp.csr_matrix(([- do0, do0],
- ([2*j, 2*j+1], [2*j+1, 2*j])),
- dtype = np.complex,
- shape = (Asize, Asize))]
- self.As = As
+ self.As = self.As + [sp.csr_matrix(([- do0, do0],
+ ([2*j, 2*j+1], [2*j+1, 2*j])),
+ dtype = np.complex,
+ shape = (Asize, Asize))]
self.bs = [np.concatenate((b * np.ones(2 + 2 * self.npar),
np.ones(n)))]
-
+ self.thAs = self.getMonomialWeights(self.nAs)
+ self.thbs = self.getMonomialWeights(self.nbs)
diff --git a/rrompy/hfengines/linear_problem/tridimensional/membrane_fracture_engine3.py b/rrompy/hfengines/linear_problem/tridimensional/membrane_fracture_engine3.py
index dea60df..1c3ca4a 100644
--- a/rrompy/hfengines/linear_problem/tridimensional/membrane_fracture_engine3.py
+++ b/rrompy/hfengines/linear_problem/tridimensional/membrane_fracture_engine3.py
@@ -1,331 +1,265 @@
# 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
import fenics as fen
import ufl
-from rrompy.utilities.base.types import ScOp, List, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenZERO, fenONE
from rrompy.hfengines.linear_problem.helmholtz_problem_engine import (
HelmholtzProblemEngine)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
+from rrompy.utilities.numerical import (nextDerivativeIndices,
+ hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['MembraneFractureEngine3']
def gen_mesh_fracture(W, delta, H, n):
n = 2 * (n // 2) + 1
xL = np.linspace(-.5 * W, - .5 * delta, n // 2 + 1)
xR = - xL[::-1]
nEff = int(np.ceil(delta / (xL[1] - xL[0])))
xC = np.linspace(-.5 * delta, .5 * delta, nEff + 1)[1:-1]
yA = np.linspace(-.5 * H, .5 * H, n)
yL = np.linspace(-.5 * H, 0., n // 2 + 1)
editor = fen.MeshEditor()
mesh = fen.Mesh()
editor.open(mesh, "triangle", 2, 2)
editor.init_vertices((2 * n + nEff - 1) * (n // 2 + 1))
editor.init_cells(2 * (2 * n - 2 + nEff) * (n // 2))
for j, y in enumerate(yA):
for i, x in enumerate(xL):
editor.add_vertex(i + j * (n // 2 + 1), np.array([x, y]))
for j in range(n - 1):
for i in range(n // 2):
editor.add_cell(2 * (i + j * (n // 2)),
np.array([i + j * (n // 2 + 1), i + 1 + j * (n // 2 + 1),
i + (j + 1) * (n // 2 + 1)], dtype=np.uintp))
editor.add_cell(2 * (i + j * (n // 2)) + 1,
np.array([i + 1 + j * (n // 2 + 1), i + 1 + (j + 1) * (n // 2 + 1),
i + (j + 1) * (n // 2 + 1)], dtype=np.uintp))
vBase1, cBase1 = n * (n // 2 + 1), 2 * (n - 1) * (n // 2)
for j, y in enumerate(yA):
for i, x in enumerate(xR):
editor.add_vertex(vBase1 + i + j * (n // 2 + 1), np.array([x, y]))
for j in range(n - 1):
for i in range(n // 2):
editor.add_cell(cBase1 + 2 * (i + j * (n // 2)),
np.array([vBase1 + i + j * (n // 2 + 1), vBase1 + i + 1 + j * (n // 2 + 1),
vBase1 + i + (j + 1) * (n // 2 + 1)], dtype=np.uintp))
editor.add_cell(cBase1 + 2 * (i + j * (n // 2)) + 1,
np.array([vBase1 + i + 1 + j * (n // 2 + 1),
vBase1 + i + 1 + (j + 1) * (n // 2 + 1),
vBase1 + i + (j + 1) * (n // 2 + 1)], dtype=np.uintp))
vBase2, cBase2 = 2 * n * (n // 2 + 1), 4 * (n - 1) * (n // 2)
for j, y in enumerate(yL):
for i, x in enumerate(xC):
editor.add_vertex(vBase2 + i + j * (nEff - 1), np.array([x, y]))
for j in range(n // 2):
for i in range(nEff - 2):
editor.add_cell(cBase2 + 2 * (i + j * (nEff - 2)),
np.array([vBase2 + i + j * (nEff - 1), vBase2 + i + 1 + j * (nEff - 1),
vBase2 + i + (j + 1) * (nEff - 1)], dtype=np.uintp))
editor.add_cell(cBase2 + 2 * (i + j * (nEff - 2)) + 1,
np.array([vBase2 + i + 1 + j * (nEff - 1),
vBase2 + i + 1 + (j + 1) * (nEff - 1),
vBase2 + i + (j + 1) * (nEff - 1)], dtype=np.uintp))
if nEff == 1:
for j in range(n // 2):
editor.add_cell(cBase2 + 2 * j,
np.array([(j + 1) * (n // 2 + 1) - 1, vBase1 + j * (n // 2 + 1),
(j + 2) * (n // 2 + 1) - 1], dtype=np.uintp))
editor.add_cell(cBase2 + 2 * j + 1,
np.array([vBase1 + j * (n // 2 + 1), vBase1 + (j + 1) * (n // 2 + 1),
(j + 2) * (n // 2 + 1) - 1], dtype=np.uintp))
else:
cBase3 = 2 * (2 * n + nEff - 4) * (n // 2)
for j in range(n // 2):
editor.add_cell(cBase3 + 2 * j,
np.array([(j + 1) * (n // 2 + 1) - 1, vBase2 + j * (nEff - 1),
(j + 2) * (n // 2 + 1) - 1], dtype=np.uintp))
editor.add_cell(cBase3 + 2 * j + 1,
np.array([vBase2 + j * (nEff - 1), vBase2 + (j + 1) * (nEff - 1),
(j + 2) * (n // 2 + 1) - 1], dtype=np.uintp))
cBase4 = 2 * (2 * n + nEff - 3) * (n // 2)
for j in range(n // 2):
editor.add_cell(cBase4 + 2 * j,
np.array([vBase2 + (j + 1) * (nEff - 1) - 1, vBase1 + j * (n // 2 + 1),
vBase2 + (j + 2) * (nEff - 1) - 1], dtype=np.uintp))
editor.add_cell(cBase4 + 2 * j + 1,
np.array([vBase1 + j * (n // 2 + 1), vBase1 + (j + 1) * (n // 2 + 1),
vBase2 + (j + 2) * (nEff - 1) - 1], dtype=np.uintp))
editor.close()
return mesh
class MembraneFractureEngine3(HelmholtzProblemEngine):
def __init__(self, mu0 : paramVal = [20. ** .5, .6, .08], H : float = 1.,
L : float = .75, delta : float = .05, n : int = 50,
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.nAs = 206
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = False
+ self.nAs = 6
self.npar = 3
self._H = H
self._delta = delta
self._L = L
self._W = 2 * L + delta
self.rescalingExp = [2., 1., 1.]
mesh = gen_mesh_fracture(self._W, delta, H, n)
self.V = fen.FunctionSpace(mesh, "P", 1)
self.NeumannBoundary = lambda x, on_b: (on_b and x[1] >= - H / 4.
and x[0] >= - .5 * delta and x[0] <= .5 * delta)
self.DirichletBoundary = "REST"
x, y = fen.SpatialCoordinate(mesh)[:]
self._aboveIndicator = ufl.conditional(ufl.gt(y, 0.), fenONE, fenZERO)
self._belowCenterIndicator = ufl.conditional(
ufl.And(ufl.ge(x, - .5 * delta),
ufl.le(x, .5 * delta)),
fenONE, fenZERO)
self._belowSidesIndicator = (fenONE - self._aboveIndicator
- self._belowCenterIndicator)
self.DirichletDatum = [fen.exp(- 10. * (H / 2. + y) / H
- .5 * ((x + .4 * L + .5 * delta) / (.1 * L)) ** 2.
) * self._belowSidesIndicator, fenZERO]
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
-
- spKx, spKy = [None] * 2, [None] * 2
- spM = None
- def getstiffnessblockj(direc:int, j:int):
- DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
- self.DirichletBoundary)
- if direc == 0:
- if j == 0:
- fact = 16. * self._L ** 2.
- else:
- fact = 4. * self._delta ** 2.
- else:
- fact = self._H ** 2.
- if direc == 0:
- if j == 0:
- fact *= (self._aboveIndicator + self._belowSidesIndicator)
- else:
- fact *= self._belowCenterIndicator
- else:
- if j == 0:
- fact *= self._aboveIndicator
- else:
- fact *= (self._belowSidesIndicator
- + self._belowCenterIndicator)
- ajRe = fact * self.u.dx(direc) * self.v.dx(direc) * fen.dx
- return fenics2Sparse(ajRe, {}, DirichletBC0, 0)
- def getmass():
- DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
- self.DirichletBoundary)
- ajRe = - 4. * self.u * self.v * fen.dx
- return fenics2Sparse(ajRe, {}, DirichletBC0, 0)
-
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.As[1] is None or self.As[2] is None or self.As[5] is None:
+ thy2 = [(1.,), ('x', '()', 1, '*', 4., '-', 2. * self._H),
+ ('x', '()', 1, '**', 2., '*', 6., '-',
+ ('x', '()', 1, '*', 6. * self._H), '+', self._H ** 2.),
+ ('x', '()', 1, '**', 2., '*', 4., '-',
+ ('x', '()', 1, '*', 3. * self._H), '+', self._H ** 2.,
+ '*', ('x', '()', 1), '*', 2.),
+ ('x', '()', 1, '*', -1., '+', self._H, '*', ('x', '()', 1),
+ '**', 2.)]
+ if self.As[3] is None or self.As[4] is None or self.As[5] is None:
+ thz2 = [(1.,), ('x', '()', 2, '*', 4., '-', 2. * self._W),
+ ('x', '()', 2, '**', 2., '*', 6., '-',
+ ('x', '()', 2, '*', 6. * self._W), '+', self._W ** 2.),
+ ('x', '()', 2, '**', 2., '*', 4., '-',
+ ('x', '()', 2, '*', 3. * self._W), '+', self._W ** 2.,
+ '*', ('x', '()', 2), '*', 2.),
+ ('x', '()', 2, '*', -1., '+', self._W, '*', ('x', '()', 2),
+ '**', 2.)]
+ if self.As[0] is None:
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
a0Re = fenZERO * fen.dot(self.u, self.v) * fen.dx
self.As[0] = fenics2Sparse(a0Re, {}, DirichletBC0, 1)
+ self.thAs[0] = self.getMonomialSingleWeight([0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 7 and self.As[7] is None:
- vbMng(self, "INIT", "Assembling operator term A7.", 20)
- if spKx[1] is None: spKx[1] = getstiffnessblockj(0, 1)
- self.As[7] = self._W ** 2. * self._H ** 2. * spKx[1]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 9 and self.As[9] is None:
- vbMng(self, "INIT", "Assembling operator term A9.", 20)
- if spKy[0] is None: spKy[0] = getstiffnessblockj(1, 0)
- self.As[9] = self._W ** 2. * self._H ** 2. * spKy[0]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 16 and self.As[16] is None:
- vbMng(self, "INIT", "Assembling operator term A16.", 20)
- if spKx[1] is None: spKx[1] = getstiffnessblockj(0, 1)
- self.As[16] = - 2. * self._W ** 2. * self._H * spKx[1]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 17 and self.As[17] is None:
- vbMng(self, "INIT", "Assembling operator term A17.", 20)
- if spKx[1] is None: spKx[1] = getstiffnessblockj(0, 1)
- self.As[17] = - 2. * self._W * self._H ** 2. * spKx[1]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 18 and self.As[18] is None:
- vbMng(self, "INIT", "Assembling operator term A18.", 20)
- if spKy[0] is None: spKy[0] = getstiffnessblockj(1, 0)
- self.As[18] = - 2. * self._W ** 2. * self._H * spKy[0]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 19 and self.As[19] is None:
- vbMng(self, "INIT", "Assembling operator term A19.", 20)
- if spKy[0] is None: spKy[0] = getstiffnessblockj(1, 0)
- self.As[19] = - 2. * self._W * self._H ** 2. * spKy[0]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 30 and self.As[30] is None:
- vbMng(self, "INIT", "Assembling operator term A30.", 20)
- if spKx[1] is None: spKx[1] = getstiffnessblockj(0, 1)
- self.As[30] = self._W ** 2. * spKx[1]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 31 and self.As[31] is None:
- vbMng(self, "INIT", "Assembling operator term A31.", 20)
- if spKx[1] is None: spKx[1] = getstiffnessblockj(0, 1)
- self.As[31] = 4. * self._W * self._H * spKx[1]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 32 and self.As[32] is None:
- vbMng(self, "INIT", "Assembling operator term A32.", 20)
- if spKx[0] is None: spKx[0] = getstiffnessblockj(0, 0)
- if spKx[1] is None: spKx[1] = getstiffnessblockj(0, 1)
- if spKy[0] is None: spKy[0] = getstiffnessblockj(1, 0)
- if spKy[1] is None: spKy[1] = getstiffnessblockj(1, 1)
- self.As[32] = (self._H ** 2. * (spKx[0] + spKx[1])
- + self._W ** 2. * (spKy[0] + spKy[1]))
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 33 and self.As[33] is None:
- vbMng(self, "INIT", "Assembling operator term A33.", 20)
- if spKy[0] is None: spKy[0] = getstiffnessblockj(1, 0)
- self.As[33] = 4. * self._W * self._H * spKy[0]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 34 and self.As[34] is None:
- vbMng(self, "INIT", "Assembling operator term A34.", 20)
- if spKy[0] is None: spKy[0] = getstiffnessblockj(1, 0)
- self.As[34] = self._H ** 2. * spKy[0]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 47 and self.As[47] is None:
- vbMng(self, "INIT", "Assembling operator term A47.", 20)
- if spM is None: spM = getmass()
- self.As[47] = self._W ** 2. * self._H ** 2. * spM
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 51 and self.As[51] is None:
- vbMng(self, "INIT", "Assembling operator term A51.", 20)
- if spKx[1] is None: spKx[1] = getstiffnessblockj(0, 1)
- self.As[51] = - 2. * self._W * spKx[1]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 52 and self.As[52] is None:
- vbMng(self, "INIT", "Assembling operator term A52.", 20)
- if spKx[0] is None: spKx[0] = getstiffnessblockj(0, 0)
- if spKx[1] is None: spKx[1] = getstiffnessblockj(0, 1)
- self.As[52] = - 2. * self._H * (spKx[0] + spKx[1])
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 53 and self.As[53] is None:
- vbMng(self, "INIT", "Assembling operator term A53.", 20)
- if spKy[0] is None: spKy[0] = getstiffnessblockj(1, 0)
- if spKy[1] is None: spKy[1] = getstiffnessblockj(1, 1)
- self.As[53] = - 2. * self._W * (spKy[0] + spKy[1])
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 54 and self.As[54] is None:
- vbMng(self, "INIT", "Assembling operator term A54.", 20)
- if spKy[0] is None: spKy[0] = getstiffnessblockj(1, 0)
- self.As[54] = - 2. * self._H * spKy[0]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 73 and self.As[73] is None:
- vbMng(self, "INIT", "Assembling operator term A73.", 20)
- if spM is None: spM = getmass()
- self.As[73] = - 2. * self._W ** 2. * self._H * spM
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 74 and self.As[74] is None:
- vbMng(self, "INIT", "Assembling operator term A74.", 20)
- if spM is None: spM = getmass()
- self.As[74] = - 2. * self._W * self._H ** 2. * spM
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 79 and self.As[79] is None:
- vbMng(self, "INIT", "Assembling operator term A79.", 20)
- if spKx[0] is None: spKx[0] = getstiffnessblockj(0, 0)
- if spKx[1] is None: spKx[1] = getstiffnessblockj(0, 1)
- self.As[79] = spKx[0] + spKx[1]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 81 and self.As[81] is None:
- vbMng(self, "INIT", "Assembling operator term A81.", 20)
- if spKy[0] is None: spKy[0] = getstiffnessblockj(1, 0)
- if spKy[1] is None: spKy[1] = getstiffnessblockj(1, 1)
- self.As[81] = spKy[0] + spKy[1]
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 107 and self.As[107] is None:
- vbMng(self, "INIT", "Assembling operator term A107.", 20)
- if spM is None: spM = getmass()
- self.As[107] = self._W ** 2. * spM
- vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 108 and self.As[108] is None:
- vbMng(self, "INIT", "Assembling operator term A108.", 20)
- if spM is None: spM = getmass()
- self.As[108] = 4. * self._W * self._H * spM
+ if self.As[1] is None:
+ vbMng(self, "INIT", "Assembling operator term A1.", 20)
+ DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
+ self.DirichletBoundary)
+ ajRe = ((self._aboveIndicator + self._belowSidesIndicator)
+ * 16. * self._L ** 2. * self.u.dx(0) * self.v.dx(0) * fen.dx)
+ self.As[1] = fenics2Sparse(ajRe, {}, DirichletBC0, 0)
+ thz0 = [(1.,), ('x', '()', 2, '*', 2.), ('x', '()', 2, '**', 2.)]
+ self.thAs[1] = []
+ idxs = nextDerivativeIndices([], 3, hashD([0, 4, 2]) + 1)
+ for idx in idxs:
+ dy, dz = 4 - idx[1], 2 - idx[2]
+ if idx[0] == 0 and dy >= 0 and dz >= 0:
+ self.thAs[1] += [thy2[dy] + ('*') + (thz0[dz],)]
+ else:
+ self.thAs[1] += [(0.,)]
+ self.thAs[1] += [None]
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 109 and self.As[109] is None:
- vbMng(self, "INIT", "Assembling operator term A109.", 20)
- if spM is None: spM = getmass()
- self.As[109] = self._H ** 2. * spM
+ if self.As[2] is None:
+ vbMng(self, "INIT", "Assembling operator term A2.", 20)
+ DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
+ self.DirichletBoundary)
+ ajRe = (4. * self._delta ** 2. * self._belowCenterIndicator
+ * self.u.dx(0) * self.v.dx(0) * fen.dx)
+ self.As[2] = fenics2Sparse(ajRe, {}, DirichletBC0, 0)
+ thz1 = [(1.,), ('x', '()', 2, '*', 2., '-', 2. * self._W),
+ ('x', '()', 2, '*', -1., '+', self._W, '**', 2.)]
+ self.thAs[2] = []
+ idxs = nextDerivativeIndices([], 3, hashD([0, 4, 2]) + 1)
+ for idx in idxs:
+ dy, dz = 4 - idx[1], 2 - idx[2]
+ if idx[0] == 0 and dy >= 0 and dz >= 0:
+ self.thAs[2] += [thy2[dy] + ('*') + (thz1[dz],)]
+ else:
+ self.thAs[2] += [(0.,)]
+ self.thAs[2] += [None]
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 151 and self.As[151] is None:
- vbMng(self, "INIT", "Assembling operator term A151.", 20)
- if spM is None: spM = getmass()
- self.As[151] = - 2. * self._W * spM
+ if self.As[3] is None:
+ vbMng(self, "INIT", "Assembling operator term A3.", 20)
+ DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
+ self.DirichletBoundary)
+ ajRe = (self._H ** 2. * self._aboveIndicator
+ * self.u.dx(1) * self.v.dx(1) * fen.dx)
+ self.As[3] = fenics2Sparse(ajRe, {}, DirichletBC0, 0)
+ thy1 = [(1.,), ('x', '()', 1, '*', 2., '-', 2. * self._H),
+ (self._H, '-', ('x', '()', 1), '**', 2.)]
+ self.thAs[3] = []
+ idxs = nextDerivativeIndices([], 3, hashD([0, 2, 4]) + 1)
+ for idx in idxs:
+ dy, dz = 2 - idx[1], 4 - idx[2]
+ if idx[0] == 0 and dy >= 0 and dz >= 0:
+ self.thAs[3] += [thy1[dy] + ('*') + (thz2[dz],)]
+ else:
+ self.thAs[3] += [(0.,)]
+ self.thAs[3] += [None]
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 152 and self.As[152] is None:
- vbMng(self, "INIT", "Assembling operator term A152.", 20)
- if spM is None: spM = getmass()
- self.As[152] = - 2. * self._H * spM
+ if self.As[4] is None:
+ vbMng(self, "INIT", "Assembling operator term A4.", 20)
+ DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
+ self.DirichletBoundary)
+ ajRe = ((self._belowSidesIndicator + self._belowCenterIndicator)
+ * self._H ** 2. * self.u.dx(1) * self.v.dx(1) * fen.dx)
+ self.As[4] = fenics2Sparse(ajRe, {}, DirichletBC0, 0)
+ thy0 = [(1.,), ('x', '()', 1, '*', 2.), ('x', '()', 1, '**', 2.)]
+ self.thAs[4] = []
+ idxs = nextDerivativeIndices([], 3, hashD([0, 2, 4]) + 1)
+ for idx in idxs:
+ dy, dz = 2 - idx[1], 4 - idx[2]
+ if idx[0] == 0 and dy >= 0 and dz >= 0:
+ self.thAs[4] += [thy0[dy] + ('*') + (thz2[dz],)]
+ else:
+ self.thAs[4] += [(0.,)]
+ self.thAs[4] += [None]
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 205 and self.As[205] is None:
- vbMng(self, "INIT", "Assembling operator term A205.", 20)
- if spM is None: spM = getmass()
- self.As[205] = spM
+ if self.As[5] is None:
+ vbMng(self, "INIT", "Assembling operator term A5.", 20)
+ DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
+ self.DirichletBoundary)
+ ajRe = - 4. * self.u * self.v * fen.dx
+ self.As[5] = fenics2Sparse(ajRe, {}, DirichletBC0, 0)
+ thx = [(1.,), ('x', '()', 0)]
+ self.thAs[5] = []
+ idxs = nextDerivativeIndices([], 3, hashD([1, 4, 4]) + 1)
+ for idx in idxs:
+ dx, dy, dz = 1 - idx[0], 4 - idx[1], 4 - idx[2]
+ if dx >= 0 and dy >= 0 and dz >= 0:
+ self.thAs[5] += [thx[dx] + ('*') + (thy2[dy],)
+ + ('*') + (thz2[dz],)]
+ else:
+ self.thAs[5] += [(0.,)]
+ self.thAs[5] += [None]
vbMng(self, "DEL", "Done assembling operator term.", 20)
- for j in range(derI, self.nAs):
- if self.As[j] is None:
- self.As[j] = self.checkAInBounds(-1)
- return self._assembleA(mu, der, derI)
-
diff --git a/rrompy/hfengines/linear_problem/tridimensional/scattering_1d.py b/rrompy/hfengines/linear_problem/tridimensional/scattering_1d.py
index bcda6f2..4d97599 100644
--- a/rrompy/hfengines/linear_problem/tridimensional/scattering_1d.py
+++ b/rrompy/hfengines/linear_problem/tridimensional/scattering_1d.py
@@ -1,78 +1,74 @@
# 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
import fenics as fen
-from rrompy.utilities.base.types import ScOp, List, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenZERO, fenONE
from rrompy.hfengines.linear_problem.scattering_problem_engine import (
ScatteringProblemEngine)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['Scattering1d']
class Scattering1d(ScatteringProblemEngine):
def __init__(self, mu0 : paramVal = [5.5, np.pi, 0.], n : int = 50,
- degree_threshold : int = np.inf, verbosity : int = 10,
- timestamp : bool = True):
+ degree_threshold : int = np.inf, homogeneized : bool = False,
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = mu0, degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.nAs = 24
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = False
+ self.nAs = 3
self.npar = 3
self.rescalingExp = [1., 1., 1.]
self._L = np.real(mu0[1])
self.V = fen.FunctionSpace(fen.IntervalMesh(n, 0., self._L), "P", 1)
self.RobinBoundary = lambda x, on_b: (on_b and x[0] >= .5 * np.pi)
self.DirichletBoundary = "REST"
self.DirichletDatum = fenONE
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.As[0] is None:
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
a0 = fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
self.As[0] = fenics2Sparse(a0, {}, DirichletBC0, 1)
+ self.thAs[0] = self.getMonomialSingleWeight([0, 0, 0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 14 and self.As[14] is None:
+ if self.As[1] is None:
self.autoSetDS()
- vbMng(self, "INIT", "Assembling operator term A14.", 20)
+ vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
- a14 = - self._L ** -1. * fen.dot(self.u, self.v) * self.ds(1)
- self.As[14] = 1.j * fenics2Sparse(a14, {}, DirichletBC0, 0)
+ a1 = - self._L ** -1. * fen.dot(self.u, self.v) * self.ds(1)
+ self.As[1] = 1.j * fenics2Sparse(a1, {}, DirichletBC0, 0)
+ self.thAs[1] = self.getMonomialSingleWeight([1, 1, 1])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 23 and self.As[23] is None:
- vbMng(self, "INIT", "Assembling operator term A23.", 20)
+ if self.As[2] is None:
+ vbMng(self, "INIT", "Assembling operator term A2.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
self.DirichletBoundary)
- a23 = - self._L ** -2. * fen.dot(self.u, self.v) * fen.dx
- self.As[23] = fenics2Sparse(a23, {}, DirichletBC0, 0)
+ a2 = - self._L ** -2. * fen.dot(self.u, self.v) * fen.dx
+ self.As[2] = fenics2Sparse(a2, {}, DirichletBC0, 0)
+ self.thAs[2] = self.getMonomialSingleWeight([2, 2, 0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- for j in range(derI, self.nAs):
- if self.As[j] is None:
- self.As[j] = self.checkAInBounds(-1)
- return self._assembleA(mu, der, derI)
diff --git a/rrompy/hfengines/vector_linear_problem/__init__.py b/rrompy/hfengines/vector_linear_problem/__init__.py
index 80da6f5..805fc8b 100644
--- a/rrompy/hfengines/vector_linear_problem/__init__.py
+++ b/rrompy/hfengines/vector_linear_problem/__init__.py
@@ -1,34 +1,32 @@
# 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 .linear_elasticity_problem_engine import LinearElasticityProblemEngine
from .linear_elasticity_helmholtz_problem_engine import LinearElasticityHelmholtzProblemEngine
from .linear_elasticity_helmholtz_problem_engine_damped import LinearElasticityHelmholtzProblemEngineDamped
from .linear_elasticity_beam_poisson_ratio import LinearElasticityBeamPoissonRatio
-from .linear_elasticity_helmholtz_archway_frequency import LinearElasticityHelmholtzArchwayFrequency
__all__ = [
'LinearElasticityProblemEngine',
'LinearElasticityHelmholtzProblemEngine',
'LinearElasticityHelmholtzProblemEngineDamped',
- 'LinearElasticityBeamPoissonRatio',
- 'LinearElasticityHelmholtzArchwayFrequency'
+ 'LinearElasticityBeamPoissonRatio'
]
diff --git a/rrompy/hfengines/vector_linear_problem/bidimensional/linear_elasticity_beam_elasticity_constants.py b/rrompy/hfengines/vector_linear_problem/bidimensional/linear_elasticity_beam_elasticity_constants.py
index d78b291..a91b95f 100644
--- a/rrompy/hfengines/vector_linear_problem/bidimensional/linear_elasticity_beam_elasticity_constants.py
+++ b/rrompy/hfengines/vector_linear_problem/bidimensional/linear_elasticity_beam_elasticity_constants.py
@@ -1,135 +1,120 @@
# 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
import fenics as fen
from rrompy.hfengines.vector_linear_problem.\
linear_elasticity_beam_poisson_ratio import LinearElasticityBeamPoissonRatio
-from rrompy.solver.fenics import fenZEROS
-from rrompy.utilities.base.types import Np1D, List, ScOp, paramVal
+from rrompy.solver.fenics import fenZERO, fenZEROS
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.exception_manager import RROMPyAssert
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse, fenics2Vector
__all__ = ['LinearElasticityBeamElasticityConstants']
class LinearElasticityBeamElasticityConstants(
LinearElasticityBeamPoissonRatio):
"""
Solver for linear elasticity problem of a beam subject to its own weight,
with parametric Joung modulus and Poisson's ratio.
- div(lambda_ * div(u) * I + 2 * mu_ * epsilon(u)) = rho_ * g in \Omega
u = 0 on \Gamma_D
\partial_nu = 0 on \Gamma_N
"""
def __init__(self, n:int, rho_:float, g:float, E0:float, nu0:float,
length:float, degree_threshold : int = np.inf,
verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = [nu0, E0], degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.nAs, self.nbs = 5, 4
+ homogeneized = False, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = False
+ self.nAs, self.nbs = 3, 2
+ self.npar = 2
mesh = fen.RectangleMesh(fen.Point(0., 0.), fen.Point(length, 1),
n, max(int(n / length), 1))
self.V = fen.VectorFunctionSpace(mesh, "P", 1)
self.forcingTerm = [fen.Constant((0., - rho_ * g)), fenZEROS(2)]
self.DirichletBoundary = lambda x, on_b: on_b and fen.near(x[0], 0.)
self.NeumannBoundary = "REST"
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- for j in [1, 3]:
- if derI <= j and self.As[j] is None:
- self.As[j] = self.checkAInBounds(-1)
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.As[0] is None:
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZEROS(2),
self.DirichletBoundary)
- a0Re = fen.inner(fenZEROS(2), self.v) * fen.dx
+ a0Re = fenZERO * fen.inner(self.u, self.v) * fen.dx
self.As[0] = fenics2Sparse(a0Re, {}, DirichletBC0, 1)
+ self.thAs[0] = self.getMonomialSingleWeight([0, 0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 4 and self.As[2] is None:
- vbMng(self, "INIT", "Assembling operator term A2.", 20)
+ if self.As[1] is None:
+ vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZEROS(2),
self.DirichletBoundary)
epsilon = lambda u: .5 * (fen.grad(u) + fen.nabla_grad(u))
- a2Re = 2. * fen.inner(epsilon(self.u), epsilon(self.v)) * fen.dx
- self.As[2] = fenics2Sparse(a2Re, {}, DirichletBC0, 0)
+ a1Re = fen.inner(epsilon(self.u), epsilon(self.v)) * fen.dx
+ self.As[1] = fenics2Sparse(a1Re, {}, DirichletBC0, 0)
+ self.thAs[1] = [('x', '()', 0, '*', -2., '+', 1.,
+ '*', ('x', '()', 1)),
+ ('x', '()', 1, '*', -2.),
+ ('x', '()', 0, '*', -2.),
+ (0.,), (-2.,), None]
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 4 and self.As[4] is None:
- vbMng(self, "INIT", "Assembling operator term A4.", 20)
+ if self.As[2] is None:
+ vbMng(self, "INIT", "Assembling operator term A2.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZEROS(2),
self.DirichletBoundary)
a4Re = fen.div(self.u) * fen.div(self.v) * fen.dx
- self.As[4] = (fenics2Sparse(a4Re, {}, DirichletBC0, 0)
- - 2. * self.As[2])
+ self.As[2] = fenics2Sparse(a4Re, {}, DirichletBC0, 0)
+ self.thAs[2] = self.getMonomialSingleWeight([1, 1])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
- def b(self, mu : paramVal = [], der : List[int] = 0,
- homogeneized : bool = False) -> Np1D:
- """Assemble (derivative of) RHS of linear system."""
- RROMPyAssert(homogeneized, False, "Homogeneized")
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- if derI <= 0 and self.bs[0] is None:
- self.autoSetDS()
+ def buildb(self):
+ """Build terms of operator of linear system."""
+ if self.thbs[0] is None:
+ self.thbs = [None] * (self.nbs + self.homogeneized * self.nAs)
+ if self.bs[0] is None:
vbMng(self, "INIT", "Assembling forcing term b0.", 20)
- fRe, fIm = self.forcingTerm
- parsRe = self.iterReduceQuadratureDegree(zip([fRe],
- ["forcingTermReal"]))
- parsIm = self.iterReduceQuadratureDegree(zip([fIm],
- ["forcingTermImag"]))
- L0Re = fen.inner(fRe, self.v) * fen.dx
- L0Im = fen.inner(fIm, self.v) * fen.dx
+ L0 = fen.inner(fenZEROS(2), self.v) * fen.dx
DBCR = fen.DirichletBC(self.V, self.DirichletDatum[0],
self.DirichletBoundary)
DBCI = fen.DirichletBC(self.V, self.DirichletDatum[1],
self.DirichletBoundary)
- self.bs[0] = (fenics2Vector(L0Re, parsRe, DBCR, 1)
- + 1.j * fenics2Vector(L0Im, parsIm, DBCI, 1))
- if derI <= 3 and self.bs[1] is None:
+ self.bs[0] = (fenics2Vector(L0, {}, DBCR, 1)
+ + 1.j * fenics2Vector(L0, {}, DBCI, 1))
+ self.thbs[0] = self.getMonomialSingleWeight([0, 0])
+ if self.bs[1] is None:
vbMng(self, "INIT", "Assembling forcing term b1.", 20)
fRe, fIm = self.forcingTerm
parsRe = self.iterReduceQuadratureDegree(zip([fRe],
- ["forcingTermReal"]))
+ ["forcingTermReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([fIm],
- ["forcingTermImag"]))
- L1Re = - fen.inner(fRe, self.v) * fen.dx
- L1Im = - fen.inner(fIm, self.v) * fen.dx
+ ["forcingTermImag"]))
+ L1Re = fen.inner(fRe, self.v) * fen.dx
+ L1Im = fen.inner(fIm, self.v) * fen.dx
DBC0 = fen.DirichletBC(self.V, fenZEROS(2), self.DirichletBoundary)
self.bs[1] = (fenics2Vector(L1Re, parsRe, DBC0, 1)
+ 1.j * fenics2Vector(L1Im, parsIm, DBC0, 1))
+ self.thbs[1] = [('x', '()', 0, '**', 2., '*', -2., '-',
+ ('x', '()', 0), '+', 1.),
+ ('x', '()', 0, '*', -4., '-', 1.),
+ (0.,), (-2.0,), None]
vbMng(self, "DEL", "Done assembling forcing term.", 20)
- if derI <= 2 and self.bs[2] is None:
- self.bs[2] = self.checkbInBounds(-1)
- if derI <= 3 and self.bs[3] is None:
- vbMng(self, "INIT", "Assembling forcing term b3.", 20)
- self.bs[3] = 2. * self.bs[1]
- vbMng(self, "DEL", "Done assembling forcing term.", 20)
- return self._assembleb(mu, der, derI, homogeneized)
-
+ self.setbHomogeneized()
diff --git a/rrompy/hfengines/vector_linear_problem/linear_elasticity_beam_poisson_ratio.py b/rrompy/hfengines/vector_linear_problem/linear_elasticity_beam_poisson_ratio.py
index 03a50a8..2ab683b 100644
--- a/rrompy/hfengines/vector_linear_problem/linear_elasticity_beam_poisson_ratio.py
+++ b/rrompy/hfengines/vector_linear_problem/linear_elasticity_beam_poisson_ratio.py
@@ -1,127 +1,117 @@
# 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
import fenics as fen
from .linear_elasticity_problem_engine import LinearElasticityProblemEngine
-from rrompy.solver.fenics import fenZEROS
-from rrompy.utilities.base.types import Np1D, List, ScOp, paramVal
+from rrompy.solver.fenics import fenZERO, fenZEROS
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.exception_manager import RROMPyAssert
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse, fenics2Vector
__all__ = ['LinearElasticityBeamPoissonRatio']
class LinearElasticityBeamPoissonRatio(LinearElasticityProblemEngine):
"""
Solver for linear elasticity problem of a beam subject to its own weight,
with parametric Poisson's ratio.
- div(lambda_ * div(u) * I + 2 * mu_ * epsilon(u)) = rho_ * g in \Omega
u = 0 on \Gamma_D
\partial_nu = 0 on \Gamma_N
"""
def __init__(self, n:int, rho_:float, g:float, E:float, nu0:float,
length:float, degree_threshold : int = np.inf,
verbosity : int = 10, timestamp : bool = True):
super().__init__(mu0 = [nu0], degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.nAs, self.nbs = 2, 3
+ homogeneized = False, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = False
+ self.nAs, self.nbs = 3, 2
self.E_ = E
mesh = fen.RectangleMesh(fen.Point(0., 0.), fen.Point(length, 1),
n, max(int(n / length), 1))
self.V = fen.VectorFunctionSpace(mesh, "P", 1)
self.forcingTerm = [fen.Constant((0., - rho_ * g / E)), fenZEROS(2)]
self.DirichletBoundary = lambda x, on_b: on_b and fen.near(x[0], 0.)
self.NeumannBoundary = "REST"
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.As[0] is None:
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZEROS(2),
self.DirichletBoundary)
- epsilon = lambda u: .5 * (fen.grad(u) + fen.nabla_grad(u))
- a0Re = 2. * self.E_ * fen.inner(epsilon(self.u),
- epsilon(self.v)) * fen.dx
+ a0Re = fenZERO * fen.inner(self.u, self.v) * fen.dx
self.As[0] = fenics2Sparse(a0Re, {}, DirichletBC0, 1)
+ self.thAs[0] = self.getMonomialSingleWeight([0])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
+ if self.As[1] is None:
vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V, fenZEROS(2),
self.DirichletBoundary)
epsilon = lambda u: .5 * (fen.grad(u) + fen.nabla_grad(u))
- a1Re = self.E_ * (fen.div(self.u) * fen.div(self.v)
- - 4. * fen.inner(epsilon(self.u),
- epsilon(self.v))) * fen.dx
+ a1Re = self.E_ * fen.inner(epsilon(self.u),
+ epsilon(self.v)) * fen.dx
self.As[1] = fenics2Sparse(a1Re, {}, DirichletBC0, 0)
+ self.thAs[1] = [('x', '()', 0, '*', -2., '+', 1.),
+ (-2.0,), None]
+ epsilon = lambda u: .5 * (fen.grad(u) + fen.nabla_grad(u))
+ vbMng(self, "DEL", "Done assembling operator term.", 20)
+ if self.As[2] is None:
+ vbMng(self, "INIT", "Assembling operator term A2.", 20)
+ DirichletBC0 = fen.DirichletBC(self.V, fenZEROS(2),
+ self.DirichletBoundary)
+ a2Re = self.E_ * fen.div(self.u) * fen.div(self.v) * fen.dx
+ self.As[2] = fenics2Sparse(a2Re, {}, DirichletBC0, 0)
+ self.thAs[2] = self.getMonomialSingleWeight([1])
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
- def b(self, mu : paramVal = [], der : List[int] = 0,
- homogeneized : bool = False) -> Np1D:
- """Assemble (derivative of) RHS of linear system."""
- RROMPyAssert(homogeneized, False, "Homogeneized")
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- if derI <= 0 and self.bs[0] is None:
- self.autoSetDS()
+ def buildb(self):
+ """Build terms of operator of linear system."""
+ if self.thbs[0] is None:
+ self.thbs = [None] * (self.nbs + self.homogeneized * self.nAs)
+ if self.bs[0] is None:
vbMng(self, "INIT", "Assembling forcing term b0.", 20)
- fRe, fIm = self.forcingTerm
- parsRe = self.iterReduceQuadratureDegree(zip([fRe],
- ["forcingTermReal"]))
- parsIm = self.iterReduceQuadratureDegree(zip([fIm],
- ["forcingTermImag"]))
- L0Re = fen.inner(fRe, self.v) * fen.dx
- L0Im = fen.inner(fIm, self.v) * fen.dx
+ L0Re = fen.inner(fenZEROS(2), self.v) * fen.dx
DBCR = fen.DirichletBC(self.V, self.DirichletDatum[0],
self.DirichletBoundary)
DBCI = fen.DirichletBC(self.V, self.DirichletDatum[1],
self.DirichletBoundary)
- self.bs[0] = (fenics2Vector(L0Re, parsRe, DBCR, 1)
- + 1.j * fenics2Vector(L0Im, parsIm, DBCI, 1))
- if derI <= 2 and self.bs[1] is None:
+ self.bs[0] = (fenics2Vector(L0Re, {}, DBCR, 1)
+ + 1.j * fenics2Vector(L0Re, {}, DBCI, 1))
+ self.thbs[0] = self.getMonomialSingleWeight([0])
+ if self.bs[1] is None:
vbMng(self, "INIT", "Assembling forcing term b1.", 20)
fRe, fIm = self.forcingTerm
parsRe = self.iterReduceQuadratureDegree(zip([fRe],
- ["forcingTermReal"]))
+ ["forcingTermReal"]))
parsIm = self.iterReduceQuadratureDegree(zip([fIm],
- ["forcingTermImag"]))
- L1Re = - fen.inner(fRe, self.v) * fen.dx
- L1Im = - fen.inner(fIm, self.v) * fen.dx
- DBC0 = fen.DirichletBC(self.V, fenZEROS(2),
- self.DirichletBoundary)
+ ["forcingTermImag"]))
+ L1Re = fen.inner(fRe, self.v) * fen.dx
+ L1Im = fen.inner(fIm, self.v) * fen.dx
+ DBC0 = fen.DirichletBC(self.V, fenZEROS(2), self.DirichletBoundary)
self.bs[1] = (fenics2Vector(L1Re, parsRe, DBC0, 1)
+ 1.j * fenics2Vector(L1Im, parsIm, DBC0, 1))
+ self.thbs[1] = [('x', '()', 0, '**', 2., '*', -2., '-',
+ ('x', '()', 0), '+', 1.),
+ ('x', '()', 0, '*', -4., '-', 1.),
+ (-2.0,), None]
vbMng(self, "DEL", "Done assembling forcing term.", 20)
-
- if derI <= 2 and self.bs[2] is None:
- vbMng(self, "INIT", "Assembling forcing term b2.", 20)
- self.bs[2] = 2. * self.bs[1]
- vbMng(self, "DEL", "Done assembling forcing term.", 20)
- return self._assembleb(mu, der, derI, homogeneized)
-
+ self.setbHomogeneized()
diff --git a/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_archway_frequency.py b/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_archway_frequency.py
deleted file mode 100644
index 50548f4..0000000
--- a/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_archway_frequency.py
+++ /dev/null
@@ -1,66 +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
-import fenics as fen
-from .linear_elasticity_helmholtz_problem_engine import \
- LinearElasticityHelmholtzProblemEngine
-from rrompy.solver.fenics import fenZEROS
-
-__all__ = ['LinearElasticityHelmholtzArchwayFrequency']
-
-class LinearElasticityHelmholtzArchwayFrequency(
- LinearElasticityHelmholtzProblemEngine):
- """
- Solver for archway linear elasticity Helmholtz problem with parametric
- wavenumber.
- - div(lambda_ * div(u) * I + 2 * mu_ * epsilon(u))
- - rho_ * omega^2 * u = rho_ * g / omega in \Omega
- u = 0 on \Gamma_D
- \partial_nu = 0 on \Gamma_N
- """
-
- def __init__(self, kappa:float, n:int, rho_:float, T:float, lambda_:float,
- mu_:float, R:float, r:float, degree_threshold : int = np.inf,
- verbosity : int = 10, timestamp : bool = True):
- super().__init__(mu0 = [kappa], degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
- self.lambda_ = lambda_
- self.mu_ = mu_
- self.rho_ = rho_
-
- import mshr
- domain = (mshr.Circle(fen.Point(0, 0), R)
- - mshr.Circle(fen.Point(0, 0), r)
- - mshr.Rectangle(fen.Point(-1.05*R, -1.05*R),
- fen.Point(1.05*R, 0)))
- mesh = mshr.generate_mesh(domain, n)
- self.V = fen.VectorFunctionSpace(mesh, "P", 1)
-
- import ufl
- x, y = fen.SpatialCoordinate(mesh)[:]
- NeumannNonZero = ufl.And(ufl.gt(y, r),
- ufl.And(ufl.ge(x, -.25 * R), ufl.le(x, .25 * R)))
- self.NeumannDatum = [ufl.as_vector((0.,
- ufl.conditional(NeumannNonZero,
- fen.Constant(T),
- 0.))),
- fenZEROS(2)]
- self.DirichletBoundary = lambda x, on_b: on_b and fen.near(x[1], 0.)
- self.NeumannBoundary = "REST"
-
diff --git a/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_problem_engine.py b/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_problem_engine.py
index d8b192a..0f699f2 100644
--- a/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_problem_engine.py
+++ b/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_problem_engine.py
@@ -1,183 +1,178 @@
# 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
import fenics as fen
from .linear_elasticity_problem_engine import LinearElasticityProblemEngine
-from rrompy.utilities.base.types import List, ScOp, paramVal
-from rrompy.solver.fenics import (fenZERO, fenZEROS, fenONE, L2NormMatrix,
- elasticNormMatrix, elasticDualNormMatrix)
+from rrompy.utilities.base.types import paramVal
+from rrompy.solver.fenics import (fenZERO, fenZEROS, fenONE, elasticNormMatrix,
+ elasticDualNormMatrix)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['LinearElasticityHelmholtzProblemEngine']
class LinearElasticityHelmholtzProblemEngine(LinearElasticityProblemEngine):
"""
Solver for generic linear elasticity Helmholtz problems with parametric
wavenumber.
- div(lambda_ * div(u) * I + 2 * mu_ * epsilon(u))
- rho_ * mu^2 * u = f in \Omega
u = u0 on \Gamma_D
\partial_nu = g1 on \Gamma_N
\partial_nu + h u = g2 on \Gamma_R
Attributes:
verbosity: Verbosity level.
BCManager: Boundary condition manager.
V: Real vector FE space.
u: Generic vector trial functions for variational form evaluation.
v: Generic vector test functions for variational form evaluation.
As: Scipy sparse array representation (in CSC format) of As.
bs: Numpy array representation of bs.
energyNormMatrix: Scipy sparse matrix representing inner product over
V.
energyNormDualMatrix: Scipy sparse matrix representing inner product
over V'.
dualityMatrix: Scipy sparse matrix representing duality V-V'.
energyNormPartialDualMatrix: Scipy sparse matrix representing dual
inner product between Riesz representers V-V.
- liftedDirichletDatum: Dofs of Dirichlet datum lifting.
- mu0BC: Mu value of last Dirichlet datum lifting.
degree_threshold: Threshold for ufl expression interpolation degree.
omega: Value of omega.
lambda_: Value of lambda_.
mu_: Value of mu_.
forcingTerm: Value of f.
DirichletDatum: Value of u0.
NeumannDatum: Value of g1.
RobinDatumG: Value of g2.
RobinDatumH: Value of h.
DirichletBoundary: Function handle to \Gamma_D.
NeumannBoundary: Function handle to \Gamma_N.
RobinBoundary: Function handle to \Gamma_R.
ds: Boundary measure 2-tuple (resp. for Neumann and Robin boundaries).
A0: Scipy sparse array representation (in CSC format) of A0.
A1: Scipy sparse array representation (in CSC format) of A1.
b0: Numpy array representation of b0.
dsToBeSet: Whether ds needs to be set.
"""
def __init__(self, mu0 : paramVal = [0.], degree_threshold : int = np.inf,
- verbosity : int = 10, timestamp : bool = True):
+ homogeneized : bool = False, verbosity : int = 10,
+ timestamp : bool = True):
super().__init__(mu0 = [mu0], degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = True
self.nAs = 2
self.omega = np.abs(self.mu0(0, 0))
self.rho_ = fenONE
self.rescalingExp = [2.]
@property
def rho_(self):
"""Value of rho_."""
return self._rho_
@rho_.setter
def rho_(self, rho_):
self.resetAs()
if not isinstance(rho_, (list, tuple,)):
rho_ = [rho_, fenZERO]
self._rho_ = rho_
def buildEnergyNormForm(self): # energy + omega norm
"""
Build sparse matrix (in CSR format) representative of scalar product.
"""
vbMng(self, "INIT", "Assembling energy matrix.", 20)
self.energyNormMatrix = elasticNormMatrix(
self.V, self.lambda_[0], self.mu_[0],
np.abs(self.omega)**2 * self.rho_[0])
vbMng(self, "DEL", "Done assembling energy matrix.", 20)
def buildEnergyNormDualForm(self):
"""
Build sparse matrix (in CSR format) representative of dual scalar
product.
"""
vbMng(self, "INIT", "Assembling energy dual matrix.", 20)
self.energyNormDualMatrix = elasticDualNormMatrix(
self.V, self.lambda_[0], self.mu_[0],
np.abs(self.omega)**2 * self.rho_[0],
compressRank = self._energyDualNormCompress)
vbMng(self, "DEL", "Done assembling energy dual matrix.", 20)
def buildEnergyNormPartialDualForm(self):
"""
Build sparse matrix (in CSR format) representative of dual scalar
product without duality.
"""
vbMng(self, "INIT", "Assembling energy partial dual matrix.", 20)
self.energyNormPartialDualMatrix = elasticDualNormMatrix(
self.V, self.lambda_[0], self.mu_[0],
np.abs(self.omega)**2 * self.rho_[0],
compressRank = self._energyDualNormCompress,
duality = False)
vbMng(self, "DEL", "Done assembling energy partial dual matrix.", 20)
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.thAs[0] is None: self.thAs = self.getMonomialWeights(self.nAs)
+ if self.As[0] is None:
+ self.autoSetDS()
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V,
fenZEROS(self.V.mesh().topology().dim()),
self.DirichletBoundary)
lambda_Re, lambda_Im = self.lambda_
mu_Re, mu_Im = self.mu_
hRe, hIm = self.RobinDatumH
termNames = ["lambda_", "mu_", "RobinDatumH"]
parsRe = self.iterReduceQuadratureDegree(zip(
[lambda_Re, mu_Re, hRe],
[x + "Real" for x in termNames]))
parsIm = self.iterReduceQuadratureDegree(zip(
[lambda_Im, mu_Re, hIm],
[x + "Imag" for x in termNames]))
epsilon = lambda u: 0.5 * (fen.grad(u) + fen.nabla_grad(u))
sigma = lambda u, l_, m_: (
l_ * fen.div(u) * fen.Identity(u.geometric_dimension())
+ 2. * m_ * epsilon(u))
a0Re = (fen.inner(sigma(self.u, lambda_Re, mu_Re),
epsilon(self.v)) * fen.dx
+ hRe * fen.inner(self.u, self.v) * self.ds(1))
a0Im = (fen.inner(sigma(self.u, lambda_Im, mu_Im),
epsilon(self.v)) * fen.dx
+ hIm * fen.inner(self.u, self.v) * self.ds(1))
self.As[0] = (fenics2Sparse(a0Re, parsRe, DirichletBC0, 1)
+ 1.j * fenics2Sparse(a0Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
+ if self.As[1] is None:
vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V,
fenZEROS(self.V.mesh().topology().dim()),
self.DirichletBoundary)
rho_Re, rho_Im = self.rho_
parsRe = self.iterReduceQuadratureDegree(zip([rho_Re],
["rho_Real"]))
parsIm = self.iterReduceQuadratureDegree(zip([rho_Im],
["rho_Imag"]))
a1Re = - rho_Re * fen.inner(self.u, self.v) * fen.dx
a1Im = - rho_Im * fen.inner(self.u, self.v) * fen.dx
self.As[1] = (fenics2Sparse(a1Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a1Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
-
diff --git a/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_problem_engine_damped.py b/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_problem_engine_damped.py
index 9902192..6329722 100644
--- a/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_problem_engine_damped.py
+++ b/rrompy/hfengines/vector_linear_problem/linear_elasticity_helmholtz_problem_engine_damped.py
@@ -1,168 +1,163 @@
# 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
import fenics as fen
from .linear_elasticity_helmholtz_problem_engine import \
LinearElasticityHelmholtzProblemEngine
-from rrompy.utilities.base.types import List, ScOp, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import fenZERO, fenZEROS
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD)
from rrompy.solver.fenics import fenics2Sparse
__all__ = ['LinearElasticityHelmholtzProblemEngineDamped']
class LinearElasticityHelmholtzProblemEngineDamped(
LinearElasticityHelmholtzProblemEngine):
"""
Solver for generic linear elasticity Helmholtz problems with parametric
wavenumber.
- div(lambda_ * div(u) * I + 2 * mu_ * epsilon(u))
- rho_ * (mu^2 - i * eta * mu) * u = f in \Omega
u = u0 on \Gamma_D
\partial_nu = g1 on \Gamma_N
\partial_nu + h u = g2 on \Gamma_R
Attributes:
verbosity: Verbosity level.
BCManager: Boundary condition manager.
V: Real vector FE space.
u: Generic vector trial functions for variational form evaluation.
v: Generic vector test functions for variational form evaluation.
As: Scipy sparse array representation (in CSC format) of As.
bs: Numpy array representation of bs.
energyNormMatrix: Scipy sparse matrix representing inner product over
V.
energyNormDualMatrix: Scipy sparse matrix representing inner product
over V'.
dualityMatrix: Scipy sparse matrix representing duality V-V'.
energyNormPartialDualMatrix: Scipy sparse matrix representing dual
inner product between Riesz representers V-V.
- liftedDirichletDatum: Dofs of Dirichlet datum lifting.
- mu0BC: Mu value of last Dirichlet datum lifting.
degree_threshold: Threshold for ufl expression interpolation degree.
omega: Value of omega.
lambda_: Value of lambda_.
mu_: Value of mu_.
eta: Value of eta.
forcingTerm: Value of f.
DirichletDatum: Value of u0.
NeumannDatum: Value of g1.
RobinDatumG: Value of g2.
RobinDatumH: Value of h.
DirichletBoundary: Function handle to \Gamma_D.
NeumannBoundary: Function handle to \Gamma_N.
RobinBoundary: Function handle to \Gamma_R.
ds: Boundary measure 2-tuple (resp. for Neumann and Robin boundaries).
A0: Scipy sparse array representation (in CSC format) of A0.
A1: Scipy sparse array representation (in CSC format) of A1.
b0: Numpy array representation of b0.
dsToBeSet: Whether ds needs to be set.
"""
def __init__(self, mu0 : paramVal = [0.], degree_threshold : int = np.inf,
- verbosity : int = 10, timestamp : bool = True):
+ homogeneized : bool = False, verbosity : int = 10,
+ timestamp : bool = True):
super().__init__(mu0 = [mu0], degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = True
self.nAs = 3
self.eta = fenZERO
self.rescalingExp = [1.]
@property
def eta(self):
"""Value of eta."""
return self._eta
@eta.setter
def eta(self, eta):
self.resetAs()
if not isinstance(eta, (list, tuple,)):
eta = [eta, fenZERO]
self._eta = eta
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.thAs[0] is None: self.thAs = self.getMonomialWeights(self.nAs)
+ if self.As[0] is None:
+ self.autoSetDS()
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V,
fenZEROS(self.V.mesh().topology().dim()),
self.DirichletBoundary)
lambda_Re, lambda_Im = self.lambda_
mu_Re, mu_Im = self.mu_
hRe, hIm = self.RobinDatumH
termNames = ["lambda_", "mu_", "RobinDatumH"]
parsRe = self.iterReduceQuadratureDegree(zip(
[lambda_Re, mu_Re, hRe],
[x + "Real" for x in termNames]))
parsIm = self.iterReduceQuadratureDegree(zip(
[lambda_Im, mu_Re, hIm],
[x + "Imag" for x in termNames]))
epsilon = lambda u: 0.5 * (fen.grad(u) + fen.nabla_grad(u))
sigma = lambda u, l_, m_: (
l_ * fen.div(u) * fen.Identity(u.geometric_dimension())
+ 2. * m_ * epsilon(u))
a0Re = (fen.inner(sigma(self.u, lambda_Re, mu_Re),
epsilon(self.v)) * fen.dx
+ hRe * fen.inner(self.u, self.v) * self.ds(1))
a0Im = (fen.inner(sigma(self.u, lambda_Im, mu_Im),
epsilon(self.v)) * fen.dx
+ hIm * fen.inner(self.u, self.v) * self.ds(1))
self.As[0] = (fenics2Sparse(a0Re, parsRe, DirichletBC0, 1)
+ 1.j * fenics2Sparse(a0Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 1 and self.As[1] is None:
+ if self.As[1] is None:
vbMng(self, "INIT", "Assembling operator term A1.", 20)
DirichletBC0 = fen.DirichletBC(self.V,
fenZEROS(self.V.mesh().topology().dim()),
self.DirichletBoundary)
rho_Re, rho_Im = self.rho_
eta_Re, eta_Im = self.eta
termNames = ["rho_", "eta"]
parsRe = self.iterReduceQuadratureDegree(zip([rho_Re, eta_Re],
[x + "Real" for x in termNames]))
parsIm = self.iterReduceQuadratureDegree(zip([rho_Im, eta_Im],
[x + "Imag" for x in termNames]))
a1Re = - ((eta_Re * rho_Im + eta_Im * rho_Re)
* fen.inner(self.u, self.v)) * fen.dx
a1Im = ((eta_Re * rho_Re - eta_Im * rho_Im)
* fen.inner(self.u, self.v)) * fen.dx
self.As[1] = (fenics2Sparse(a1Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a1Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- if derI <= 2 and self.As[2] is None:
+ if self.As[2] is None:
vbMng(self, "INIT", "Assembling operator term A2.", 20)
DirichletBC0 = fen.DirichletBC(self.V,
fenZEROS(self.V.mesh().topology().dim()),
self.DirichletBoundary)
rho_Re, rho_Im = self.rho_
parsRe = self.iterReduceQuadratureDegree(zip([rho_Re],
["rho_Real"]))
parsIm = self.iterReduceQuadratureDegree(zip([rho_Im],
["rho_Imag"]))
a2Re = - rho_Re * fen.inner(self.u, self.v) * fen.dx
a2Im = - rho_Im * fen.inner(self.u, self.v) * fen.dx
self.As[2] = (fenics2Sparse(a2Re, parsRe, DirichletBC0, 0)
+ 1.j * fenics2Sparse(a2Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
-
diff --git a/rrompy/hfengines/vector_linear_problem/linear_elasticity_problem_engine.py b/rrompy/hfengines/vector_linear_problem/linear_elasticity_problem_engine.py
index 25dcbe3..60cc8a0 100644
--- a/rrompy/hfengines/vector_linear_problem/linear_elasticity_problem_engine.py
+++ b/rrompy/hfengines/vector_linear_problem/linear_elasticity_problem_engine.py
@@ -1,363 +1,321 @@
# 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
import fenics as fen
from rrompy.hfengines.base.vector_problem_engine_base import \
VectorProblemEngineBase
-from rrompy.utilities.base.types import Np1D, List, ScOp, paramVal
+from rrompy.utilities.base.types import paramVal
from rrompy.solver.fenics import (fenZERO, fenZEROS, fenONE,
L2InverseNormMatrix, elasticNormMatrix,
elasticDualNormMatrix)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD, hashIdxToDerivative as hashI)
from rrompy.parameter import checkParameter
from rrompy.solver.fenics import fenics2Sparse, fenics2Vector
__all__ = ['LinearElasticityProblemEngine']
class LinearElasticityProblemEngine(VectorProblemEngineBase):
"""
Solver for generic linear elasticity problems.
- div(lambda_ * div(u) * I + 2 * mu_ * epsilon(u)) = f in \Omega
u = u0 on \Gamma_D
\partial_nu = g1 on \Gamma_N
\partial_nu + h u = g2 on \Gamma_R
Attributes:
+ homogeneized: Whether to homogeneize Dirichlet BCs.
verbosity: Verbosity level.
BCManager: Boundary condition manager.
V: Real vector FE space.
u: Generic vector trial functions for variational form evaluation.
v: Generic vector test functions for variational form evaluation.
As: Scipy sparse array representation (in CSC format) of As.
bs: Numpy array representation of bs.
energyNormMatrix: Scipy sparse matrix representing inner product over
V.
energyNormDualMatrix: Scipy sparse matrix representing inner product
over V'.
dualityMatrix: Scipy sparse matrix representing duality V-V'.
energyNormPartialDualMatrix: Scipy sparse matrix representing dual
inner product between Riesz representers V-V.
- liftedDirichletDatum: Dofs of Dirichlet datum lifting.
- mu0BC: Mu value of last Dirichlet datum lifting.
degree_threshold: Threshold for ufl expression interpolation degree.
lambda_: Value of lambda_.
mu_: Value of mu_.
forcingTerm: Value of f.
DirichletDatum: Value of u0.
NeumannDatum: Value of g1.
RobinDatumG: Value of g2.
RobinDatumH: Value of h.
DirichletBoundary: Function handle to \Gamma_D.
NeumannBoundary: Function handle to \Gamma_N.
RobinBoundary: Function handle to \Gamma_R.
ds: Boundary measure 2-tuple (resp. for Neumann and Robin boundaries).
A0: Scipy sparse array representation (in CSC format) of A0.
b0: Numpy array representation of b0.
dsToBeSet: Whether ds needs to be set.
"""
_energyDualNormCompress = None
def __init__(self, mu0 : paramVal = [], degree_threshold : int = np.inf,
- verbosity : int = 10, timestamp : bool = True):
+ homogeneized : bool = False, verbosity : int = 10,
+ timestamp : bool = True):
super().__init__(degree_threshold = degree_threshold,
- verbosity = verbosity, timestamp = timestamp)
+ homogeneized = homogeneized, verbosity = verbosity,
+ timestamp = timestamp)
+ self._affinePoly = True
self.lambda_ = fenONE
self.mu_ = fenONE
self.mu0 = checkParameter(mu0)
self.npar = self.mu0.shape[1]
self.forcingTerm = fenZEROS(self.V.mesh().topology().dim())
self.DirichletDatum = fenZEROS(self.V.mesh().topology().dim())
self.NeumannDatum = fenZEROS(self.V.mesh().topology().dim())
self.RobinDatumG = fenZEROS(self.V.mesh().topology().dim())
self.RobinDatumH = fenZERO
@property
def V(self):
"""Value of V."""
return self._V
@V.setter
def V(self, V):
VectorProblemEngineBase.V.fset(self, V)
self.forcingTerm = fenZEROS(self.V.mesh().topology().dim())
self.DirichletDatum = fenZEROS(self.V.mesh().topology().dim())
self.NeumannDatum = fenZEROS(self.V.mesh().topology().dim())
self.RobinDatumG = fenZEROS(self.V.mesh().topology().dim())
self.dsToBeSet = True
@property
def lambda_(self):
"""Value of lambda_."""
return self._lambda_
@lambda_.setter
def lambda_(self, lambda_):
self.resetAs()
if not isinstance(lambda_, (list, tuple,)):
lambda_ = [lambda_, fenZERO]
self._lambda_ = lambda_
@property
def mu_(self):
"""Value of mu_."""
return self._mu_
@mu_.setter
def mu_(self, mu_):
self.resetAs()
if not isinstance(mu_, (list, tuple,)):
mu_ = [mu_, fenZERO]
self._mu_ = mu_
@property
def forcingTerm(self):
"""Value of f."""
return self._forcingTerm
@forcingTerm.setter
def forcingTerm(self, forcingTerm):
self.resetbs()
if not isinstance(forcingTerm, (list, tuple,)):
forcingTerm = [forcingTerm,
fenZEROS(self.V.mesh().topology().dim())]
self._forcingTerm = forcingTerm
@property
def DirichletDatum(self):
"""Value of u0."""
return self._DirichletDatum
@DirichletDatum.setter
def DirichletDatum(self, DirichletDatum):
self.resetbs()
if not isinstance(DirichletDatum, (list, tuple,)):
DirichletDatum = [DirichletDatum,
fenZEROS(self.V.mesh().topology().dim())]
self._DirichletDatum = DirichletDatum
@property
def NeumannDatum(self):
"""Value of g1."""
return self._NeumannDatum
@NeumannDatum.setter
def NeumannDatum(self, NeumannDatum):
self.resetbs()
if not isinstance(NeumannDatum, (list, tuple,)):
NeumannDatum = [NeumannDatum,
fenZEROS(self.V.mesh().topology().dim())]
self._NeumannDatum = NeumannDatum
@property
def RobinDatumG(self):
"""Value of g2."""
return self._RobinDatumG
@RobinDatumG.setter
def RobinDatumG(self, RobinDatumG):
self.resetbs()
if not isinstance(RobinDatumG, (list, tuple,)):
RobinDatumG = [RobinDatumG,
fenZEROS(self.V.mesh().topology().dim())]
self._RobinDatumG = RobinDatumG
@property
def RobinDatumH(self):
"""Value of h."""
return self._RobinDatumH
@RobinDatumH.setter
def RobinDatumH(self, RobinDatumH):
self.resetAs()
if not isinstance(RobinDatumH, (list, tuple,)):
RobinDatumH = [RobinDatumH, fenZERO]
self._RobinDatumH = RobinDatumH
@property
def DirichletBoundary(self):
"""Function handle to DirichletBoundary."""
return self.BCManager.DirichletBoundary
@DirichletBoundary.setter
def DirichletBoundary(self, DirichletBoundary):
self.resetAs()
self.resetbs()
self.BCManager.DirichletBoundary = DirichletBoundary
@property
def NeumannBoundary(self):
"""Function handle to NeumannBoundary."""
return self.BCManager.NeumannBoundary
@NeumannBoundary.setter
def NeumannBoundary(self, NeumannBoundary):
self.resetAs()
self.resetbs()
self.dsToBeSet = True
self.BCManager.NeumannBoundary = NeumannBoundary
@property
def RobinBoundary(self):
"""Function handle to RobinBoundary."""
return self.BCManager.RobinBoundary
@RobinBoundary.setter
def RobinBoundary(self, RobinBoundary):
self.resetAs()
self.resetbs()
self.dsToBeSet = True
self.BCManager.RobinBoundary = RobinBoundary
- def autoSetDS(self):
- """Set FEniCS boundary measure based on boundary function handles."""
- if self.dsToBeSet:
- vbMng(self, "INIT", "Initializing boundary measures.", 20)
- NB = self.NeumannBoundary
- RB = self.RobinBoundary
- boundary_markers = fen.MeshFunction("size_t", self.V.mesh(),
- self.V.mesh().topology().dim() - 1)
- NB.mark(boundary_markers, 0)
- RB.mark(boundary_markers, 1)
- self.ds = fen.Measure("ds", domain = self.V.mesh(),
- subdomain_data = boundary_markers)
- self.dsToBeSet = False
- vbMng(self, "DEL", "Done initializing boundary measures.", 20)
-
def buildEnergyNormForm(self):
"""
Build sparse matrix (in CSR format) representative of scalar product.
"""
vbMng(self, "INIT", "Assembling energy matrix.", 20)
self.energyNormMatrix = elasticNormMatrix(self.V, self.lambda_[0],
self.mu_[0])
vbMng(self, "DEL", "Done assembling energy matrix.", 20)
def buildEnergyNormDualForm(self):
"""
Build sparse matrix (in CSR format) representative of dual scalar
product.
"""
vbMng(self, "INIT", "Assembling energy dual matrix.", 20)
self.energyNormDualMatrix = elasticDualNormMatrix(
self.V, self.lambda_[0], self.mu_[0],
compressRank = self._energyDualNormCompress)
vbMng(self, "DEL", "Done assembling energy dual matrix.", 20)
def buildDualityPairingForm(self):
"""Build sparse matrix (in CSR format) representative of duality."""
vbMng(self, "INIT", "Assembling duality matrix.", 20)
self.dualityMatrix = L2InverseNormMatrix(
self.V, solverType = self._solver,
solverArgs = self._solverArgs,
compressRank = self._dualityCompress)
vbMng(self, "DEL", "Done assembling duality matrix.", 20)
def buildEnergyNormPartialDualForm(self):
"""
Build sparse matrix (in CSR format) representative of dual scalar
product without duality.
"""
vbMng(self, "INIT", "Assembling energy partial dual matrix.", 20)
self.energyNormPartialDualMatrix = elasticDualNormMatrix(
self.V, self.lambda_[0], self.mu_[0],
compressRank = self._energyDualNormCompress,
duality = False)
vbMng(self, "DEL", "Done assembling energy partial dual matrix.", 20)
- def A(self, mu : paramVal = [], der : List[int] = 0) -> ScOp:
- """Assemble (derivative of) operator of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- self.autoSetDS()
- if derI <= 0 and self.As[0] is None:
+ def buildA(self):
+ """Build terms of operator of linear system."""
+ if self.thAs[0] is None: self.thAs = self.getMonomialWeights(self.nAs)
+ if self.As[0] is None:
+ self.autoSetDS()
vbMng(self, "INIT", "Assembling operator term A0.", 20)
DirichletBC0 = fen.DirichletBC(self.V,
fenZEROS(self.V.mesh().topology().dim()),
self.DirichletBoundary)
lambda_Re, lambda_Im = self.lambda_
mu_Re, mu_Im = self.mu_
hRe, hIm = self.RobinDatumH
termNames = ["lambda_", "mu_", "RobinDatumH"]
parsRe = self.iterReduceQuadratureDegree(zip(
[lambda_Re, mu_Re, hRe],
[x + "Real" for x in termNames]))
parsIm = self.iterReduceQuadratureDegree(zip(
[lambda_Im, mu_Re, hIm],
[x + "Imag" for x in termNames]))
epsilon = lambda u: 0.5 * (fen.grad(u) + fen.nabla_grad(u))
sigma = lambda u, l_, m_: (
l_ * fen.div(u) * fen.Identity(u.geometric_dimension())
+ 2. * m_ * epsilon(u))
a0Re = (fen.inner(sigma(self.u, lambda_Re, mu_Re),
epsilon(self.v)) * fen.dx
+ hRe * fen.inner(self.u, self.v) * self.ds(1))
a0Im = (fen.inner(sigma(self.u, lambda_Im, mu_Im),
epsilon(self.v)) * fen.dx
+ hIm * fen.inner(self.u, self.v) * self.ds(1))
self.As[0] = (fenics2Sparse(a0Re, parsRe, DirichletBC0, 1)
+ 1.j * fenics2Sparse(a0Im, parsIm, DirichletBC0, 0))
vbMng(self, "DEL", "Done assembling operator term.", 20)
- return self._assembleA(mu, der, derI)
- def b(self, mu : paramVal = [], der : List[int] = 0,
- homogeneized : bool = False) -> Np1D:
- """Assemble (derivative of) RHS of linear system."""
- mu = self.checkParameter(mu)
- if not hasattr(der, "__len__"): der = [der] * self.npar
- derI = hashD(der)
- nbsTot = self.nbsH if homogeneized else self.nbs
- bs = self.bsH if homogeneized else self.bs
- if homogeneized and self.mu != self.mu0BC:
- self.liftDirichletData(self.mu)
- fenZEROSEff = fenZEROS(self.V.mesh().topology().dim())
- for j in range(derI, nbsTot):
- if bs[j] is None:
- self.autoSetDS()
- vbMng(self, "INIT", "Assembling forcing term b{}.".format(j),
- 20)
- if j == 0:
- u0Re, u0Im = self.DirichletDatum
- fRe, fIm = self.forcingTerm
- g1Re, g1Im = self.NeumannDatum
- g2Re, g2Im = self.RobinDatumG
- else:
- u0Re, u0Im = fenZEROSEff, fenZEROSEff
- fRe, fIm = fenZEROSEff, fenZEROSEff
- g1Re, g1Im = fenZEROSEff, fenZEROSEff
- g2Re, g2Im = fenZEROSEff, fenZEROSEff
- termNames = ["forcingTerm", "NeumannDatum", "RobinDatumG"]
- parsRe = self.iterReduceQuadratureDegree(zip(
- [fRe, g1Re, g2Re],
+ def buildb(self):
+ """Build terms of operator of linear system."""
+ if self.thbs[0] is None:
+ self.thbs = (self.getMonomialWeights(self.nbs)
+ + [None] * (self.homogeneized * self.nAs))
+ if self.bs[0] is None:
+ self.autoSetDS()
+ vbMng(self, "INIT", "Assembling forcing term b0.", 20)
+ u0Re, u0Im = self.DirichletDatum
+ fRe, fIm = self.forcingTerm
+ g1Re, g1Im = self.NeumannDatum
+ g2Re, g2Im = self.RobinDatumG
+ termNames = ["forcingTerm", "NeumannDatum", "RobinDatumG"]
+ parsRe = self.iterReduceQuadratureDegree(zip([fRe, g1Re, g2Re],
[x + "Real" for x in termNames]))
- parsIm = self.iterReduceQuadratureDegree(zip(
- [fIm, g1Im, g2Im],
+ parsIm = self.iterReduceQuadratureDegree(zip([fIm, g1Im, g2Im],
[x + "Imag" for x in termNames]))
- L0Re = (fen.inner(fRe, self.v) * fen.dx
- + fen.inner(g1Re, self.v) * self.ds(0)
- + fen.inner(g2Re, self.v) * self.ds(1))
- L0Im = (fen.inner(fIm, self.v) * fen.dx
- + fen.inner(g1Im, self.v) * self.ds(0)
- + fen.inner(g2Im, self.v) * self.ds(1))
- DBCR = fen.DirichletBC(self.V, u0Re, self.DirichletBoundary)
- DBCI = fen.DirichletBC(self.V, u0Im, self.DirichletBoundary)
- b = (fenics2Vector(L0Re, parsRe, DBCR, 1)
- + 1.j * fenics2Vector(L0Im, parsIm, DBCI, 1))
- if homogeneized:
- Ader = self.A(0, hashI(j, self.npar))
- b -= Ader.dot(self.liftedDirichletDatum)
- if homogeneized:
- self.bsH[j] = b
- else:
- self.bs[j] = b
- vbMng(self, "DEL", "Done assembling forcing term.", 20)
- return self._assembleb(mu, der, derI, homogeneized)
-
+ L0Re = (fen.inner(fRe, self.v) * fen.dx
+ + fen.inner(g1Re, self.v) * self.ds(0)
+ + fen.inner(g2Re, self.v) * self.ds(1))
+ L0Im = (fen.inner(fIm, self.v) * fen.dx
+ + fen.inner(g1Im, self.v) * self.ds(0)
+ + fen.inner(g2Im, self.v) * self.ds(1))
+ DBCR = fen.DirichletBC(self.V, u0Re, self.DirichletBoundary)
+ DBCI = fen.DirichletBC(self.V, u0Im, self.DirichletBoundary)
+ self.bs[0] = (fenics2Vector(L0Re, parsRe, DBCR, 1)
+ + 1.j * fenics2Vector(L0Im, parsIm, DBCI, 1))
+ vbMng(self, "DEL", "Done assembling forcing term.", 20)
+ self.setbHomogeneized()
diff --git a/rrompy/parameter/parameter_list.py b/rrompy/parameter/parameter_list.py
index ffaef89..93d514a 100644
--- a/rrompy/parameter/parameter_list.py
+++ b/rrompy/parameter/parameter_list.py
@@ -1,221 +1,223 @@
# 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 itertools import product as iterprod
from copy import deepcopy as copy
from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
from rrompy.utilities.base.types import Np2D
__all__ = ['parameterList', 'emptyParameterList', 'checkParameterList']
def checkParameterList(mu, npar = None):
if not isinstance(mu, (parameterList,)):
mu = parameterList(mu, npar)
else:
if npar is not None:
RROMPyAssert(mu.shape[1], npar, "Number of parameters")
mu = copy(mu)
return mu, len(mu) <= 1
def checkParameter(mu, npar = None):
muL, wasPar = checkParameterList(mu, npar)
if not wasPar:
muL, wasPar = checkParameterList([mu], npar)
if not wasPar:
raise RROMPyException(("Only single parameter allowed. No "
"parameter lists here."))
return muL
def emptyParameterList():
return parameterList([[]])
def addMemberFromNumpyArray(self, fieldName):
def objFunc(self, other):
if not isinstance(other, (self.__class__,)):
other = parameterList(other, self.shape[1])
return parameterList(getattr(np.ndarray, fieldName)(self.data,
other.data))
setattr(self.__class__, fieldName, objFunc)
def objIFunc(self, other):
self.data = getattr(self.__class__, fieldName)(self, other).data
setattr(self.__class__, "__i" + fieldName[2:], objIFunc)
class parameterList:
"""HERE"""
__all__ += [pre + post for pre, post in iterprod(["__", "__i"],
["__add__", "__sub__", "__mul__", "__div__",
"__truediv__", "__floordiv__", "__pow__"])]
def __init__(self, data:Np2D, lengthCheck : int = None):
if not hasattr(data, "__len__"): data = [data]
elif isinstance(data, (self.__class__,)): data = data.data
elif isinstance(data, (tuple,)): data = list(data)
if (isinstance(data, (list,)) and len(data) > 0
and isinstance(data[0], (tuple,))):
data = [list(x) for x in data]
self.data = np.array(data, ndmin = 1, copy = 1)
if self.data.ndim == 1:
self.data = self.data[:, None]
if np.size(self.data) > 0:
self.data = self.data.reshape((len(self), -1))
if self.shape[0] * self.shape[1] == 0:
lenEff = 0 if lengthCheck is None else lengthCheck
self.reset((0, lenEff), self.dtype)
if lengthCheck is not None:
if lengthCheck != 1 and self.shape == (lengthCheck, 1):
self.data = self.data.T
RROMPyAssert(self.shape[1], lengthCheck, "Number of parameters")
for fieldName in ["__add__", "__sub__", "__mul__", "__div__",
"__truediv__", "__floordiv__", "__pow__"]:
addMemberFromNumpyArray(self, fieldName)
def __len__(self):
return self.shape[0]
def __str__(self):
- if len(self) <= 3:
- selfstr = str(self.data)
+ if len(self) == 0:
+ selfstr = "[]"
+ elif len(self) <= 3:
+ selfstr = "[{}]".format(" ".join([str(x) for x in self.data]))
else:
selfstr = "[{} ..({}).. {}]".format(self[0], len(self) - 2,
self[-1])
return selfstr
def __repr__(self):
return repr(self.data)
@property
def shape(self):
return self.data.shape
@property
def re(self):
return parameterList(np.real(self.data))
@property
def im(self):
return parameterList(np.imag(self.data))
@property
def abs(self):
return parameterList(np.abs(self.data))
@property
def angle(self):
return parameterList(np.angle(self.data))
@property
def conj(self):
return parameterList(np.conj(self.data))
@property
def dtype(self):
return self.data.dtype
def __getitem__(self, key):
return self.data[key]
def __call__(self, key, idx = None):
if idx is None:
return self.data[:, key]
return self[key, idx]
def __setitem__(self, key, value):
if isinstance(key, (tuple, list,)):
RROMPyAssert(len(key), len(value), "Slice length")
for k, val in zip(key, value):
self[k] = val
else:
self.data[key] = value
def __eq__(self, other):
if not hasattr(other, "shape") or self.shape != other.shape:
return False
if isinstance(other, self.__class__):
other = other.data
return np.allclose(self.data, other)
def __contains__(self, item):
return next((x for x in self if np.allclose(x[0], item)), -1) != -1
def __iter__(self):
return iter([parameterList([x]) for x in self.data])
def __copy__(self):
return parameterList(self.data)
def __deepcopy__(self, memo):
return parameterList(copy(self.data, memo))
def __neg__(self):
return parameterList(-self.data)
def __pos__(self):
return copy(self)
def reset(self, size, dtype = complex):
self.data = np.empty(size, dtype = dtype)
self.data[:] = np.nan
def append(self, items):
if isinstance(items, self.__class__):
items = items.data
else:
items = np.array(items, ndmin = 2)
if len(self) == 0:
self.data = parameterList(items).data
else:
self.data = np.append(self.data, items, axis = 0)
def pop(self, idx = -1):
self.data = np.delete(self.data, idx, axis = 0)
def find(self, item):
if len(self) == 0: return None
return next((j for j in range(len(self))
if np.allclose(self[j], item)), None)
def findall(self, item):
if len(self) == 0: return []
return [j for j in range(len(self)) if np.allclose(self[j], item)]
def sort(self, overwrite = False, *args, **kwargs):
dataT = np.array([tuple(x[0]) for x in self],
dtype = [(str(j), self.dtype)
for j in range(self.shape[1])])
sortedP = parameterList([list(x) for x in np.sort(dataT, *args,
**kwargs)])
if overwrite: self.data = sortedP.data
return sortedP
def unique(self, overwrite = False, *args, **kwargs):
dataT = np.array([tuple(x[0]) for x in self],
dtype = [(str(j), self.dtype)
for j in range(self.shape[1])])
uniqueT = np.unique(dataT, *args, **kwargs)
if isinstance(uniqueT, (tuple,)):
extraT = uniqueT[1:]
uniqueT = uniqueT[0]
else: extraT = ()
uniqueP = parameterList([list(x) for x in uniqueT])
if overwrite: self.data = uniqueP.data
uniqueP = (uniqueP,) + extraT
if len(uniqueP) == 1: return uniqueP[0]
return uniqueP
diff --git a/rrompy/parameter/parameter_sampling/fft_sampler.py b/rrompy/parameter/parameter_sampling/fft_sampler.py
index 4199886..bd6a9b7 100644
--- a/rrompy/parameter/parameter_sampling/fft_sampler.py
+++ b/rrompy/parameter/parameter_sampling/fft_sampler.py
@@ -1,48 +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 .
#
import numpy as np
from .generic_sampler import GenericSampler
-from rrompy.utilities.base.types import List, paramList
+from rrompy.utilities.base.types import paramList
from rrompy.utilities.numerical import lowDiscrepancy, kroneckerer
from rrompy.parameter import checkParameterList
__all__ = ['FFTSampler']
class FFTSampler(GenericSampler):
"""Generator of FFT-type sample points on scaled roots of unity."""
- def generatePoints(self, n:List[int], reorder : bool = True) -> paramList:
+ def generatePoints(self, n:int, reorder : bool = True) -> paramList:
"""Array of sample points."""
- if not hasattr(n, "__len__"): n = [n]
- super().generatePoints(n)
- nleft, nright = 1, np.prod(n)
+ n1d = int(np.ceil(n ** (1. / self.npar)))
+ nleft, nright = 1, n1d ** self.npar
xmat = np.empty((nright, self.npar), dtype = np.complex)
for d in range(self.npar):
- nright //= n[d]
+ nright //= n1d
a = self.lims(0, d) ** self.scalingExp[d]
b = self.lims(1, d) ** self.scalingExp[d]
- c, r = (a + b) / 2., np.abs(a - b) / 2.
- xd = c + r * np.exp(1.j * np.linspace(0, 2 * np.pi, n[d] + 1)[:-1])
+ c, r = (a + b) / 2., (a - b) / 2.
+ xd = c + r * np.exp(1.j * np.linspace(0, 2 * np.pi, n1d + 1)[:-1])
xd **= 1. / self.scalingExp[d]
+ if n1d > 1 and reorder:
+ fejerOrdering = [n1d - 1] + lowDiscrepancy(n1d - 1)
+ xd = xd[fejerOrdering]
xmat[:, d] = kroneckerer(xd, nleft, nright)
- nleft *= n[d]
- if reorder:
- xmat = xmat[lowDiscrepancy(np.prod(n)), :]
+ nleft *= n1d
x = checkParameterList(xmat, self.npar)[0]
return x
diff --git a/rrompy/parameter/parameter_sampling/generic_sampler.py b/rrompy/parameter/parameter_sampling/generic_sampler.py
index 30f631a..9bb61db 100644
--- a/rrompy/parameter/parameter_sampling/generic_sampler.py
+++ b/rrompy/parameter/parameter_sampling/generic_sampler.py
@@ -1,79 +1,77 @@
# 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 abc import abstractmethod
from rrompy.utilities.base.types import List, paramList
from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
from rrompy.parameter import checkParameterList
__all__ = ['GenericSampler']
class GenericSampler:
"""ABSTRACT. Generic generator of sample points."""
def __init__(self, lims:paramList, scalingExp : List[float] = None):
self.lims = lims
self.scalingExp = scalingExp
def name(self) -> str:
return self.__class__.__name__
def __str__(self) -> str:
return "{}[{}_{}]".format(self.name(), self.lims[0], self.lims[1])
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
def __eq__(self, other) -> bool:
return self.__dict__ == other.__dict__
@property
def npar(self):
"""Number of parameters."""
return self._lims.shape[1]
@property
def lims(self):
"""Value of lims."""
return self._lims
@lims.setter
def lims(self, lims):
lims = checkParameterList(lims)[0]
if len(lims) != 2:
raise RROMPyException("2 limits must be specified.")
self._lims = lims
@property
def scalingExp(self):
"""Value of scalingExp."""
return self._scalingExp
@scalingExp.setter
def scalingExp(self, scalingExp):
if scalingExp is None:
scalingExp = [1.] * self.npar
if not hasattr(scalingExp, "__len__"): scalingExp = [scalingExp]
RROMPyAssert(self.npar, len(scalingExp), "Number of scaling terms")
self._scalingExp = scalingExp
@abstractmethod
- def generatePoints(self, n:List[int]) -> paramList:
+ def generatePoints(self, n:int) -> paramList:
"""Array of points."""
- if not hasattr(n, "__len__"): n = [n]
- RROMPyAssert(self.npar, len(n), "Point number")
pass
diff --git a/rrompy/parameter/parameter_sampling/manual_sampler.py b/rrompy/parameter/parameter_sampling/manual_sampler.py
index 42aa93d..f381d45 100644
--- a/rrompy/parameter/parameter_sampling/manual_sampler.py
+++ b/rrompy/parameter/parameter_sampling/manual_sampler.py
@@ -1,61 +1,60 @@
# 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 .generic_sampler import GenericSampler
from rrompy.utilities.base.types import List, paramList
from rrompy.parameter import checkParameterList
__all__ = ['ManualSampler']
class ManualSampler(GenericSampler):
"""Manual generator of sample points."""
def __init__(self, lims:paramList, points:paramList,
scalingExp : List[float] = None):
super().__init__(lims = lims, scalingExp = scalingExp)
self.points = points
@property
def points(self):
"""Value of points."""
return self._points
@points.setter
def points(self, points):
points = checkParameterList(points, self.npar)[0]
self._points = points
def __str__(self) -> str:
return "{}[{}]".format(self.name(), "_".join(map(str, self.points)))
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
def generatePoints(self, n:int) -> paramList:
"""Array of sample points."""
- if hasattr(n, "__len__"): n = n[0]
if n > len(self.points):
pts = copy(self.points)
for j in range(int(np.ceil(n / len(self.points)))):
pts.append(self.points)
else:
pts = self.points
x = checkParameterList(pts[list(range(n))], self.npar)[0]
return x
diff --git a/rrompy/parameter/parameter_sampling/quadrature_sampler.py b/rrompy/parameter/parameter_sampling/quadrature_sampler.py
index a08adf8..fe65111 100644
--- a/rrompy/parameter/parameter_sampling/quadrature_sampler.py
+++ b/rrompy/parameter/parameter_sampling/quadrature_sampler.py
@@ -1,83 +1,86 @@
# 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 .generic_sampler import GenericSampler
from rrompy.utilities.base.types import List, paramList
from rrompy.utilities.exception_manager import RROMPyException
from rrompy.utilities.numerical import lowDiscrepancy, kroneckerer
from rrompy.parameter import checkParameterList
__all__ = ['QuadratureSampler']
class QuadratureSampler(GenericSampler):
"""Generator of quadrature sample points."""
- allowedKinds = ["UNIFORM", "CHEBYSHEV", "GAUSSLEGENDRE"]
+ _allowedKinds = ["UNIFORM", "CHEBYSHEV", "EXTENDEDCHEBYSHEV",
+ "GAUSSLEGENDRE", "EXTENDEDGAUSSLEGENDRE"]
def __init__(self, lims:paramList, kind : str = "UNIFORM",
scalingExp : List[float] = None):
super().__init__(lims = lims, scalingExp = scalingExp)
self.kind = kind
def __str__(self) -> str:
return "{}_{}".format(super().__str__(), self.kind)
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
@property
def kind(self):
"""Value of kind."""
return self._kind
@kind.setter
def kind(self, kind):
- if kind.upper() not in self.allowedKinds:
+ if kind.upper() not in self._allowedKinds:
raise RROMPyException("Generator kind not recognized.")
self._kind = kind.upper()
- def generatePoints(self, n:List[int], reorder : bool = True) -> paramList:
+ def generatePoints(self, n:int, reorder : bool = True) -> paramList:
"""Array of sample points."""
- if not hasattr(n, "__len__"): n = [n]
- super().generatePoints(n)
- nleft, nright = 1, np.prod(n)
+ n1d = int(np.ceil(n ** (1. / self.npar)))
+ nleft, nright = 1, n1d ** self.npar
xmat = np.empty((nright, self.npar), dtype = self.lims.dtype)
for d in range(self.npar):
- nright //= n[d]
+ nright //= n1d
a = self.lims(0, d) ** self.scalingExp[d]
b = self.lims(1, d) ** self.scalingExp[d]
c, r = (a + b) / 2., (a - b) / 2.
- dAbs = 2. * np.abs(r)
if self.kind == "UNIFORM":
- xd = np.linspace(a, b, n[d])
- elif self.kind == "CHEBYSHEV":
- nodes, _ = np.polynomial.chebyshev.chebgauss(n[d])
+ xd = np.linspace(a, b, n1d)
+ elif self.kind in ["CHEBYSHEV", "EXTENDEDCHEBYSHEV"]:
+ nodes = np.polynomial.chebyshev.chebgauss(n1d)[0]
+ if n1d > 1 and self.kind == "EXTENDEDCHEBYSHEV":
+ nodes /= nodes[0]
+ xd = c + r * nodes
+ elif self.kind in ["GAUSSLEGENDRE", "EXTENDEDGAUSSLEGENDRE"]:
+ nodes = np.polynomial.legendre.leggauss(n1d)[0][::-1]
+ if n1d > 1 and self.kind == "EXTENDEDCHEBYSHEV":
+ nodes /= nodes[0]
xd = c + r * nodes
- elif self.kind == "GAUSSLEGENDRE":
- nodes, _ = np.polynomial.legendre.leggauss(n[d])
- xd = c + r * nodes[::-1]
xd **= 1. / self.scalingExp[d]
xmat[:, d] = kroneckerer(xd, nleft, nright)
- nleft *= n[d]
- nright = np.prod(n)
+ nleft *= n1d
+ nright = n1d ** self.npar
if nright > 1 and reorder:
fejerOrdering = [nright - 1] + lowDiscrepancy(nright - 1)
xmat = xmat[fejerOrdering, :]
x = checkParameterList(xmat, self.npar)[0]
return x
diff --git a/rrompy/parameter/parameter_sampling/quadrature_sampler_total.py b/rrompy/parameter/parameter_sampling/quadrature_sampler_total.py
index 99d5cf3..1a35f3d 100644
--- a/rrompy/parameter/parameter_sampling/quadrature_sampler_total.py
+++ b/rrompy/parameter/parameter_sampling/quadrature_sampler_total.py
@@ -1,60 +1,56 @@
# 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 scipy.special import binom, factorial as fact
from .quadrature_sampler import QuadratureSampler
from rrompy.utilities.base.types import paramList
from rrompy.utilities.numerical import lowDiscrepancy
from rrompy.parameter import checkParameterList
__all__ = ['QuadratureSamplerTotal']
class QuadratureSamplerTotal(QuadratureSampler):
"""
Generator of quadrature sample points for total degree polynomial
computations.
"""
def generatePoints(self, n:int, reorder : bool = True) -> paramList:
"""Array of sample points."""
- if hasattr(n, "__len__"): n = n[0]
d = self.npar
n1d = int((fact(d) * n) ** (1. / d))
while binom(n1d + d - 1, d) > n: n1d -= 1
- x = super().generatePoints([n1d] * d, reorder = False)
+ x = super().generatePoints(n1d ** d, reorder = reorder)
nTot = n1d ** d
indicesBase = np.zeros(nTot, dtype = int)
idxBase = [x + 1 for x in lowDiscrepancy(n1d - 1, inverse = True)]
linearIdxs = np.array(idxBase + [0])
nleft, nright = 1, nTot
for j in range(d):
nright //= n1d
kronIn = np.repeat(linearIdxs, nright)
indicesBase += np.tile(kronIn, nleft)
nleft *= n1d
keepIdxs = np.zeros(nTot, dtype = bool)
keepIdxs[indicesBase < n1d] = True
xmat = x.data[keepIdxs, :]
- if reorder:
- fejerTot = np.array([nTot - 1] + list(lowDiscrepancy(nTot - 1)))
- xmat = xmat[np.argsort(np.argsort(fejerTot[keepIdxs])), :]
x = checkParameterList(xmat, d)[0]
return x
diff --git a/rrompy/parameter/parameter_sampling/random_sampler.py b/rrompy/parameter/parameter_sampling/random_sampler.py
index 68625d2..6d1cd07 100644
--- a/rrompy/parameter/parameter_sampling/random_sampler.py
+++ b/rrompy/parameter/parameter_sampling/random_sampler.py
@@ -1,72 +1,71 @@
# 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 .generic_sampler import GenericSampler
from rrompy.utilities.numerical import haltonGenerate, sobolGenerate
from rrompy.utilities.base.types import List, paramList
from rrompy.utilities.exception_manager import RROMPyException
from rrompy.parameter import checkParameterList
__all__ = ['RandomSampler']
class RandomSampler(GenericSampler):
"""Generator of quadrature sample points."""
allowedKinds = ["UNIFORM", "HALTON", "SOBOL"]
def __init__(self, lims:paramList, kind : str = "UNIFORM",
scalingExp : List[float] = None, seed : int = 42):
super().__init__(lims = lims, scalingExp = scalingExp)
self.kind = kind
self.seed = seed
def __str__(self) -> str:
return "{}_{}".format(super().__str__(), self.kind)
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
@property
def kind(self):
"""Value of kind."""
return self._kind
@kind.setter
def kind(self, kind):
if kind.upper() not in self.allowedKinds:
raise RROMPyException("Generator kind not recognized.")
self._kind = kind.upper()
def generatePoints(self, n:int) -> paramList:
"""Array of quadrature points."""
- if hasattr(n, "__len__"): n = n[0]
if self.kind == "UNIFORM":
np.random.seed(self.seed)
xmat = np.random.uniform(size = (n, self.npar))
elif self.kind == "HALTON":
xmat = haltonGenerate(self.npar, n, self.seed)
else:
xmat = sobolGenerate(self.npar, n, self.seed)
for d in range(self.npar):
a = self.lims(0, d) ** self.scalingExp[d]
b = self.lims(1, d) ** self.scalingExp[d]
xmat[:, d] = a + (b - a) * xmat[:, d]
xmat[:, d] **= 1. / self.scalingExp[d]
x = checkParameterList(xmat, self.npar)[0]
return x
diff --git a/rrompy/reduction_methods/base/generic_approximant.py b/rrompy/reduction_methods/base/generic_approximant.py
index 12718ee..7351d4d 100644
--- a/rrompy/reduction_methods/base/generic_approximant.py
+++ b/rrompy/reduction_methods/base/generic_approximant.py
@@ -1,886 +1,853 @@
# 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 abc import abstractmethod
import numpy as np
from itertools import product as iterprod
from copy import deepcopy as copy
from os import remove as osrm
from rrompy.sampling.standard import (SamplingEngineStandard,
SamplingEngineStandardPOD)
from rrompy.utilities.base.types import (Np1D, DictAny, HFEng, List, Tuple,
ListAny, strLst, paramVal, paramList,
sampList)
from rrompy.utilities.base import (purgeDict, verbosityManager as vbMng,
getNewFilename)
from rrompy.utilities.exception_manager import (RROMPyException, RROMPyAssert,
RROMPy_READY, RROMPy_FRAGILE)
from rrompy.utilities.base import pickleDump, pickleLoad
from rrompy.parameter import (emptyParameterList, checkParameter,
checkParameterList)
from rrompy.sampling import sampleList, emptySampleList
__all__ = ['GenericApproximant']
def addNormFieldToClass(self, fieldName):
- def objFunc(self, mu:paramList, *args, homogeneized : bool = False,
- **kwargs) -> Np1D:
- uV = getattr(self.__class__, "get" + fieldName)(self, mu, homogeneized)
+ def objFunc(self, mu:paramList, *args, **kwargs) -> Np1D:
+ uV = getattr(self.__class__, "get" + fieldName)(self, mu)
val = self.HFEngine.norm(uV, *args, **kwargs)
return val
setattr(self.__class__, "norm" + fieldName, objFunc)
def addNormDualFieldToClass(self, fieldName):
- def objFunc(self, mu:paramList, *args, homogeneized : bool = False,
- duality : bool = True, **kwargs) -> Np1D:
- uV = getattr(self.__class__, "get" + fieldName)(self, mu, homogeneized,
- duality)
+ def objFunc(self, mu:paramList, *args, **kwargs) -> Np1D:
+ uV = getattr(self.__class__, "get" + fieldName)(self, mu)
+ if "dual" not in kwargs.keys(): kwargs["dual"] = True
val = self.HFEngine.norm(uV, *args, **kwargs)
return val
setattr(self.__class__, "norm" + fieldName, objFunc)
def addPlotFieldToClass(self, fieldName):
- def objFunc(self, mu:paramList, *args, homogeneized : bool = False,
- **kwargs):
- uV = getattr(self.__class__, "get" + fieldName)(self, mu, homogeneized)
+ def objFunc(self, mu:paramList, *args, **kwargs):
+ uV = getattr(self.__class__, "get" + fieldName)(self, mu)
+ kwargsCopy = copy(kwargs)
+ for j, u in enumerate(uV):
+ if "name" in kwargs.keys():
+ kwargsCopy["name"] = kwargs["name"] + str(j)
+ self.HFEngine.plot(u, *args, **kwargs)
+ setattr(self.__class__, "plot" + fieldName, objFunc)
+
+def addPlotDualFieldToClass(self, fieldName):
+ def objFunc(self, mu:paramList, *args, **kwargs):
+ uV = getattr(self.__class__, "get" + fieldName)(self, mu,
+ duality = False)
kwargsCopy = copy(kwargs)
for j, u in enumerate(uV):
if "name" in kwargs.keys():
kwargsCopy["name"] = kwargs["name"] + str(j)
self.HFEngine.plot(u, *args, **kwargs)
setattr(self.__class__, "plot" + fieldName, objFunc)
def addOutParaviewFieldToClass(self, fieldName):
- def objFunc(self, mu:paramVal, *args, homogeneized : bool = False,
- **kwargs):
+ def objFunc(self, mu:paramVal, *args, **kwargs):
if not hasattr(self.HFEngine, "outParaview"):
raise RROMPyException(("High fidelity engine cannot output to "
"Paraview."))
- uV = getattr(self.__class__, "get" + fieldName)(self, mu, homogeneized)
+ uV = getattr(self.__class__, "get" + fieldName)(self, mu)
kwargsCopy = copy(kwargs)
for j, u in enumerate(uV):
if "name" in kwargs.keys():
kwargsCopy["name"] = kwargs["name"] + str(j)
self.HFEngine.outParaview(u, *args, **kwargsCopy)
setattr(self.__class__, "outParaview" + fieldName, objFunc)
def addOutParaviewTimeDomainFieldToClass(self, fieldName):
- def objFunc(self, mu:paramVal, *args,
- homogeneized : bool = False, **kwargs):
+ def objFunc(self, mu:paramVal, *args, **kwargs):
if not hasattr(self.HFEngine, "outParaviewTimeDomain"):
raise RROMPyException(("High fidelity engine cannot output to "
"Paraview."))
- uV = getattr(self.__class__, "get" + fieldName)(self, mu, homogeneized)
+ uV = getattr(self.__class__, "get" + fieldName)(self, mu)
omega = args.pop(0) if len(args) > 0 else np.real(mu)
kwargsCopy = copy(kwargs)
for j, u in enumerate(uV):
if "name" in kwargs.keys():
kwargsCopy["name"] = kwargs["name"] + str(j)
self.HFEngine.outParaviewTimeDomain(u, omega, *args,
**kwargsCopy)
setattr(self.__class__, "outParaviewTimeDomain" + fieldName, objFunc)
class GenericApproximant:
"""
ABSTRACT
ROM approximant computation for parametric problems.
Args:
HFEngine: HF problem solver.
mu0(optional): Default parameter. Defaults to 0.
approxParameters(optional): Dictionary containing values for main
parameters of approximant. Recognized keys are:
- 'POD': whether to compute POD of snapshots; defaults to True;
- 'S': total number of samples current approximant relies upon.
Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. Defaults
- to False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
trainedModel: Trained model evaluator.
mu0: Default parameter.
- homogeneized: Whether to homogeneize Dirichlet BCs.
approxParameters: Dictionary containing values for main parameters of
approximant. Recognized keys are in parameterList{Soft,Critical}.
parameterListSoft: Recognized keys of soft approximant parameters:
- 'POD': whether to compute POD of snapshots.
parameterListCritical: Recognized keys of critical approximant
parameters:
- 'S': total number of samples current approximant relies upon.
verbosity: Verbosity level.
POD: Whether to compute POD of snapshots.
S: Number of solution snapshots over which current approximant is
based upon.
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.
"""
__all__ += [ftype + dtype for ftype, dtype in iterprod(
["norm", "plot", "outParaview", "outParaviewTimeDomain"],
["HF", "RHS", "Approx", "Res", "Err"])]
def __init__(self, HFEngine:HFEng, mu0 : paramVal = None,
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
+ approxParameters : DictAny = {}, verbosity : int = 10,
+ timestamp : bool = True):
self._preInit()
self._mode = RROMPy_READY
self.verbosity = verbosity
self.timestamp = timestamp
vbMng(self, "INIT",
"Initializing engine of type {}.".format(self.name()), 10)
self._HFEngine = HFEngine
self.trainedModel = None
self.lastSolvedHF = emptyParameterList()
self.uHF = emptySampleList()
- self._addParametersToList(["POD"], [True], ["S"], [[1]])
+ self._addParametersToList(["POD"], [True], ["S"], [1])
if mu0 is None:
if hasattr(self.HFEngine, "mu0"):
self.mu0 = checkParameter(self.HFEngine.mu0)
else:
raise RROMPyException(("Center of approximation cannot be "
"inferred from HF engine. Parameter "
"required"))
else:
self.mu0 = checkParameter(mu0, self.HFEngine.npar)
self.resetSamples()
- self.homogeneized = homogeneized
self.approxParameters = approxParameters
self._postInit()
### add norm{HF,Approx,Err} methods
"""
Compute norm of * at arbitrary parameter.
Args:
mu: Target parameter.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
Returns:
Target norm of *.
"""
for objName in ["HF", "Err"]:
addNormFieldToClass(self, objName)
if not hasattr(self, "normApprox"):
addNormFieldToClass(self, "Approx")
### add norm{RHS,Res} methods
"""
Compute norm of * at arbitrary parameter.
Args:
mu: Target parameter.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
- duality(optional): Whether to compute duality of object.
Returns:
Target norm of *.
"""
for objName in ["RHS", "Res"]:
addNormDualFieldToClass(self, objName)
- ### add plot{HF,RHS,Approx,Res,Err} methods
+ ### add plot{HF,Approx,Err} methods
"""
Do some nice plots of * at arbitrary parameter.
Args:
mu: Target parameter.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
show(optional): Whether to show figure. Defaults to True.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
- for objName in ["HF", "RHS", "Approx", "Res", "Err"]:
+ for objName in ["HF", "Approx", "Err"]:
addPlotFieldToClass(self, objName)
+ ### add plot{RHS,Res} methods
+ """
+ Do some nice plots of * at arbitrary parameter.
+
+ Args:
+ mu: Target parameter.
+ name(optional): Name to be shown as title of the plots. Defaults to
+ 'u'.
+ what(optional): Which plots to do. If list, can contain 'ABS',
+ 'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
+ Defaults to 'ALL'.
+ save(optional): Where to save plot(s). Defaults to None, i.e. no
+ saving.
+ saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+ saveDPI(optional): DPI for saved plot(s). Defaults to 100.
+ show(optional): Whether to show figure. Defaults to True.
+ figspecs(optional key args): Optional arguments for matplotlib
+ figure creation.
+ """
+ for objName in ["RHS", "Res"]:
+ addPlotDualFieldToClass(self, objName)
+
### add outParaview{HF,RHS,Approx,Res,Err} methods
"""
Output * to ParaView file.
Args:
mu: Target parameter.
name(optional): Base name to be used for data output.
filename(optional): Name of output file.
time(optional): Timestamp.
what(optional): Which plots to do. If list, can contain 'MESH',
'ABS', 'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard
'ALL'. Defaults to 'ALL'.
forceNewFile(optional): Whether to create new output file.
filePW(optional): Fenics File entity (for time series).
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
"""
for objName in ["HF", "RHS", "Approx", "Res", "Err"]:
addOutParaviewFieldToClass(self, objName)
### add outParaviewTimeDomain{HF,RHS,Approx,Res,Err} methods
"""
Output * to ParaView file, converted to time domain.
Args:
mu: Target parameter.
omega(optional): frequency.
timeFinal(optional): final time of simulation.
periodResolution(optional): number of time steps per period.
name(optional): Base name to be used for data output.
filename(optional): Name of output file.
forceNewFile(optional): Whether to create new output file.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
"""
for objName in ["HF", "RHS", "Approx", "Res", "Err"]:
addOutParaviewTimeDomainFieldToClass(self, objName)
def _preInit(self):
if not hasattr(self, "depth"): self.depth = 0
else: self.depth += 1
@property
def parameterList(self):
"""Value of parameterListSoft + parameterListCritical."""
return self.parameterListSoft + self.parameterListCritical
def _addParametersToList(self, whatSoft:strLst, defaultSoft:ListAny,
whatCritical : strLst = [],
defaultCritical : ListAny = [],
toBeExcluded : strLst = []):
if not hasattr(self, "parameterToBeExcluded"):
self.parameterToBeExcluded = []
self.parameterToBeExcluded = toBeExcluded + self.parameterToBeExcluded
if not hasattr(self, "parameterListSoft"):
self.parameterListSoft = []
if not hasattr(self, "parameterDefaultSoft"):
self.parameterDefaultSoft = {}
if not hasattr(self, "parameterListCritical"):
self.parameterListCritical = []
if not hasattr(self, "parameterDefaultCritical"):
self.parameterDefaultCritical = {}
for j, what in enumerate(whatSoft):
if what not in self.parameterToBeExcluded:
self.parameterListSoft = [what] + self.parameterListSoft
self.parameterDefaultSoft[what] = defaultSoft[j]
for j, what in enumerate(whatCritical):
if what not in self.parameterToBeExcluded:
self.parameterListCritical = ([what]
+ self.parameterListCritical)
self.parameterDefaultCritical[what] = defaultCritical[j]
def _postInit(self):
if self.depth == 0:
vbMng(self, "DEL", "Done initializing.", 10)
del self.depth
else: self.depth -= 1
def name(self) -> str:
return self.__class__.__name__
def __str__(self) -> str:
return self.name()
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
def setupSampling(self):
"""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:
SamplingEngine = SamplingEngineStandardPOD
else:
SamplingEngine = SamplingEngineStandard
self.samplingEngine = SamplingEngine(self.HFEngine,
- verbosity = self.verbosity,
- allowRepeatedSamples = True)
+ verbosity = self.verbosity)
@property
def HFEngine(self):
"""Value of HFEngine."""
return self._HFEngine
@HFEngine.setter
def HFEngine(self, HFEngine):
raise RROMPyException("Cannot change HFEngine.")
@property
def mu0(self):
"""Value of mu0."""
return self._mu0
@mu0.setter
def mu0(self, mu0):
mu0 = checkParameter(mu0)
if not hasattr(self, "_mu0") or mu0 != self.mu0:
self.resetSamples()
self._mu0 = mu0
@property
def npar(self):
"""Number of parameters."""
return self.mu0.shape[1]
@property
def approxParameters(self):
"""Value of approximant parameters."""
return self._approxParameters
@approxParameters.setter
def approxParameters(self, approxParams):
if not hasattr(self, "approxParameters"):
self._approxParameters = {}
approxParameters = purgeDict(approxParams, self.parameterList,
dictname = self.name() + ".approxParameters",
baselevel = 1)
keyList = list(approxParameters.keys())
for key in self.parameterListCritical:
if key in keyList:
setattr(self, "_" + key, self.parameterDefaultCritical[key])
for key in self.parameterListSoft:
if key in keyList:
setattr(self, "_" + key, self.parameterDefaultSoft[key])
fragile = False
for key in self.parameterListCritical:
if key in keyList:
val = approxParameters[key]
else:
val = getattr(self, "_" + key, None)
if val is None:
val = self.parameterDefaultCritical[key]
getattr(self.__class__, key, None).fset(self, val)
fragile = fragile or val is None
for key in self.parameterListSoft:
if key in keyList:
val = approxParameters[key]
else:
val = getattr(self, "_" + key, None)
if val is None:
val = self.parameterDefaultSoft[key]
getattr(self.__class__, key, None).fset(self, val)
if fragile:
self._mode = RROMPy_FRAGILE
@property
def POD(self):
"""Value of POD."""
return self._POD
@POD.setter
def POD(self, POD):
if hasattr(self, "_POD"): PODold = self.POD
else: PODold = -1
self._POD = POD
self._approxParameters["POD"] = self.POD
if PODold != self.POD:
self.samplingEngine = None
self.resetSamples()
@property
def S(self):
"""Value of S."""
return self._S
@S.setter
def S(self, S):
- if not hasattr(S, "__len__"): S = [S]
- if any([s <= 0 for s in S]):
- raise RROMPyException("S must be positive.")
- if hasattr(self, "_S") and self._S is not None: Sold = tuple(self.S)
+ if S <= 0: raise RROMPyException("S must be positive.")
+ if hasattr(self, "_S") and self._S is not None: Sold = self.S
else: Sold = -1
self._S = S
self._approxParameters["S"] = self.S
- if Sold != tuple(self.S):
- self.resetSamples()
-
- @property
- def homogeneized(self):
- """Value of homogeneized."""
- return self._homogeneized
- @homogeneized.setter
- def homogeneized(self, homogeneized):
- if not hasattr(self, "_homogeneized"):
- self._homogeneized = None
- if homogeneized != self.homogeneized:
- self._homogeneized = homogeneized
- self.resetSamples()
+ if Sold != self.S: self.resetSamples()
@property
def trainedModel(self):
"""Value of trainedModel."""
return self._trainedModel
@trainedModel.setter
def trainedModel(self, trainedModel):
self._trainedModel = trainedModel
if self._trainedModel is not None:
self._trainedModel.lastSolvedApproxReduced = emptyParameterList()
self._trainedModel.lastSolvedApprox = emptyParameterList()
self.lastSolvedApproxReduced = emptyParameterList()
self.lastSolvedApprox = emptyParameterList()
self.uApproxReduced = emptySampleList()
self.uApprox = emptySampleList()
def resetSamples(self):
if hasattr(self, "samplingEngine") and self.samplingEngine is not None:
self.samplingEngine.resetHistory()
else:
self.setupSampling()
self._mode = RROMPy_READY
def plotSamples(self, warping : List[callable] = None, name : str = "u",
save : str = None, what : strLst = 'all',
saveFormat : str = "eps", saveDPI : int = 100,
show : bool = True, plotArgs : dict = {}, **figspecs):
"""
Do some nice plots of the samples.
Args:
warping(optional): Domain warping functions.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
show(optional): Whether to show figure. Defaults to True.
plotArgs(optional): Optional arguments for fen/pyplot.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
RROMPyAssert(self._mode, message = "Cannot plot samples.")
self.samplingEngine.plotSamples(warping, name, save, what, saveFormat,
saveDPI, show, plotArgs, **figspecs)
def outParaviewSamples(self, name : str = "u", filename : str = "out",
times : Np1D = None, what : strLst = 'all',
forceNewFile : bool = True, folders : bool = False,
filePW = None):
"""
Output samples to ParaView file.
Args:
name(optional): Base name to be used for data output.
filename(optional): Name of output file.
times(optional): Timestamps.
what(optional): Which plots to do. If list, can contain 'MESH',
'ABS', 'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard
'ALL'. Defaults to 'ALL'.
forceNewFile(optional): Whether to create new output file.
folders(optional): Whether to split output in folders.
filePW(optional): Fenics File entity (for time series).
"""
RROMPyAssert(self._mode, message = "Cannot output samples.")
self.samplingEngine.outParaviewSamples(name = name,
filename = filename,
times = times, what = what,
forceNewFile = forceNewFile,
folders = folders,
filePW = filePW)
def outParaviewTimeDomainSamples(self, omegas : Np1D = None,
timeFinal : Np1D = None,
periodResolution : int = 20,
name : str = "u",
filename : str = "out",
forceNewFile : bool = True,
folders : bool = False):
"""
Output samples to ParaView file, converted to time domain.
Args:
omegas(optional): frequencies.
timeFinal(optional): final time of simulation.
periodResolution(optional): number of time steps per period.
name(optional): Base name to be used for data output.
filename(optional): Name of output file.
forceNewFile(optional): Whether to create new output file.
folders(optional): Whether to split output in folders.
"""
RROMPyAssert(self._mode, message = "Cannot output samples.")
self.samplingEngine.outParaviewTimeDomainSamples(omegas = omegas,
timeFinal = timeFinal,
periodResolution = periodResolution,
name = name, filename = filename,
forceNewFile = forceNewFile,
folders = folders)
def setSamples(self, samplingEngine):
"""Copy samplingEngine and samples."""
vbMng(self, "INIT", "Transfering samples.", 10)
self.samplingEngine = copy(samplingEngine)
vbMng(self, "DEL", "Done transfering samples.", 10)
def setTrainedModel(self, model):
"""Deepcopy approximation from trained model."""
if hasattr(model, "storeTrainedModel"):
verb = model.verbosity
model.verbosity = 0
fileOut = model.storeTrainedModel()
model.verbosity = verb
else:
try:
fileOut = getNewFilename("trained_model", "pkl")
pickleDump(model.data.__dict__, fileOut)
except:
raise RROMPyException(("Failed to store model data. Parameter "
"model must have either "
"storeTrainedModel or "
"data.__dict__ properties."))
self.loadTrainedModel(fileOut)
osrm(fileOut)
@abstractmethod
def setupApprox(self):
"""
Setup approximant. (ABSTRACT)
Any specialization should include something like
if self.checkComputedApprox():
return
RROMPyAssert(self._mode, message = "Cannot setup approximant.")
...
self.trainedModel = ...
self.trainedModel.data = ...
self.trainedModel.data.approxParameters = copy(
self.approxParameters)
"""
pass
def checkComputedApprox(self) -> bool:
"""
Check if setup of new approximant is not needed.
Returns:
True if new setup is not needed. False otherwise.
"""
return self._mode == RROMPy_FRAGILE or (self.trainedModel is not None
and self.trainedModel.data.approxParameters == self.approxParameters)
def _pruneBeforeEval(self, mu:paramList, field:str, append:bool,
prune:bool) -> Tuple[paramList, Np1D, Np1D, bool]:
mu = checkParameterList(mu, self.npar)[0]
idx = np.empty(len(mu), dtype = np.int)
if prune:
jExtra = np.zeros(len(mu), dtype = bool)
muExtra = emptyParameterList()
lastSolvedMus = getattr(self, "lastSolved" + field)
if (len(mu) > 0 and len(mu) == len(lastSolvedMus)
and mu == lastSolvedMus):
idx = np.arange(len(mu), dtype = np.int)
return muExtra, jExtra, idx, True
muKeep = copy(muExtra)
for j in range(len(mu)):
jPos = lastSolvedMus.find(mu[j])
if jPos is not None:
idx[j] = jPos
muKeep.append(mu[j])
else:
jExtra[j] = True
muExtra.append(mu[j])
if len(muKeep) > 0 and not append:
lastSolvedu = getattr(self, "u" + field)
idx[~jExtra] = getattr(self.__class__, "set" + field)(self,
muKeep, lastSolvedu[idx[~jExtra]], append)
append = True
else:
jExtra = np.ones(len(mu), dtype = bool)
muExtra = mu
return muExtra, jExtra, idx, append
def _setObject(self, mu:paramList, field:str, object:sampList,
append:bool) -> List[int]:
newMus = checkParameterList(mu, self.npar)[0]
newObj = sampleList(object)
if append:
getattr(self, "lastSolved" + field).append(newMus)
getattr(self, "u" + field).append(newObj)
Ltot = len(getattr(self, "u" + field))
return list(range(Ltot - len(newObj), Ltot))
setattr(self, "lastSolved" + field, copy(newMus))
setattr(self, "u" + field, copy(newObj))
return list(range(len(getattr(self, "u" + field))))
def setHF(self, muHF:paramList, uHF:sampleList,
append : bool = False) -> List[int]:
"""Assign high fidelity solution."""
return self._setObject(muHF, "HF", uHF, append)
def evalHF(self, mu:paramList, append : bool = False,
prune : bool = True) -> List[int]:
"""
Find high fidelity solution with original parameters and arbitrary
parameter.
Args:
mu: Target parameter.
append(optional): Whether to append new HF solutions to old ones.
prune(optional): Whether to remove duplicates of already appearing
HF solutions.
"""
muExtra, jExtra, idx, append = self._pruneBeforeEval(mu, "HF", append,
prune)
if len(muExtra) > 0:
vbMng(self, "INIT", "Solving HF model for mu = {}.".format(mu),
15)
- newuHFs = self.HFEngine.solve(muExtra,
- homogeneized = self.homogeneized)
+ newuHFs = self.HFEngine.solve(muExtra)
vbMng(self, "DEL", "Done solving HF model.", 15)
idx[jExtra] = self.setHF(muExtra, newuHFs, append)
return list(idx)
def setApproxReduced(self, muApproxR:paramList, uApproxR:sampleList,
append : bool = False) -> List[int]:
"""Assign high fidelity solution."""
return self._setObject(muApproxR, "ApproxReduced", uApproxR, append)
def evalApproxReduced(self, mu:paramList, append : bool = False,
prune : bool = True) -> List[int]:
"""
Evaluate reduced representation of approximant at arbitrary parameter.
Args:
mu: Target parameter.
append(optional): Whether to append new HF solutions to old ones.
prune(optional): Whether to remove duplicates of already appearing
HF solutions.
"""
self.setupApprox()
muExtra, jExtra, idx, append = self._pruneBeforeEval(mu,
"ApproxReduced",
append, prune)
if len(muExtra) > 0:
newuApproxs = self.trainedModel.getApproxReduced(muExtra)
idx[jExtra] = self.setApproxReduced(muExtra, newuApproxs, append)
return list(idx)
def setApprox(self, muApprox:paramList, uApprox:sampleList,
append : bool = False) -> List[int]:
"""Assign high fidelity solution."""
return self._setObject(muApprox, "Approx", uApprox, append)
def evalApprox(self, mu:paramList, append : bool = False,
prune : bool = True) -> List[int]:
"""
Evaluate approximant at arbitrary parameter.
Args:
mu: Target parameter.
append(optional): Whether to append new HF solutions to old ones.
prune(optional): Whether to remove duplicates of already appearing
HF solutions.
"""
self.setupApprox()
muExtra, jExtra, idx, append = self._pruneBeforeEval(mu, "Approx",
append, prune)
if len(muExtra) > 0:
newuApproxs = self.trainedModel.getApprox(muExtra)
idx[jExtra] = self.setApprox(muExtra, newuApproxs, append)
return list(idx)
- def getHF(self, mu:paramList, homogeneized : bool = False,
- append : bool = False, prune : bool = True) -> sampList:
+ def getHF(self, mu:paramList, append : bool = False,
+ prune : bool = True) -> sampList:
"""
Get HF solution at arbitrary parameter.
Args:
mu: Target parameter.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
Returns:
HFsolution.
"""
mu = checkParameterList(mu, self.npar)[0]
idx = self.evalHF(mu, append = append, prune = prune)
- uHFs = self.uHF(idx)
- if self.homogeneized and not homogeneized:
- for j, m in enumerate(mu):
- uHFs[j] += self.HFEngine.liftDirichletData(m)
- if not self.homogeneized and homogeneized:
- for j, m in enumerate(mu):
- uHFs[j] -= self.HFEngine.liftDirichletData(m)
- return uHFs
-
- def getRHS(self, mu:paramList, homogeneized : bool = False,
- duality : bool = True) -> sampList:
+ return self.uHF(idx)
+
+ def getRHS(self, mu:paramList, duality : bool = True) -> sampList:
"""
Get linear system RHS at arbitrary parameter.
Args:
mu: Target parameter.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
Returns:
Linear system RHS.
"""
- return self.HFEngine.residual(None, mu, homogeneized = homogeneized,
- duality = duality)
+ return self.HFEngine.residual(mu, None, duality = duality)
def getApproxReduced(self, mu:paramList, append : bool = False,
prune : bool = True) -> sampList:
"""
Get approximant at arbitrary parameter.
Args:
mu: Target parameter.
Returns:
Reduced approximant.
"""
mu = checkParameterList(mu, self.npar)[0]
idx = self.evalApproxReduced(mu, append = append, prune = prune)
- uApproxRs = self.uApproxReduced(idx)
- return uApproxRs
+ return self.uApproxReduced(idx)
- def getApprox(self, mu:paramList, homogeneized : bool = False,
- append : bool = False, prune : bool = True) -> sampList:
+ def getApprox(self, mu:paramList, append : bool = False,
+ prune : bool = True) -> sampList:
"""
Get approximant at arbitrary parameter.
Args:
mu: Target parameter.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
Returns:
Approximant.
"""
mu = checkParameterList(mu, self.npar)[0]
idx = self.evalApprox(mu, append = append, prune = prune)
- uApproxs = self.uApprox(idx)
- if self.homogeneized and not homogeneized:
- for j, m in enumerate(mu):
- uApproxs[j] += self.HFEngine.liftDirichletData(m)
- if not self.homogeneized and homogeneized:
- for j, m in enumerate(mu):
- uApproxs[j] -= self.HFEngine.liftDirichletData(m)
- return uApproxs
-
- def getRes(self, mu:paramList, homogeneized : bool = False,
- duality : bool = True) -> sampList:
+ return self.uApprox(idx)
+
+ def getRes(self, mu:paramList, duality : bool = True) -> sampList:
"""
Get residual at arbitrary parameter.
Args:
mu: Target parameter.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
Returns:
Approximant residual.
"""
- return self.HFEngine.residual(self.getApprox(mu, homogeneized), mu,
- homogeneized = homogeneized,
+ return self.HFEngine.residual(mu, self.getApprox(mu),
duality = duality)
- def getErr(self, mu:paramList, homogeneized : bool = False,
- append : bool = False, prune : bool = True) -> sampList:
+ def getErr(self, mu:paramList, append : bool = False,
+ prune : bool = True) -> sampList:
"""
Get error at arbitrary parameter.
Args:
mu: Target parameter.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
Returns:
Approximant error.
"""
- return (self.getApprox(mu, homogeneized, append = append, prune =prune)
- - self.getHF(mu, homogeneized, append = append, prune = prune))
+ return (self.getApprox(mu, append = append, prune =prune)
+ - self.getHF(mu, append = append, prune = prune))
def getPoles(self, *args, **kwargs) -> Np1D:
"""
Obtain approximant poles.
Returns:
Numpy complex vector of poles.
"""
self.setupApprox()
vbMng(self, "INIT", "Computing poles of model.", 20)
poles = self.trainedModel.getPoles(*args, **kwargs)
vbMng(self, "DEL", "Done computing poles.", 20)
return poles
def storeTrainedModel(self, filenameBase : str = "trained_model",
forceNewFile : bool = True) -> str:
"""Store trained reduced model to file."""
self.setupApprox()
vbMng(self, "INIT", "Storing trained model to file.", 20)
if forceNewFile:
filename = getNewFilename(filenameBase, "pkl")
else:
filename = "{}.pkl".format(filenameBase)
pickleDump(self.trainedModel.data.__dict__, filename)
vbMng(self, "DEL", "Done storing trained model.", 20)
return filename
def loadTrainedModel(self, filename:str):
"""Load trained reduced model from file."""
vbMng(self, "INIT", "Loading pre-trained model from file.", 20)
datadict = pickleLoad(filename)
name = datadict.pop("name")
if name == "TrainedModelRational":
from rrompy.reduction_methods.trained_model import \
TrainedModelRational as tModel
elif name == "TrainedModelReducedBasis":
from rrompy.reduction_methods.trained_model import \
TrainedModelReducedBasis as tModel
else:
raise RROMPyException(("Trained model name not recognized. "
"Loading failed."))
self.mu0 = datadict.pop("mu0")
from rrompy.reduction_methods.trained_model import TrainedModelData
trainedModel = tModel()
trainedModel.verbosity = self.verbosity
trainedModel.timestamp = self.timestamp
self.scaleFactor = datadict.pop("scaleFactor")
data = TrainedModelData(name, self.mu0, datadict.pop("projMat"),
self.scaleFactor, datadict.pop("rescalingExp"))
if "mus" in datadict:
data.mus = datadict.pop("mus")
approxParameters = datadict.pop("approxParameters")
data.approxParameters = copy(approxParameters)
if "sampler" in approxParameters:
self._approxParameters["sampler"] = approxParameters.pop("sampler")
self.approxParameters = copy(approxParameters)
if "mus" in data.__dict__:
self.mus = copy(data.mus)
for key in datadict:
setattr(data, key, datadict[key])
trainedModel.data = data
self.trainedModel = trainedModel
self._mode = RROMPy_FRAGILE
vbMng(self, "DEL", "Done loading pre-trained model.", 20)
diff --git a/rrompy/reduction_methods/base/reduced_basis_utils.py b/rrompy/reduction_methods/base/reduced_basis_utils.py
index fde59e0..5ebe3b9 100644
--- a/rrompy/reduction_methods/base/reduced_basis_utils.py
+++ b/rrompy/reduction_methods/base/reduced_basis_utils.py
@@ -1,68 +1,67 @@
# 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.utilities.base.types import (Np1D, Np2D, Tuple, List, ListAny,
sampList)
-from rrompy.utilities.poly_fitting.polynomial import (
- hashIdxToDerivative as hashI)
+from rrompy.utilities.numerical import hashIdxToDerivative as hashI, dot
from rrompy.utilities.exception_manager import RROMPyAssert
from rrompy.sampling import sampleList
__all__ = ['projectAffineDecomposition']
def projectAffineDecomposition(As:List[Np2D], bs:List[Np1D], pMat:sampList,
ARBsOld : List[Np2D] = None,
bRBsOld : List[Np1D] = None,
pMatOld : sampList = None)\
-> Tuple[List[Np2D], List[Np1D]]:
"""Project affine decomposition of linear system onto basis."""
RROMPyAssert((ARBsOld is None, bRBsOld is None),
(pMatOld is None, pMatOld is None),
"Old affine projected terms")
if isinstance(pMat, (sampleList,)): pMat = pMat.data
- pMatH = pMat.T.conj()
+ pMatC = pMat.conj()
ARBs = [None] * len(As)
bRBs = [None] * len(bs)
if pMatOld is None:
for j in range(max(len(As), len(bs))):
if j < len(As):
- ARBs[j] = pMatH.dot(As[j].dot(pMat))
+ ARBs[j] = dot(dot(As[j], pMat).T, pMatC).T
if j < len(bs):
- bRBs[j] = pMatH.dot(bs[j])
+ bRBs[j] = dot(pMatC.T, bs[j])
else:
RROMPyAssert((len(ARBsOld), len(bRBsOld)), (len(As), len(bs)),
"Old affine projected terms")
if isinstance(pMatOld, (sampleList,)): pMatOld = pMatOld.data
- pMatOldH = pMatOld.T.conj()
+ pMatOldC = pMatOld.conj()
Sold = pMatOld.shape[1]
Snew = pMat.shape[1]
for j in range(max(len(As), len(bs))):
if j < len(As):
ARBs[j] = np.empty((Sold + Snew, Sold + Snew),
- dtype = np.complex)
+ dtype = ARBsOld[j].dtype)
ARBs[j][: Sold, : Sold] = ARBsOld[j]
- ARBs[j][: Sold, Sold :] = pMatOldH.dot(As[j].dot(pMat))
- ARBs[j][Sold :, : Sold] = pMatH.dot(As[j].dot(pMatOld))
- ARBs[j][Sold :, Sold :] = pMatH.dot(As[j].dot(pMat))
+ ARBs[j][: Sold, Sold :] = dot(dot(As[j], pMat).T, pMatOldC).T
+ ARBs[j][Sold :, : Sold] = dot(dot(As[j], pMatOld).T, pMatC).T
+ ARBs[j][Sold :, Sold :] = dot(dot(As[j], pMat).T, pMatC).T
if j < len(bs):
- bRBs[j] = np.empty((Sold + Snew), dtype = np.complex)
+ bRBs[j] = np.empty((Sold + Snew), dtype = bRBsOld[j].dtype)
bRBs[j][: Sold] = bRBsOld[j]
- bRBs[j][Sold :] = pMatH.dot(bs[j])
+ bRBs[j][Sold :] = dot(pMatC.T, bs[j])
return ARBs, bRBs
diff --git a/rrompy/reduction_methods/greedy/generic_greedy_approximant.py b/rrompy/reduction_methods/greedy/generic_greedy_approximant.py
index c0f41fa..9f7ce60 100644
--- a/rrompy/reduction_methods/greedy/generic_greedy_approximant.py
+++ b/rrompy/reduction_methods/greedy/generic_greedy_approximant.py
@@ -1,583 +1,672 @@
# 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.standard.generic_standard_approximant \
import GenericStandardApproximant
from rrompy.utilities.base.types import (Np1D, Np2D, DictAny, HFEng, Tuple,
List, normEng, paramVal, paramList,
sampList)
from rrompy.utilities.base import verbosityManager as vbMng
+from rrompy.utilities.numerical import dot
+from rrompy.utilities.expression import expressionEvaluator
from rrompy.solver import normEngine
from rrompy.utilities.exception_manager import (RROMPyException, RROMPyAssert,
RROMPyWarning)
from rrompy.parameter import checkParameterList, emptyParameterList
__all__ = ['GenericGreedyApproximant']
+def localL2Distance(mus:Np2D, badmus:Np2D) -> Np2D:
+ return np.linalg.norm(np.tile(mus[..., np.newaxis], [1, 1, len(badmus)])
+ - badmus[..., np.newaxis].T, axis = 1)
+
def pruneSamples(mus:paramList, badmus:paramList,
- tol : float = 1e-8) -> paramList:
+ tol : float = 1e-8) -> Np1D:
"""Remove from mus all the elements which are too close to badmus."""
if len(badmus) == 0: return mus
- musNp = np.array(mus(0))
- badmus = np.array(badmus(0))
- proximity = np.min(np.abs(musNp.reshape(-1, 1)
- - np.tile(badmus.reshape(1, -1), [len(mus), 1])),
- axis = 1).flatten()
- idxPop = np.arange(len(mus))[proximity <= tol]
- for i, j in enumerate(idxPop):
- mus.pop(j - i)
- return mus
+ proximity = np.min(localL2Distance(mus.data, badmus.data), axis = 1)
+ return np.arange(len(mus))[proximity <= tol]
class GenericGreedyApproximant(GenericStandardApproximant):
"""
ROM greedy interpolant computation for parametric problems
(ABSTRACT).
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;
- 'S': number of starting training points;
- 'sampler': sample point generator;
- 'greedyTol': uniform error tolerance for greedy algorithm;
defaults to 1e-2;
+ - 'collinearityTol': collinearity tolerance for greedy algorithm;
+ defaults to 0.;
- 'interactive': whether to interactively terminate greedy
algorithm; defaults to False;
- 'maxIter': maximum number of greedy steps; defaults to 1e2;
- 'refinementRatio': ratio of test points to be exhausted before
test set refinement; defaults to 0.2;
- 'nTestPoints': number of test points; defaults to 5e2;
- 'trainSetGenerator': training sample points generator; defaults
to sampler.
Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. Defaults
- to False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
mus: Array of snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
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.
- 'greedyTol': uniform error tolerance for greedy algorithm;
+ - 'collinearityTol': collinearity tolerance for greedy algorithm;
- 'interactive': whether to interactively terminate greedy
algorithm;
- 'maxIter': maximum number of greedy steps;
- 'refinementRatio': ratio of test points to be exhausted before
test set refinement;
- 'nTestPoints': number of test points;
- 'trainSetGenerator': training sample points generator.
parameterListCritical: Recognized keys of critical approximant
parameters:
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator.
POD: whether to compute POD of snapshots.
S: number of test points.
sampler: Sample point generator.
- greedyTol: uniform error tolerance for greedy algorithm.
+ greedyTol: Uniform error tolerance for greedy algorithm.
+ collinearityTol: Collinearity tolerance for greedy algorithm.
interactive: whether to interactively terminate greedy algorithm.
maxIter: maximum number of greedy steps.
refinementRatio: ratio of training points to be exhausted before
training set refinement.
nTestPoints: number of starting training points.
trainSetGenerator: training sample points generator.
muBounds: list of bounds for parameter values.
samplingEngine: Sampling engine.
estimatorNormEngine: Engine for estimator norm computation.
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.
"""
TOL_INSTABILITY = 1e-6
def __init__(self, HFEngine:HFEng, mu0 : paramVal = None,
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
+ approxParameters : DictAny = {}, verbosity : int = 10,
+ timestamp : bool = True):
self._preInit()
- self._addParametersToList(["greedyTol", "interactive", "maxIter",
- "refinementRatio", "nTestPoints"],
- [1e-2, False, 1e2, .2, 5e2],
+ self._addParametersToList(["greedyTol", "collinearityTol",
+ "interactive", "maxIter", "refinementRatio",
+ "nTestPoints"],
+ [1e-2, 0., False, 1e2, .2, 5e2],
["trainSetGenerator"], ["AUTO"])
super().__init__(HFEngine = HFEngine, mu0 = mu0,
approxParameters = approxParameters,
- homogeneized = homogeneized, verbosity = verbosity,
- timestamp = timestamp)
- RROMPyAssert(self.HFEngine.npar, 1, "Parameter dimension")
+ verbosity = verbosity, timestamp = timestamp)
self._postInit()
@property
def greedyTol(self):
"""Value of greedyTol."""
return self._greedyTol
@greedyTol.setter
def greedyTol(self, greedyTol):
if greedyTol < 0:
raise RROMPyException("greedyTol must be non-negative.")
if hasattr(self, "_greedyTol") and self.greedyTol is not None:
greedyTolold = self.greedyTol
else:
greedyTolold = -1
self._greedyTol = greedyTol
self._approxParameters["greedyTol"] = self.greedyTol
if greedyTolold != self.greedyTol:
self.resetSamples()
+ @property
+ def collinearityTol(self):
+ """Value of collinearityTol."""
+ return self._collinearityTol
+ @collinearityTol.setter
+ def collinearityTol(self, collinearityTol):
+ if collinearityTol < 0:
+ raise RROMPyException("collinearityTol must be non-negative.")
+ if (hasattr(self, "_collinearityTol")
+ and self.collinearityTol is not None):
+ collinearityTolold = self.collinearityTol
+ else:
+ collinearityTolold = -1
+ self._collinearityTol = collinearityTol
+ self._approxParameters["collinearityTol"] = self.collinearityTol
+ if collinearityTolold != self.collinearityTol:
+ self.resetSamples()
+
@property
def interactive(self):
"""Value of interactive."""
return self._interactive
@interactive.setter
def interactive(self, interactive):
self._interactive = interactive
@property
def maxIter(self):
"""Value of maxIter."""
return self._maxIter
@maxIter.setter
def maxIter(self, maxIter):
if maxIter <= 0: raise RROMPyException("maxIter must be positive.")
if hasattr(self, "_maxIter") and self.maxIter is not None:
maxIterold = self.maxIter
else:
maxIterold = -1
self._maxIter = maxIter
self._approxParameters["maxIter"] = self.maxIter
if maxIterold != self.maxIter:
self.resetSamples()
@property
def refinementRatio(self):
"""Value of refinementRatio."""
return self._refinementRatio
@refinementRatio.setter
def refinementRatio(self, refinementRatio):
if refinementRatio <= 0. or refinementRatio > 1.:
raise RROMPyException(("refinementRatio must be between 0 "
"(excluded) and 1."))
if (hasattr(self, "_refinementRatio")
and self.refinementRatio is not None):
refinementRatioold = self.refinementRatio
else:
refinementRatioold = -1
self._refinementRatio = refinementRatio
self._approxParameters["refinementRatio"] = self.refinementRatio
if refinementRatioold != self.refinementRatio:
self.resetSamples()
@property
def nTestPoints(self):
"""Value of nTestPoints."""
return self._nTestPoints
@nTestPoints.setter
def nTestPoints(self, nTestPoints):
if nTestPoints <= 0:
raise RROMPyException("nTestPoints must be positive.")
if not np.isclose(nTestPoints, np.int(nTestPoints)):
raise RROMPyException("nTestPoints must be an integer.")
nTestPoints = np.int(nTestPoints)
if hasattr(self, "_nTestPoints") and self.nTestPoints is not None:
nTestPointsold = self.nTestPoints
else:
nTestPointsold = -1
self._nTestPoints = nTestPoints
self._approxParameters["nTestPoints"] = self.nTestPoints
if nTestPointsold != self.nTestPoints:
self.resetSamples()
@property
def trainSetGenerator(self):
"""Value of trainSetGenerator."""
return self._trainSetGenerator
@trainSetGenerator.setter
def trainSetGenerator(self, trainSetGenerator):
if (isinstance(trainSetGenerator, (str,))
and trainSetGenerator.upper() == "AUTO"):
trainSetGenerator = self.sampler
if 'generatePoints' not in dir(trainSetGenerator):
raise RROMPyException("trainSetGenerator type not recognized.")
if (hasattr(self, '_trainSetGenerator')
and self.trainSetGenerator not in [None, "AUTO"]):
trainSetGeneratorOld = self.trainSetGenerator
self._trainSetGenerator = trainSetGenerator
self._approxParameters["trainSetGenerator"] = self.trainSetGenerator
if (not 'trainSetGeneratorOld' in locals()
or trainSetGeneratorOld != self.trainSetGenerator):
self.resetSamples()
def resetSamples(self):
"""Reset samples."""
super().resetSamples()
self._mus = emptyParameterList()
def initEstimatorNormEngine(self, normEngn : normEng = None):
"""Initialize estimator norm engine."""
if (normEngn is not None or not hasattr(self, "estimatorNormEngine")
or self.estimatorNormEngine is None):
if normEngn is None:
if not hasattr(self.HFEngine, "energyNormPartialDualMatrix"):
self.HFEngine.buildEnergyNormPartialDualForm()
estimatorEnergyMatrix = (
self.HFEngine.energyNormPartialDualMatrix)
else:
if hasattr(normEngn, "buildEnergyNormPartialDualForm"):
if not hasattr(normEngn, "energyNormPartialDualMatrix"):
normEngn.buildEnergyNormPartialDualForm()
estimatorEnergyMatrix = (
normEngn.energyNormPartialDualMatrix)
else:
estimatorEnergyMatrix = normEngn
self.estimatorNormEngine = normEngine(estimatorEnergyMatrix)
- def errorEstimator(self, mus:paramList) -> List[complex]:
- """
- Standard residual-based error estimator with explicit residual
- computation.
- """
+ def _affineResidualMatricesContraction(self, rb:Np2D, rA : Np2D = None) \
+ -> Tuple[Np1D, Np1D, Np1D]:
+ self.assembleReducedResidualBlocks(full = True)
+ # 'ij,jk,ik->k', resbb, radiusb, radiusb.conj()
+ ff = np.sum(self.trainedModel.data.resbb.dot(rb) * rb.conj(), axis = 0)
+ if rA is None: return ff
+ # 'ijk,jkl,il->l', resAb, radiusA, radiusb.conj()
+ Lf = np.sum(np.tensordot(self.trainedModel.data.resAb, rA, 2)
+ * rb.conj(), axis = 0)
+ # 'ijkl,klt,ijt->t', resAA, radiusA, radiusA.conj()
+ LL = np.sum(np.tensordot(self.trainedModel.data.resAA, rA, 2)
+ * rA.conj(), axis = (0, 1))
+ return ff, Lf, LL
+
+ def errorEstimator(self, mus:Np1D) -> Np1D:
+ """Standard residual-based error estimator."""
self.setupApprox()
- res = self.getRes(mus, homogeneized = self.homogeneized,
- duality = False)
- if self.HFEngine.nbs == 1:
- RHS = self.getRHS(mus[0], homogeneized = self.homogeneized,
- duality = False)
- else:
- RHS = self.getRHS(mus, homogeneized = self.homogeneized,
- duality = False)
- return np.abs(self.estimatorNormEngine.norm(res)
- / self.estimatorNormEngine.norm(RHS))
+ mus = checkParameterList(mus, self.npar)[0]
+ vbMng(self.trainedModel, "INIT",
+ "Evaluating error estimator at mu = {}.".format(mus), 10)
+ verb = self.trainedModel.verbosity
+ self.trainedModel.verbosity = 0
+ uApproxRs = self.getApproxReduced(mus)
+ muTestEff = mus ** self.HFEngine.rescalingExp
+ radiusA = np.empty((len(self.HFEngine.thAs), len(mus)),
+ dtype = np.complex)
+ radiusb = np.empty((len(self.HFEngine.thbs), len(mus)),
+ dtype = np.complex)
+ for j, thA in enumerate(self.HFEngine.thAs):
+ radiusA[j] = expressionEvaluator(thA[0], muTestEff)
+ for j, thb in enumerate(self.HFEngine.thbs):
+ radiusb[j] = expressionEvaluator(thb[0], muTestEff)
+ radiusA = np.expand_dims(uApproxRs.data, 1) * radiusA
+ ff, Lf, LL = self._affineResidualMatricesContraction(radiusb, radiusA)
+ err = np.abs((LL - 2. * np.real(Lf) + ff) / ff) ** .5
+ self.trainedModel.verbosity = verb
+ vbMng(self.trainedModel, "DEL", "Done evaluating error estimator", 10)
+ return err
- def getMaxErrorEstimator(self, mus:paramList,
- plot : bool = False) -> Tuple[Np1D, int, float]:
+ def getMaxErrorEstimator(self, mus:paramList) -> Tuple[Np1D, int, float]:
"""
Compute maximum of (and index of maximum of) error estimator over given
parameters.
"""
errorEstTest = self.errorEstimator(mus)
- idxMaxEst = np.argmax(errorEstTest)
- maxEst = errorEstTest[idxMaxEst]
- if plot and not np.all(np.isinf(errorEstTest)):
- musre = mus.re(0)
- from matplotlib import pyplot as plt
- plt.figure()
- plt.semilogy(musre, errorEstTest, 'k')
- plt.semilogy([musre[0], musre[-1]], [self.greedyTol] * 2, 'r--')
- plt.semilogy(self.mus.re(0),
- 2. * self.greedyTol * np.ones(len(self.mus)), '*m')
- plt.semilogy(musre[idxMaxEst], maxEst, 'xr')
- plt.grid()
- plt.show()
- plt.close()
- return errorEstTest, idxMaxEst, maxEst
+ idxMaxEst = [np.argmax(errorEstTest)]
+ return errorEstTest, idxMaxEst, errorEstTest[idxMaxEst]
+
+ def _isLastSampleCollinear(self) -> bool:
+ """Check collinearity of last sample."""
+ if self.collinearityTol <= 0.: return False
+ if self.POD:
+ reff = self.samplingEngine.RPOD[:, -1]
+ else:
+ RROMPyWarning(("Repeated orthogonalization of the samples for "
+ "collinearity check. Consider setting POD to "
+ "True."))
+ if not hasattr(self, "_PODEngine"):
+ from rrompy.sampling.base.pod_engine import PODEngine
+ self._PODEngine = PODEngine(self.HFEngine)
+ reff = self._PODEngine.generalizedQR(self.samplingEngine.samples,
+ only_R = True)[:, -1]
+ cLevel = np.abs(reff[-1]) / np.linalg.norm(reff)
+ vbMng(self, "MAIN", "Collinearity indicator {:.4e}.".format(cLevel), 5)
+ return cLevel < self.collinearityTol
def greedyNextSample(self, muidx:int, plotEst : bool = False)\
-> Tuple[Np1D, int, float, paramVal]:
"""Compute next greedy snapshot of solution map."""
RROMPyAssert(self._mode, message = "Cannot add greedy sample.")
- mu = copy(self.muTest[muidx])
+ mus = copy(self.muTest[muidx])
self.muTest.pop(muidx)
- vbMng(self, "MAIN",
- ("Adding {}-th sample point at {} to training "
- "set.").format(self.samplingEngine.nsamples + 1, mu), 2)
- self.mus.append(mu)
- self.samplingEngine.nextSample(mu, homogeneized = self.homogeneized)
+ for mu in mus:
+ vbMng(self, "MAIN",
+ ("Adding sample point no. {} at {} to training "
+ "set.").format(self.samplingEngine.nsamples + 1, mu), 2)
+ self.mus.append(mu)
+ self.samplingEngine.nextSample(mu)
+ if self._isLastSampleCollinear():
+ RROMPyWarning("Collinearity above tolerance detected.")
+ errorEstTest = np.empty(len(self.muTest))
+ errorEstTest[:] = np.nan
+ return errorEstTest, [-1], np.nan, np.nan
errorEstTest, muidx, maxErrorEst = self.getMaxErrorEstimator(
- self.muTest, plotEst)
+ self.muTest)
+ if (plotEst and not np.any(np.isnan(errorEstTest))
+ and not np.any(np.isinf(errorEstTest))):
+ musre = copy(self.muTest.re.data)
+ from matplotlib import pyplot as plt
+ plt.figure()
+ errCP = copy(errorEstTest)
+ while len(musre) > 0:
+ if self.npar == 1:
+ currIdx = np.arange(len(musre))
+ else:
+ currIdx = np.where(np.isclose(np.sum(
+ np.abs(musre[:, 1 :] - musre[0, 1 :]), 1), 0.))[0]
+ plt.semilogy(musre[currIdx, 0], errCP[currIdx], 'k',
+ linewidth = 1)
+ musre = np.delete(musre, currIdx, 0)
+ errCP = np.delete(errCP, currIdx)
+ plt.semilogy([self.muTest.re(0, 0), self.muTest.re(-1, 0)],
+ [self.greedyTol] * 2, 'r--')
+ plt.semilogy(self.mus.re(0),
+ 2. * self.greedyTol * np.ones(len(self.mus)), '*m')
+ plt.semilogy(self.muTest.re(muidx, 0), maxErrorEst, 'xr')
+ plt.grid()
+ plt.show()
+ plt.close()
return errorEstTest, muidx, maxErrorEst, self.muTest[muidx]
def _preliminaryTraining(self):
"""Initialize starting snapshots of solution map."""
RROMPyAssert(self._mode, message = "Cannot start greedy algorithm.")
- self.computeScaleFactor()
if self.samplingEngine.nsamples > 0:
return
- vbMng(self, "INIT", "Starting computation of snapshots.", 2)
+ self.computeScaleFactor()
self.resetSamples()
- self.mus = self.trainSetGenerator.generatePoints(self.S)
+ self.mus = self.trainSetGenerator.generatePoints(self.S)[
+ list(range(self.S))]
muTestBase = self.sampler.generatePoints(self.nTestPoints)
- muTestBase = pruneSamples(muTestBase, self.mus,
- 1e-10 * self.scaleFactor[0]).sort()
+ idxPop = pruneSamples(muTestBase ** self.HFEngine.rescalingExp,
+ self.mus ** self.HFEngine.rescalingExp,
+ 1e-10 * self.scaleFactor[0])
+ muTestBase.pop(idxPop)
+ muTestBase = muTestBase.sort()
muLast = copy(self.mus[-1])
self.mus.pop()
if len(self.mus) > 0:
- nSamples = np.prod(self.S) - 1
vbMng(self, "MAIN",
("Adding first {} sample point{} at {} to training "
- "set.").format(nSamples, "" + "s" * (nSamples > 1),
+ "set.").format(self.S - 1, "" + "s" * (self.S > 2),
self.mus), 2)
- self.samplingEngine.iterSample(self.mus,
- homogeneized = self.homogeneized)
+ self.samplingEngine.iterSample(self.mus)
self.muTest = emptyParameterList()
self.muTest.reset((len(muTestBase) + 1, self.mus.shape[1]))
- self.muTest[: -1] = muTestBase
- self.muTest[-1] = muLast
+ self.muTest[: -1] = muTestBase.data
+ self.muTest[-1] = muLast.data
def _enrichTestSet(self, nTest:int):
"""Add extra elements to test set."""
RROMPyAssert(self._mode, message = "Cannot enrich test set.")
muTestExtra = self.sampler.generatePoints(2 * nTest)
muTotal = copy(self.mus)
muTotal.append(self.muTest)
- muTestExtra = pruneSamples(muTestExtra, muTotal,
- 1e-10 * self.scaleFactor[0])
- muTestNew = np.empty(len(self.muTest) + len(muTestExtra),
- dtype = np.complex)
- muTestNew[: len(self.muTest)] = self.muTest(0)
- muTestNew[len(self.muTest) :] = muTestExtra(0)
- self.muTest = checkParameterList(muTestNew.sort(), self.npar)[0]
+ idxPop = pruneSamples(muTestExtra ** self.HFEngine.rescalingExp,
+ muTotal ** self.HFEngine.rescalingExp,
+ 1e-10 * self.scaleFactor[0])
+ muTestExtra.pop(idxPop)
+ muTestNew = np.empty((len(self.muTest) + len(muTestExtra),
+ self.muTest.shape[1]), dtype = np.complex)
+ muTestNew[: len(self.muTest)] = self.muTest.data
+ muTestNew[len(self.muTest) :] = muTestExtra.data
+ self.muTest = checkParameterList(muTestNew, self.npar)[0].sort()
vbMng(self, "MAIN",
"Enriching test set by {} elements.".format(len(muTestExtra)), 5)
def greedy(self, plotEst : bool = False):
"""Compute greedy snapshots of solution map."""
RROMPyAssert(self._mode, message = "Cannot start greedy algorithm.")
if self.samplingEngine.nsamples > 0:
return
+ vbMng(self, "INIT", "Starting computation of snapshots.", 2)
self._preliminaryTraining()
nTest = self.nTestPoints
- errorEstTest, muidx, maxErrorEst, mu = self.greedyNextSample(-1,
- plotEst)
- vbMng(self, "MAIN",
- "Uniform testing error estimate {:.4e}.".format(maxErrorEst), 2)
- trainedModelOld = copy(self.trainedModel)
- while (self.samplingEngine.nsamples < self.maxIter
- and maxErrorEst > self.greedyTol):
- if (1. - self.refinementRatio) * nTest > len(self.muTest):
- self._enrichTestSet(nTest)
- nTest = len(self.muTest)
- muTestOld, maxErrorEstOld = self.muTest, maxErrorEst
- errorEstTest, muidx, maxErrorEst, mu = self.greedyNextSample(
+ muT0 = copy(self.muTest[-1])
+ errorEstTest, muidx, maxErrorEst, mu = self.greedyNextSample(
+ [len(self.muTest) - 1], plotEst)
+ if np.any(np.isnan(maxErrorEst)):
+ RROMPyWarning(("Instability in a posteriori estimator. "
+ "Starting preemptive greedy loop termination."))
+ self.muTest.append(muT0)
+ self.mus.pop(-1)
+ self.samplingEngine.popSample()
+ self.setupApprox()
+ else:
+ vbMng(self, "MAIN", ("Uniform testing error estimate "
+ "{:.4e}.").format(np.max(maxErrorEst)), 2)
+ trainedModelOld = copy(self.trainedModel)
+ while (self.samplingEngine.nsamples < self.maxIter
+ and np.max(maxErrorEst) > self.greedyTol):
+ if (1. - self.refinementRatio) * nTest > len(self.muTest):
+ self._enrichTestSet(nTest)
+ nTest = len(self.muTest)
+ muTestOld, maxErrorEstOld = self.muTest, np.max(maxErrorEst)
+ errorEstTest, muidx, maxErrorEst, mu = self.greedyNextSample(
muidx, plotEst)
- vbMng(self, "MAIN",
- "Uniform testing error estimate {:.4e}.".format(maxErrorEst),
- 2)
- if (np.isnan(maxErrorEst) or np.isinf(maxErrorEst)
- or maxErrorEstOld < maxErrorEst * self.TOL_INSTABILITY):
- RROMPyWarning(("Instability in a posteriori estimator. "
- "Starting preemptive greedy loop termination."))
- maxErrorEst = maxErrorEstOld
- self.muTest = muTestOld
- self.mus = self.mus[:-1]
- self.samplingEngine.popSample()
- self.trainedModel.data = copy(trainedModelOld.data)
- break
- trainedModelOld.data = copy(self.trainedModel.data)
- if (self.interactive and maxErrorEst <= self.greedyTol):
- vbMng(self, "MAIN",
- ("Required tolerance {} achieved. Want to decrease "
- "greedyTol and continue? Y/N").format(self.greedyTol),
- 0, end = "")
- increasemaxIter = input()
- if increasemaxIter.upper() == "Y":
- vbMng(self, "MAIN", "Reducing value of greedyTol...", 0)
- while maxErrorEst <= self._greedyTol:
- self._greedyTol *= .5
- if (self.interactive
- and self.samplingEngine.nsamples >= self.maxIter):
- vbMng(self, "MAIN",
- ("Maximum number of iterations {} reached. Want to "
- "increase maxIter and continue? "
- "Y/N").format(self.maxIter), 0, end = "")
- increasemaxIter = input()
- if increasemaxIter.upper() == "Y":
- vbMng(self, "MAIN", "Doubling value of maxIter...", 0)
- self._maxIter *= 2
+ vbMng(self, "MAIN", ("Uniform testing error estimate "
+ "{:.4e}.").format(np.max(maxErrorEst)), 2)
+ if (np.any(np.isnan(maxErrorEst))
+ or np.any(np.isinf(maxErrorEst))
+ or maxErrorEstOld < (np.max(maxErrorEst)
+ * self.TOL_INSTABILITY)):
+ RROMPyWarning(("Instability in a posteriori estimator. "
+ "Starting preemptive greedy loop "
+ "termination."))
+ self.muTest = muTestOld
+ self.mus.pop(-1)
+ self.samplingEngine.popSample()
+ self.trainedModel.data = copy(trainedModelOld.data)
+ break
+ trainedModelOld.data = copy(self.trainedModel.data)
+ if (self.interactive and np.max(maxErrorEst) <= self.greedyTol):
+ vbMng(self, "MAIN",
+ ("Required tolerance {} achieved. Want to decrease "
+ "greedyTol and continue? "
+ "Y/N").format(self.greedyTol), 0, end = "")
+ increasemaxIter = input()
+ if increasemaxIter.upper() == "Y":
+ vbMng(self, "MAIN", "Reducing value of greedyTol...",
+ 0)
+ while np.max(maxErrorEst) <= self._greedyTol:
+ self._greedyTol *= .5
+ if (self.interactive
+ and self.samplingEngine.nsamples >= self.maxIter):
+ vbMng(self, "MAIN",
+ ("Maximum number of iterations {} reached. Want to "
+ "increase maxIter and continue? "
+ "Y/N").format(self.maxIter), 0, end = "")
+ increasemaxIter = input()
+ if increasemaxIter.upper() == "Y":
+ vbMng(self, "MAIN", "Doubling value of maxIter...", 0)
+ self._maxIter *= 2
vbMng(self, "DEL",
("Done computing snapshots (final snapshot count: "
"{}).").format(self.samplingEngine.nsamples), 2)
def checkComputedApprox(self) -> bool:
"""
Check if setup of new approximant is not needed.
Returns:
True if new setup is not needed. False otherwise.
"""
return (super().checkComputedApprox()
and len(self.mus) == self.trainedModel.data.projMat.shape[1])
def assembleReducedResidualGramian(self, pMat:sampList):
"""
Build residual gramian of reduced linear system through projections.
"""
self.initEstimatorNormEngine()
if (not hasattr(self.trainedModel.data, "gramian")
or self.trainedModel.data.gramian is None):
gramian = self.estimatorNormEngine.innerProduct(pMat, pMat)
else:
Sold = self.trainedModel.data.gramian.shape[0]
S = len(self.mus)
if Sold > S:
gramian = self.trainedModel.data.gramian[: S, : S]
else:
idxOld = list(range(Sold))
idxNew = list(range(Sold, S))
gramian = np.empty((S, S), dtype = np.complex)
gramian[: Sold, : Sold] = self.trainedModel.data.gramian
gramian[: Sold, Sold :] = (
self.estimatorNormEngine.innerProduct(pMat(idxNew),
pMat(idxOld)))
gramian[Sold :, : Sold] = gramian[: Sold, Sold :].T.conj()
gramian[Sold :, Sold :] = (
self.estimatorNormEngine.innerProduct(pMat(idxNew),
pMat(idxNew)))
self.trainedModel.data.gramian = gramian
def assembleReducedResidualBlocksbb(self, bs:List[Np1D]):
"""
Build blocks (of type bb) of reduced linear system through projections.
"""
self.initEstimatorNormEngine()
nbs = len(bs)
if (not hasattr(self.trainedModel.data, "resbb")
or self.trainedModel.data.resbb is None):
resbb = np.empty((nbs, nbs), dtype = np.complex)
for i in range(nbs):
Mbi = bs[i]
resbb[i, i] = self.estimatorNormEngine.innerProduct(Mbi, Mbi)
for j in range(i):
Mbj = bs[j]
resbb[i, j] = self.estimatorNormEngine.innerProduct(Mbj,
Mbi)
for i in range(nbs):
for j in range(i + 1, nbs):
resbb[i, j] = resbb[j, i].conj()
self.trainedModel.data.resbb = resbb
def assembleReducedResidualBlocksAb(self, As:List[Np2D], bs:List[Np1D],
pMat:sampList):
"""
Build blocks (of type Ab) of reduced linear system through projections.
"""
self.initEstimatorNormEngine()
nAs = len(As)
nbs = len(bs)
S = len(self.mus)
if (not hasattr(self.trainedModel.data, "resAb")
or self.trainedModel.data.resAb is None):
if not isinstance(pMat, (np.ndarray,)): pMat = pMat.data
resAb = np.empty((nbs, S, nAs), dtype = np.complex)
for j in range(nAs):
- MAj = As[j].dot(pMat)
+ MAj = dot(As[j], pMat)
for i in range(nbs):
Mbi = bs[i]
resAb[i, :, j] = self.estimatorNormEngine.innerProduct(MAj,
Mbi)
else:
Sold = self.trainedModel.data.resAb.shape[1]
if Sold == S: return
if Sold > S:
resAb = self.trainedModel.data.resAb[:, : S, :]
else:
if not isinstance(pMat, (np.ndarray,)): pMat = pMat.data
resAb = np.empty((nbs, S, nAs), dtype = np.complex)
resAb[:, : Sold, :] = self.trainedModel.data.resAb
for j in range(nAs):
- MAj = As[j].dot(pMat[:, Sold :])
+ MAj = dot(As[j], pMat[:, Sold :])
for i in range(nbs):
Mbi = bs[i]
resAb[i, Sold :, j] = (
self.estimatorNormEngine.innerProduct(MAj, Mbi))
self.trainedModel.data.resAb = resAb
def assembleReducedResidualBlocksAA(self, As:List[Np2D], pMat:sampList):
"""
Build blocks (of type AA) of reduced linear system through projections.
"""
self.initEstimatorNormEngine()
nAs = len(As)
S = len(self.mus)
if (not hasattr(self.trainedModel.data, "resAA")
or self.trainedModel.data.resAA is None):
if not isinstance(pMat, (np.ndarray,)): pMat = pMat.data
resAA = np.empty((S, nAs, S, nAs), dtype = np.complex)
for i in range(nAs):
- MAi = As[i].dot(pMat)
+ MAi = dot(As[i], pMat)
resAA[:, i, :, i] = (
self.estimatorNormEngine.innerProduct(MAi, MAi))
for j in range(i):
- MAj = As[j].dot(pMat)
+ MAj = dot(As[j], pMat)
resAA[:, i, :, j] = (
self.estimatorNormEngine.innerProduct(MAj, MAi))
for i in range(nAs):
for j in range(i + 1, nAs):
resAA[:, i, :, j] = resAA[:, j, :, i].T.conj()
else:
Sold = self.trainedModel.data.resAA.shape[0]
if Sold == S: return
if Sold > S:
resAA = self.trainedModel.data.resAA[: S, :, : S, :]
else:
if not isinstance(pMat, (np.ndarray,)): pMat = pMat.data
resAA = np.empty((S, nAs, S, nAs), dtype = np.complex)
resAA[: Sold, :, : Sold, :] = self.trainedModel.data.resAA
for i in range(nAs):
- MAi = As[i].dot(pMat)
+ MAi = dot(As[i], pMat)
resAA[: Sold, i, Sold :, i] = (
self.estimatorNormEngine.innerProduct(MAi[:, Sold :],
MAi[:, : Sold]))
resAA[Sold :, i, : Sold, i] = resAA[: Sold, i,
Sold :, i].T.conj()
resAA[Sold :, i, Sold :, i] = (
self.estimatorNormEngine.innerProduct(MAi[:, Sold :],
MAi[:, Sold :]))
for j in range(i):
- MAj = As[j].dot(pMat)
+ MAj = dot(As[j], pMat)
resAA[: Sold, i, Sold :, j] = (
self.estimatorNormEngine.innerProduct(MAj[:, Sold :],
MAi[:, : Sold]))
resAA[Sold :, i, : Sold, j] = (
self.estimatorNormEngine.innerProduct(MAj[:, : Sold],
MAi[:, Sold :]))
resAA[Sold :, i, Sold :, j] = (
self.estimatorNormEngine.innerProduct(MAj[:, Sold :],
MAi[:, Sold :]))
for i in range(nAs):
for j in range(i + 1, nAs):
resAA[: Sold, i, Sold :, j] = (
resAA[Sold :, j, : Sold, i].T.conj())
resAA[Sold :, i, : Sold, j] = (
resAA[: Sold, j, Sold :, i].T.conj())
resAA[Sold :, i, Sold :, j] = (
resAA[Sold :, j, Sold :, i].T.conj())
self.trainedModel.data.resAA = resAA
def assembleReducedResidualBlocks(self, full : bool = False):
"""Build affine blocks of affine decomposition of residual."""
- self.assembleReducedResidualBlocksbb(self.bs)
+ self.assembleReducedResidualBlocksbb(self.HFEngine.bs)
if full:
pMat = self.trainedModel.data.projMat
- self.assembleReducedResidualBlocksAb(self.As, self.bs, pMat)
- self.assembleReducedResidualBlocksAA(self.As, pMat)
+ self.assembleReducedResidualBlocksAb(self.HFEngine.As,
+ self.HFEngine.bs, pMat)
+ self.assembleReducedResidualBlocksAA(self.HFEngine.As, pMat)
diff --git a/rrompy/reduction_methods/greedy/rational_interpolant_greedy.py b/rrompy/reduction_methods/greedy/rational_interpolant_greedy.py
index c4ba5ba..01514cb 100644
--- a/rrompy/reduction_methods/greedy/rational_interpolant_greedy.py
+++ b/rrompy/reduction_methods/greedy/rational_interpolant_greedy.py
@@ -1,354 +1,490 @@
# 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 .generic_greedy_approximant import GenericGreedyApproximant
+from .generic_greedy_approximant import (GenericGreedyApproximant,
+ localL2Distance as lL2D)
from rrompy.utilities.poly_fitting.polynomial import (polybases, polydomcoeff,
- PolynomialInterpolator as PI)
+ PolynomialInterpolator as PI,
+ polyvanderTotal as pvT)
+from rrompy.utilities.numerical import totalDegreeN
+from rrompy.utilities.expression import expressionEvaluator
from rrompy.reduction_methods.standard import RationalInterpolant
from rrompy.reduction_methods.trained_model import (
TrainedModelRational as tModel)
from rrompy.reduction_methods.trained_model import TrainedModelData
-from rrompy.utilities.base.types import Np1D, Np2D, DictAny, HFEng, paramVal
+from rrompy.utilities.base.types import (Np1D, Tuple, DictAny, HFEng, paramVal,
+ paramList)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.exception_manager import RROMPyWarning
-from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
+from rrompy.utilities.poly_fitting import customFit
+from rrompy.utilities.exception_manager import (RROMPyWarning, RROMPyException,
+ RROMPyAssert)
+from rrompy.parameter import checkParameterList
__all__ = ['RationalInterpolantGreedy']
class RationalInterpolantGreedy(GenericGreedyApproximant, RationalInterpolant):
"""
ROM greedy 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;
- 'S': number of starting training points;
- 'sampler': sample point generator;
- - 'radialBasis': radial basis family for interpolant numerator;
- defaults to 0, i.e. no radial basis;
- - 'radialBasisWeights': radial basis weights for interpolant
- numerator; defaults to 0, i.e. identity;
- 'greedyTol': uniform error tolerance for greedy algorithm;
defaults to 1e-2;
+ - 'collinearityTol': collinearity tolerance for greedy algorithm;
+ defaults to 0.;
- 'interactive': whether to interactively terminate greedy
algorithm; defaults to False;
- 'maxIter': maximum number of greedy steps; defaults to 1e2;
- - 'refinementRatio': ratio of training points to be exhausted
- before training set refinement; defaults to 0.2;
+ - 'refinementRatio': ratio of test points to be exhausted before
+ test set refinement; defaults to 0.2;
- 'nTestPoints': number of test points; defaults to 5e2;
- 'trainSetGenerator': training sample points generator; defaults
to sampler;
- - 'polybasis': type of basis for interpolation; allowed values
- include 'MONOMIAL', 'CHEBYSHEV' and 'LEGENDRE'; defaults to
+ - 'polybasis': type of basis for interpolation; defaults to
'MONOMIAL';
- 'errorEstimatorKind': kind of error estimator; available values
- include 'EXACT', 'BASIC', and 'BARE'; defaults to 'EXACT';
+ include 'AFFINE', 'DISCREPANCY', 'INTERPOLATORY',
+ 'EIM_INTERPOLATORY', and 'EIM_DIAGONAL'; defaults to 'AFFINE';
- 'interpRcond': tolerance for interpolation; defaults to None;
- 'robustTol': tolerance for robust rational denominator
management; defaults to 0.
Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. Defaults
- to False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
mus: Array of snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
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.
- - 'radialBasis': radial basis family for interpolant numerator;
- defaults to 0, i.e. no radial basis;
- - 'radialBasisWeights': radial basis weights for interpolant
- numerator; defaults to 0, i.e. identity;
- 'greedyTol': uniform error tolerance for greedy algorithm;
+ - 'collinearityTol': collinearity tolerance for greedy algorithm;
- 'interactive': whether to interactively terminate greedy
algorithm;
- 'maxIter': maximum number of greedy steps;
- 'refinementRatio': ratio of test points to be exhausted before
test set refinement;
- 'nTestPoints': number of test points;
- 'trainSetGenerator': training sample points generator;
- 'errorEstimatorKind': kind of error estimator;
- 'interpRcond': tolerance for interpolation;
- '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.
POD: whether to compute POD of snapshots.
S: number of test points.
sampler: Sample point generator.
- radialBasis: Radial basis family for interpolant numerator.
- radialBasisWeights: Radial basis weights for interpolant numerator.
greedyTol: uniform error tolerance for greedy algorithm.
+ collinearityTol: Collinearity tolerance for greedy algorithm.
interactive: whether to interactively terminate greedy algorithm.
maxIter: maximum number of greedy steps.
refinementRatio: ratio of training points to be exhausted before
training set refinement.
nTestPoints: number of starting training points.
trainSetGenerator: training sample points generator.
robustTol: tolerance for robust rational denominator management.
errorEstimatorKind: kind of error estimator.
interpRcond: tolerance for interpolation.
robustTol: tolerance for robust rational denominator management.
muBounds: list of bounds for parameter values.
samplingEngine: Sampling engine.
estimatorNormEngine: Engine for estimator norm computation.
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.
"""
- _allowedEstimatorKinds = ["EXACT", "BASIC", "BARE"]
+ _allowedEstimatorKinds = ["AFFINE", "DISCREPANCY", "INTERPOLATORY",
+ "EIM_INTERPOLATORY", "EIM_DIAGONAL"]
def __init__(self, HFEngine:HFEng, mu0 : paramVal = None,
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
+ approxParameters : DictAny = {}, verbosity : int = 10,
+ timestamp : bool = True):
self._preInit()
- self._addParametersToList(["polybasis", "errorEstimatorKind",
- "interpRcond", "robustTol"],
- ["MONOMIAL", "EXACT", -1, 0],
- toBeExcluded = ["E"])
+ self._addParametersToList(["errorEstimatorKind"], ["AFFINE"],
+ toBeExcluded = ["M", "N", "polydegreetype",
+ "radialDirectionalWeights",
+ "nNearestNeighbor"])
super().__init__(HFEngine = HFEngine, mu0 = mu0,
approxParameters = approxParameters,
- homogeneized = homogeneized,
verbosity = verbosity, timestamp = timestamp)
self._postInit()
@property
def E(self):
"""Value of E."""
- self._E = np.prod(self._S) - 1
+ self._E = self.sampleBatchIdx - 1
return self._E
@E.setter
def E(self, E):
RROMPyWarning(("E is used just to simplify inheritance, and its value "
- "cannot be changed from that of prod(S) - 1."))
+ "cannot be changed from that of sampleBatchIdx - 1."))
+
+ @property
+ def polydegreetype(self):
+ """Value of polydegreetype."""
+ return "TOTAL"
+ @polydegreetype.setter
+ def polydegreetype(self, polydegreetype):
+ RROMPyWarning(("polydegreetype is used just to simplify inheritance, "
+ "and its value cannot be changed from 'TOTAL'."))
@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 polybases:
raise RROMPyException("Sample type not recognized.")
self._polybasis = polybasis
except:
RROMPyWarning(("Prescribed polybasis not recognized. Overriding "
"to 'MONOMIAL'."))
self._polybasis = "MONOMIAL"
self._approxParameters["polybasis"] = self.polybasis
@property
def errorEstimatorKind(self):
"""Value of errorEstimatorKind."""
return self._errorEstimatorKind
@errorEstimatorKind.setter
def errorEstimatorKind(self, errorEstimatorKind):
errorEstimatorKind = errorEstimatorKind.upper()
if errorEstimatorKind not in self._allowedEstimatorKinds:
RROMPyWarning(("Error estimator kind not recognized. Overriding "
- "to 'EXACT'."))
- errorEstimatorKind = "EXACT"
+ "to 'AFFINE'."))
+ errorEstimatorKind = "AFFINE"
self._errorEstimatorKind = errorEstimatorKind
self._approxParameters["errorEstimatorKind"] = self.errorEstimatorKind
- @property
- def nTestPoints(self):
- """Value of nTestPoints."""
- return self._nTestPoints
- @nTestPoints.setter
- def nTestPoints(self, nTestPoints):
- if nTestPoints <= 0:
- RROMPyWarning("nTestPoints must be at least 1. Overriding to 1.")
- nTestPoints = 1
- if not np.isclose(nTestPoints, np.int(nTestPoints)):
- raise RROMPyException("nTestPoints must be an integer.")
- nTestPoints = np.int(nTestPoints)
- if hasattr(self, "_nTestPoints") and self.nTestPoints is not None:
- nTestPointsold = self.nTestPoints
- else: nTestPointsold = -1
- self._nTestPoints = nTestPoints
- self._approxParameters["nTestPoints"] = self.nTestPoints
- if nTestPointsold != self.nTestPoints:
- self.resetSamples()
-
- def _errorSamplingRatio(self, mus:Np1D, muRTest:Np1D,
- muRTrain:Np1D) -> Np1D:
- """Scalar ratio in explicit error estimator."""
- self.setupApprox()
- testTile = np.tile(np.reshape(muRTest, (-1, 1)), [1, len(muRTrain)])
- nodalVals = np.prod(testTile - np.reshape(muRTrain, (1, -1)), axis = 1)
- denVals = self.trainedModel.getQVal(mus)
- return np.abs(nodalVals / denVals)
-
- def _RHSNorms(self, radiusb0:Np2D) -> Np1D:
- """High fidelity system RHS norms."""
- self.assembleReducedResidualBlocks(full = False)
- # 'ij,jk,ik->k', resbb, radiusb0, radiusb0.conj()
- b0resb0 = np.sum(self.trainedModel.data.resbb.dot(radiusb0)
- * radiusb0.conj(), axis = 0)
- RHSnorms = np.power(np.abs(b0resb0), .5)
- return RHSnorms
+ def errorEstimator(self, mus:Np1D) -> Np1D:
+ """Standard residual-based error estimator."""
+ if self.errorEstimatorKind == "AFFINE":
+ return super().errorEstimator(mus)
+ setupOK = self.setupApprox()
+ if not setupOK:
+ err = np.empty(len(mus))
+ err[:] = np.nan
+ return err
+ if self.errorEstimatorKind == "DIAGONAL":
+ return self.errorEstimatorEIM(mus)
+ mus = checkParameterList(mus, self.npar)[0]
+ muCTest = self.trainedModel.centerNormalize(mus)
+ vbMng(self.trainedModel, "INIT",
+ "Evaluating error estimator at mu = {}.".format(mus), 10)
+ verb = self.trainedModel.verbosity
+ self.trainedModel.verbosity = 0
+ QTest = self.trainedModel.getQVal(mus)
+ if self.errorEstimatorKind == "DISCREPANCY":
+ nAs, nbs = len(self.HFEngine.thAs), len(self.HFEngine.thbs)
+ muTrainEff = self.mus ** self.HFEngine.rescalingExp
+ muTestEff = mus ** self.HFEngine.rescalingExp
+ PTrain = self.trainedModel.getPVal(self.mus).data.T
+ QTrain = self.trainedModel.getQVal(self.mus)
+ PTest = self.trainedModel.getPVal(mus).data
+ radiusAbTrain = np.empty((self.S, nAs * self.S + nbs),
+ dtype = np.complex)
+ radiusA = np.empty((self.S, nAs, len(mus)), dtype = np.complex)
+ radiusb = np.empty((nbs, len(mus)), dtype = np.complex)
+ for j, thA in enumerate(self.HFEngine.thAs):
+ idxs = j * self.S + np.arange(self.S)
+ radiusAbTrain[:, idxs] = expressionEvaluator(thA[0],
+ muTrainEff, (self.S, 1)) * PTrain
+ radiusA[:, j] = PTest * expressionEvaluator(thA[0],
+ muTestEff, (len(mus),))
+ for j, thb in enumerate(self.HFEngine.thbs):
+ idx = nAs * self.S + j
+ radiusAbTrain[:, idx] = QTrain * expressionEvaluator(thb[0],
+ muTrainEff, (self.S,))
+ radiusb[j] = QTest * expressionEvaluator(thb[0], muTestEff,
+ (len(mus),))
+ QRHSNorm2 = self._affineResidualMatricesContraction(radiusb)
+ vanTrain, _, vanTrainIdxs = pvT(self._musUniqueCN, self.N,
+ self.polybasis0, self._derIdxs,
+ self._reorder)
+ interpPQ = customFit(vanTrain[:, vanTrainIdxs], radiusAbTrain,
+ rcond = self.interpRcond)
+ vanTest, _, vanTestIdxs = pvT(muCTest, self.N, self.polybasis0)
+ DradiusAb = vanTest[:, vanTestIdxs].dot(interpPQ)
+ radiusA = (radiusA
+ - DradiusAb[:, : - nbs].reshape(len(mus), -1, self.S).T)
+ radiusb = radiusb - DradiusAb[:, - nbs :].T
+ ff, Lf, LL = self._affineResidualMatricesContraction(radiusb,
+ radiusA)
+ err = np.abs((LL - 2. * np.real(Lf) + ff) / QRHSNorm2) ** .5
+ else: #if self.errorEstimatorKind == "INTERPOLATORY":
+ muCTrain = self.trainedModel.centerNormalize(self.mus)
+ samplingRatio = np.prod(lL2D(muCTest.data, muCTrain.data),
+ axis = 1) / np.abs(QTest)
+ self.initEstimatorNormEngine()
+ QTest = np.abs(QTest)
+ sampRCP = copy(samplingRatio)
+ idx_muTestSample = np.empty(self.sampleBatchSize,
+ dtype = int)
+ for j in range(self.sampleBatchSize):
+ k = np.argmax(sampRCP)
+ idx_muTestSample[j] = k
+ if j + 1 < self.sampleBatchSize:
+ musZero = self.trainedModel.centerNormalize(mus, mus[k])
+ sampRCP *= np.linalg.norm(musZero.data, axis = 1)
+ mu_muTestSample = mus[idx_muTestSample]
+ app_muTestSample = self.getApprox(mu_muTestSample)
+ resmus = self.HFEngine.residual(mu_muTestSample, app_muTestSample,
+ duality = False)
+ RHSmus = self.HFEngine.residual(mu_muTestSample, None,
+ duality = False)
+ ressamples = (self.estimatorNormEngine.norm(resmus)
+ / self.estimatorNormEngine.norm(RHSmus))
+ musT = copy(self.mus)
+ musT.append(mu_muTestSample)
+ musT = self.trainedModel.centerNormalize(musT)
+ musC = self.trainedModel.centerNormalize(mus)
+ resT = np.zeros(len(musT), dtype = np.complex)
+ err = np.zeros(len(mus))
+ for l in range(len(mu_muTestSample)):
+ resT[len(self.mus) + l] = (ressamples[l]
+ * QTest[idx_muTestSample[l]])
+ p = PI()
+ wellCond, msg = p.setupByInterpolation(musT, resT, self.M + 1,
+ self.polybasis, self.verbosity >= 15,
+ True, {}, {"rcond": self.interpRcond})
+ err += np.abs(p(musC))
+ resT[len(self.mus) + l] = 0.
+ err /= QTest
+ vbMng(self, "MAIN", msg, 15)
+ self.trainedModel.verbosity = verb
+ vbMng(self.trainedModel, "DEL", "Done evaluating error estimator", 10)
+ return err
- def _errorEstimatorBare(self) -> Np1D:
- """Bare residual-based error estimator."""
- self.setupApprox()
- self.assembleReducedResidualGramian(self.trainedModel.data.projMat)
- pDom = self.trainedModel.data.P.domCoeff
- LL = pDom.conj().dot(self.trainedModel.data.gramian.dot(pDom))
- Adiag = self.As[0].diagonal()
- AnormApprox = np.linalg.norm(Adiag) ** 2. / np.size(Adiag)
- return np.abs(AnormApprox * LL) ** .5
+ def errorEstimatorEIM(self, mus:Np1D,
+ return_max_idxs : bool = False) -> Np1D:
+ """EIM-like interpolation error estimator."""
+ setupOK = self.setupApprox()
+ if not setupOK:
+ err = np.empty(len(mus))
+ err[:] = np.nan
+ return err
+ mus = checkParameterList(mus, self.npar)[0]
+ vbMng(self.trainedModel, "INIT",
+ "Evaluating error estimator at mu = {}.".format(mus), 10)
+ verb = self.trainedModel.verbosity
+ self.trainedModel.verbosity = 0
+ QTest = self.trainedModel.getQVal(mus)
+ muCTest = self.trainedModel.centerNormalize(mus)
+ muCTrain = self.trainedModel.centerNormalize(self.mus)
+ vanderTest, _, vanderTestR = pvT(muCTest, self.E, self.polybasis)
+ vanderTest = vanderTest[:, vanderTestR]
+ vanderTestNext, _, vanderTestNextR = pvT(muCTest, self.E + 1,
+ self.polybasis)
+ vanderTestNext = vanderTestNext[:, vanderTestNextR[
+ vanderTest.shape[1] :]]
+ idxsTest = np.arange(vanderTestNext.shape[1])
+ basis = np.zeros((len(idxsTest), 0), dtype = float)
+ idxMaxEst = []
+ err = None
+ while len(idxsTest) > 0:
+ vanderTrial, _, vanderTrialR = pvT(muCTrain, self.E,
+ self.polybasis)
+ vanderTrial = vanderTrial[:, vanderTrialR]
+ vanderTrialNext, _, vanderTrialNextR = pvT(muCTrain, self.E + 1,
+ self.polybasis)
+ vanderTrialNext = vanderTrialNext[:, vanderTrialNextR[
+ vanderTrial.shape[1] :]]
+ vanderTrial = np.hstack((vanderTrial,
+ vanderTrialNext.dot(basis).reshape(
+ len(vanderTrialNext),
+ basis.shape[1])))
+ valuesTrial = vanderTrialNext[:, idxsTest]
+ vanderTestEff = np.hstack((vanderTest,
+ vanderTestNext.dot(basis).reshape(
+ len(vanderTestNext),
+ basis.shape[1])))
+ vanderTestNextEff = vanderTestNext[:, idxsTest]
+ coeffTest = np.linalg.solve(vanderTrial, valuesTrial)
+ errTest = np.abs((vanderTestNextEff - vanderTestEff.dot(coeffTest))
+ / np.expand_dims(QTest, 1))
+ idxMaxErr = np.unravel_index(np.argmax(errTest), errTest.shape)
+ idxMaxEst += [idxMaxErr[0]]
+ if err is None: err = np.max(errTest, axis = 1)
+ if not return_max_idxs: break
+ muCTrain.append(muCTest[idxMaxErr[0]])
+ basis = np.pad(basis, [(0, 0), (0, 1)], "constant")
+ basis[idxsTest[idxMaxErr[1]], -1] = 1.
+ idxsTest = np.delete(idxsTest, idxMaxErr[1])
+ if self.errorEstimatorKind == "EIM_DIAGONAL":
+ self.assembleReducedResidualBlocks(full = False)
+ muTestEff = mus ** self.HFEngine.rescalingExp
+ radiusb = np.empty((len(self.HFEngine.thbs), len(mus)),
+ dtype = np.complex)
+ for j, thb in enumerate(self.HFEngine.thbs):
+ radiusb[j] = expressionEvaluator(thb[0], muTestEff)
+ bresb = self._affineResidualMatricesContraction(radiusb)
+ self.assembleReducedResidualGramian(self.trainedModel.data.projMat)
+ pDom = (polydomcoeff(self.E, self.polybasis)
+ * self.trainedModel.data.P[(-1,) + (0,) * (self.npar - 1)])
+ LL = pDom.conj().dot(self.trainedModel.data.gramian.dot(pDom))
+ if not hasattr(self, "Anorm2Approx"):
+ if self.HFEngine.nAs > 1:
+ Ader = self.HFEngine.A(self.mu0,
+ [1] + [0] * (self.npar - 1))
+ try:
+ Adiag = self.scaleFactor[0] * Ader.diagonal()
+ except:
+ Adiag = self.scaleFactor[0] * np.diagonal(Ader)
+ self.Anorm2Approx = np.mean(np.abs(Adiag) ** 2.)
+ if (np.isclose(self.Anorm2Approx, 0.)
+ or self.HFEngine.nAs <= 1):
+ self.Anorm2Approx = 1
+ jOpt = np.abs(self.Anorm2Approx * LL / bresb) ** .5
+ err = jOpt * err
+ else: #if self.errorEstimatorKind == "EIM_INTERPOLATORY":
+ self.initEstimatorNormEngine()
+ mu_muTestSample = mus[idxMaxEst[0]]
+ app_muTestSample = self.getApprox(mu_muTestSample)
+ resmu = self.HFEngine.residual(mu_muTestSample,
+ app_muTestSample,
+ duality = False)
+ RHSmu = self.HFEngine.residual(mu_muTestSample, None,
+ duality = False)
+ jOpt = np.abs(self.estimatorNormEngine.norm(resmu)[0]
+ / err[idxMaxEst[0]]
+ / self.estimatorNormEngine.norm(RHSmu)[0])
+ err = jOpt * err
+ self.trainedModel.verbosity = verb
+ vbMng(self.trainedModel, "DEL", "Done evaluating error estimator", 10)
+ if return_max_idxs: return err, idxMaxEst
+ return err
- def _errorEstimatorBasic(self, muTest:paramVal, ratioTest:complex) -> Np1D:
- """Basic residual-based error estimator."""
- resmu = self.HFEngine.residual(self.getApprox(muTest), muTest,
- self.homogeneized, duality = False)[0]
- return np.abs(self.estimatorNormEngine.norm(resmu) / ratioTest)
+ def getMaxErrorEstimator(self, mus:paramList) -> Tuple[Np1D, int, float]:
+ """
+ Compute maximum of (and index of maximum of) error estimator over given
+ parameters.
+ """
+ if self.errorEstimatorKind[: 4] == "EIM_":
+ errorEstTest, idxMaxEst = self.errorEstimatorEIM(mus, True)
+ else:
+ errorEstTest = self.errorEstimator(mus)
+ idxMaxEst = np.empty(self.sampleBatchSize, dtype = int)
+ errCP = copy(errorEstTest)
+ for j in range(self.sampleBatchSize):
+ k = np.argmax(errCP)
+ idxMaxEst[j] = k
+ if j + 1 < self.sampleBatchSize:
+ musZero = self.trainedModel.centerNormalize(mus, mus[k])
+ errCP *= np.linalg.norm(musZero.data, axis = 1)
+ maxEst = errorEstTest[idxMaxEst]
+ return errorEstTest, idxMaxEst, maxEst
- def _errorEstimatorExact(self, muRTrain:Np1D, vanderBase:Np2D) -> Np1D:
- """Exact residual-based error estimator."""
- self.setupApprox()
- self.assembleReducedResidualBlocks(full = True)
- nAsM = self.HFEngine.nAs - 1
- nbsM = max(self.HFEngine.nbs - 1, nAsM * self.homogeneized)
- radiusA = np.zeros((len(self.mus), nAsM, vanderBase.shape[1]),
- dtype = np.complex)
- radiusb = np.zeros((nbsM, vanderBase.shape[1]), dtype = np.complex)
- domcoeff = polydomcoeff(self.trainedModel.data.Q.deg[0],
- self.trainedModel.data.Q.polybasis)
- Qvals = self.trainedModel.getQVal(self.mus)
- for k in range(max(nAsM, nbsM)):
- if k < nAsM:
- radiusA[:, k :, :] += np.multiply.outer(Qvals * self._fitinv,
- vanderBase[: nAsM - k, :])
- if k < nbsM:
- radiusb[k :, :] += (self._fitinv.dot(Qvals)
- * vanderBase[: nbsM - k, :])
- Qvals = Qvals * muRTrain
- if self.POD:
- radiusA = np.tensordot(self.samplingEngine.RPOD, radiusA, 1)
- # 'ijkl,klt,ijt->t', resAA, radiusA, radiusA.conj()
- LL = np.sum(np.tensordot(self.trainedModel.data.resAA, radiusA, 2)
- * radiusA.conj(), axis = (0, 1))
- # 'ijk,jkl,il->l', resAb, radiusA, radiusb.conj()
- Lf = np.sum(np.tensordot(self.trainedModel.data.resAb[1 :, :, :],
- radiusA, 2) * radiusb.conj(), axis = 0)
- # 'ij,jk,ik->k', resbb, radiusb, radiusb.conj()
- ff = np.sum(self.trainedModel.data.resbb[1 :, 1 :].dot(radiusb)
- * radiusb.conj(), axis = 0)
- return domcoeff * np.abs(ff - 2. * np.real(Lf) + LL) ** .5
+ def greedyNextSample(self, muidx:int, plotEst : bool = False)\
+ -> Tuple[Np1D, int, float, paramVal]:
+ """Compute next greedy snapshot of solution map."""
+ RROMPyAssert(self._mode, message = "Cannot add greedy sample.")
+ self.sampleBatchIdx += 1
+ self.sampleBatchSize = totalDegreeN(self.npar - 1, self.sampleBatchIdx)
+ return super().greedyNextSample(muidx, plotEst)
- def errorEstimator(self, mus:Np1D) -> Np1D:
- """Standard residual-based error estimator."""
- self.setupApprox()
- nAsM = self.HFEngine.nAs - 1
- nbsM = max(self.HFEngine.nbs - 1, nAsM * self.homogeneized)
- muRTest = self.centerNormalize(mus)(0)
- muRTrain = self.centerNormalize(self.mus)(0)
- samplingRatio = self._errorSamplingRatio(mus, muRTest, muRTrain)
- if self.errorEstimatorKind == "EXACT":
- vanSize = max(nAsM, nbsM)
- else:
- vanSize = nbsM
- vanderBase = np.polynomial.polynomial.polyvander(muRTest, vanSize).T
- RHSnorms = self._RHSNorms(vanderBase[: nbsM + 1, :])
- if self.errorEstimatorKind == "BARE":
- jOpt = self._errorEstimatorBare()
- elif self.errorEstimatorKind == "BASIC":
- idx_muTestSample = np.argmax(samplingRatio)
- jOpt = self._errorEstimatorBasic(mus[idx_muTestSample],
- samplingRatio[idx_muTestSample])
- else: #if self.errorEstimatorKind == "EXACT":
- jOpt = self._errorEstimatorExact(muRTrain, vanderBase[: -1, :])
- return jOpt * samplingRatio / RHSnorms
+ def _preliminaryTraining(self):
+ """Initialize starting snapshots of solution map."""
+ RROMPyAssert(self._mode, message = "Cannot start greedy algorithm.")
+ if self.samplingEngine.nsamples > 0:
+ return
+ S = self.S
+ self.sampleBatchIdx, self.sampleBatchSize, self._S = -1, 0, 0
+ nextBatchSize = 1
+ while self._S + nextBatchSize <= S:
+ self.sampleBatchIdx += 1
+ self.sampleBatchSize = nextBatchSize
+ self._S += self.sampleBatchSize
+ nextBatchSize = totalDegreeN(self.npar - 1,
+ self.sampleBatchIdx + 1)
+ super()._preliminaryTraining()
def setupApprox(self, plotEst : bool = False):
"""
Compute rational interpolant.
SVD-based robust eigenvalue management.
"""
if self.checkComputedApprox():
- return
+ return True
RROMPyAssert(self._mode, message = "Cannot setup approximant.")
vbMng(self, "INIT", "Setting up {}.".format(self.name()), 5)
- self.computeScaleFactor()
- if not hasattr(self, "As") or not hasattr(self, "bs"):
- vbMng(self, "INIT", "Computing affine blocks of system.", 10)
- self.As = self.HFEngine.affineLinearSystemA(self.mu0,
- self.scaleFactor)[1 :]
- self.bs = self.HFEngine.affineLinearSystemb(self.mu0,
- self.scaleFactor,
- self.homogeneized)
- vbMng(self, "DEL", "Done computing affine blocks.", 10)
self.greedy(plotEst)
self._S = len(self.mus)
- self._N, self._M = [self._S - 1] * 2
+ self._N, self._M = [self.E] * 2
if self.trainedModel is None:
self.trainedModel = tModel()
self.trainedModel.verbosity = self.verbosity
self.trainedModel.timestamp = self.timestamp
data = TrainedModelData(self.trainedModel.name(), self.mu0,
self.samplingEngine.samples,
self.scaleFactor,
self.HFEngine.rescalingExp)
data.mus = copy(self.mus)
self.trainedModel.data = data
else:
self.trainedModel = self.trainedModel
self.trainedModel.data.projMat = copy(self.samplingEngine.samples)
self.trainedModel.data.mus = copy(self.mus)
self.catchInstability = True
if self.N > 0:
- Qf = self._setupDenominator()
- Q = Qf[0]
- if self.errorEstimatorKind == "EXACT":
- self._fitinv = Qf[1].flatten()
+ try:
+ Q = self._setupDenominator()[0]
+ except RROMPyException as RE:
+ RROMPyWarning(RE)
+ vbMng(self, "DEL", "Done setting up approximant.", 5)
+ return False
else:
Q = PI()
Q.coeffs = np.ones(1, dtype = np.complex)
Q.npar = 1
Q.polybasis = self.polybasis
- if self.errorEstimatorKind == "EXACT": self._fitinv = np.ones(1)
self.trainedModel.data.Q = copy(Q)
- self.trainedModel.data.P = copy(self._setupNumerator())
+ try:
+ self.trainedModel.data.P = copy(self._setupNumerator())
+ except RROMPyException as RE:
+ RROMPyWarning(RE)
+ vbMng(self, "DEL", "Done setting up approximant.", 5)
+ return False
self.trainedModel.data.approxParameters = copy(self.approxParameters)
vbMng(self, "DEL", "Done setting up approximant.", 5)
+ return True
diff --git a/rrompy/reduction_methods/greedy/reduced_basis_greedy.py b/rrompy/reduction_methods/greedy/reduced_basis_greedy.py
index 55ae357..2e53456 100644
--- a/rrompy/reduction_methods/greedy/reduced_basis_greedy.py
+++ b/rrompy/reduction_methods/greedy/reduced_basis_greedy.py
@@ -1,227 +1,178 @@
# 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 .generic_greedy_approximant import GenericGreedyApproximant
from rrompy.reduction_methods.standard import ReducedBasis
from rrompy.reduction_methods.trained_model import \
TrainedModelReducedBasis as tModel
from rrompy.reduction_methods.trained_model import TrainedModelData
-from rrompy.utilities.base.types import Np1D, DictAny, HFEng, paramVal
+from rrompy.utilities.base.types import DictAny, HFEng, paramVal
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.utilities.exception_manager import RROMPyWarning, RROMPyAssert
-from rrompy.parameter import checkParameterList
__all__ = ['ReducedBasisGreedy']
class ReducedBasisGreedy(GenericGreedyApproximant, ReducedBasis):
"""
ROM greedy RB approximant computation for parametric problems.
Args:
HFEngine: HF problem solver.
mu0(optional): Default parameter. Defaults to 0.
approxParameters(optional): Dictionary containing values for main
parameters of approximant. Recognized keys are:
- 'POD': whether to compute POD of snapshots; defaults to True;
- 'S': number of starting training points;
- 'sampler': sample point generator;
- 'greedyTol': uniform error tolerance for greedy algorithm;
defaults to 1e-2;
+ - 'collinearityTol': collinearity tolerance for greedy algorithm;
+ defaults to 0.;
- 'interactive': whether to interactively terminate greedy
algorithm; defaults to False;
- 'maxIter': maximum number of greedy steps; defaults to 1e2;
- 'refinementRatio': ratio of test points to be exhausted before
test set refinement; defaults to 0.2;
- 'nTestPoints': number of test points; defaults to 5e2;
- 'trainSetGenerator': training sample points generator; defaults
to sampler.
Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. Defaults
- to False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
mus: Array of snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
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.
- 'greedyTol': uniform error tolerance for greedy algorithm;
+ - 'collinearityTol': collinearity tolerance for greedy algorithm;
- 'interactive': whether to interactively terminate greedy
algorithm;
- 'maxIter': maximum number of greedy steps;
- 'refinementRatio': ratio of test points to be exhausted before
test set refinement;
- 'nTestPoints': number of test points;
- 'trainSetGenerator': training sample points generator.
parameterListCritical: Recognized keys of critical approximant
parameters:
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator.
POD: whether to compute POD of snapshots.
S: number of test points.
sampler: Sample point generator.
greedyTol: uniform error tolerance for greedy algorithm.
+ collinearityTol: Collinearity tolerance for greedy algorithm.
interactive: whether to interactively terminate greedy algorithm.
maxIter: maximum number of greedy steps.
refinementRatio: ratio of training points to be exhausted before
training set refinement.
nTestPoints: number of starting training points.
trainSetGenerator: training sample points generator.
muBounds: list of bounds for parameter values.
samplingEngine: Sampling engine.
estimatorNormEngine: Engine for estimator norm computation.
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.
As: List of sparse matrices (in CSC format) representing coefficients
of linear system matrix.
bs: List of numpy vectors representing coefficients of linear system
RHS.
ARBs: List of sparse matrices (in CSC format) representing coefficients
of compressed linear system matrix.
bRBs: List of numpy vectors representing coefficients of compressed
linear system RHS.
"""
def __init__(self, HFEngine:HFEng, mu0 : paramVal = None,
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
+ approxParameters : DictAny = {}, verbosity : int = 10,
+ timestamp : bool = True):
self._preInit()
self._addParametersToList([], [], toBeExcluded = ["R", "PODTolerance"])
super().__init__(HFEngine = HFEngine, mu0 = mu0,
approxParameters = approxParameters,
- homogeneized = homogeneized,
verbosity = verbosity, timestamp = timestamp)
self._postInit()
@property
def R(self):
"""Value of R."""
- self._R = np.prod(self._S)
+ self._R = self._S
return self._R
@R.setter
def R(self, R):
RROMPyWarning(("R is used just to simplify inheritance, and its value "
- "cannot be changed from that of prod(S)."))
+ "cannot be changed from that of S."))
@property
def PODTolerance(self):
"""Value of PODTolerance."""
self._PODTolerance = -1
return self._PODTolerance
@PODTolerance.setter
def PODTolerance(self, PODTolerance):
RROMPyWarning(("PODTolerance is used just to simplify inheritance, "
"and its value cannot be changed from -1."))
- def errorEstimator(self, mus:Np1D) -> Np1D:
- """
- Standard residual-based error estimator. Unreliable for unstable
- problems (inf-sup constant is missing).
- """
- self.setupApprox()
- self.assembleReducedResidualBlocks(full = True)
- nmus = len(mus)
- nAs = self.trainedModel.data.resAA.shape[1]
- nbs = self.trainedModel.data.resbb.shape[0]
- radiusA = np.empty((len(self.mus), nAs, nmus), dtype = np.complex)
- radiusb = np.empty((nbs, nmus), dtype = np.complex)
- mustr = mus
- if nmus > 2:
- mustr = "[{} ..({}).. {}]".format(mus[0], nmus - 2, mus[-1])
- vbMng(self.trainedModel, "INIT",
- "Computing RB solution at mu = {}.".format(mustr), 5)
- verb = self.trainedModel.verbosity
- self.trainedModel.verbosity = 0
- parmus = checkParameterList(mus, self.npar)[0]
- uApproxRs = self.getApproxReduced(parmus)
- mu0Eff = self.mu0(0, 0) ** self.HFEngine.rescalingExp[0]
- for j, muPL in enumerate(parmus):
- uApproxR = uApproxRs[j]
- for i in range(max(nAs, nbs)):
- thetai = ((muPL[0] ** self.HFEngine.rescalingExp[0]
- - mu0Eff) / self.scaleFactor[0]) ** i
- if i < nAs:
- radiusA[:, i, j] = thetai * uApproxR
- if i < nbs:
- radiusb[i, j] = thetai
- self.trainedModel.verbosity = verb
- vbMng(self.trainedModel, "DEL", "Done computing RB solution.", 5)
- # 'ij,jk,ik->k', resbb, radiusb, radiusb.conj()
- ff = np.sum(self.trainedModel.data.resbb.dot(radiusb) * radiusb.conj(),
- axis = 0)
- # 'ijk,jkl,il->l', resAb, radiusA, radiusb.conj()
- Lf = np.sum(np.tensordot(self.trainedModel.data.resAb, radiusA, 2)
- * radiusb.conj(), axis = 0)
- # 'ijkl,klt,ijt->t', resAA, radiusA, radiusA.conj()
- LL = np.sum(np.tensordot(self.trainedModel.data.resAA, radiusA, 2)
- * radiusA.conj(), axis = (0, 1))
- return np.abs((LL - 2. * np.real(Lf) + ff) / ff) ** .5
-
def setupApprox(self, plotEst : bool = False):
"""Compute RB projection matrix."""
if self.checkComputedApprox():
return
RROMPyAssert(self._mode, message = "Cannot setup approximant.")
vbMng(self, "INIT", "Setting up {}.". format(self.name()), 5)
- self.computeScaleFactor()
self.greedy(plotEst)
vbMng(self, "INIT", "Computing projection matrix.", 7)
pMat = self.samplingEngine.samples
- vbMng(self, "INIT", "Computing affine blocks of system.", 10)
- self.As = self.HFEngine.affineLinearSystemA(self.mu0, self.scaleFactor)
- self.bs = self.HFEngine.affineLinearSystemb(self.mu0, self.scaleFactor,
- self.homogeneized)
- vbMng(self, "DEL", "Done computing affine blocks.", 10)
if self.trainedModel is None:
self.trainedModel = tModel()
self.trainedModel.verbosity = self.verbosity
self.trainedModel.timestamp = self.timestamp
data = TrainedModelData(self.trainedModel.name(), self.mu0,
pMat, self.scaleFactor,
self.HFEngine.rescalingExp)
ARBs, bRBs = self.assembleReducedSystem(pMat)
+ data.affinePoly = self.HFEngine.affinePoly
+ data.thAs, data.thbs = self.HFEngine.thAs, self.HFEngine.thbs
self.trainedModel.data = data
else:
self.trainedModel = self.trainedModel
pMatOld = self.trainedModel.data.projMat
Sold = pMatOld.shape[1]
idxNew = list(range(Sold, pMat.shape[1]))
ARBs, bRBs = self.assembleReducedSystem(pMat(idxNew), pMatOld)
self.trainedModel.data.projMat = copy(pMat)
self.trainedModel.data.mus = copy(self.mus)
self.trainedModel.data.ARBs = ARBs
self.trainedModel.data.bRBs = bRBs
vbMng(self, "DEL", "Done computing projection matrix.", 7)
self.trainedModel.data.approxParameters = copy(self.approxParameters)
vbMng(self, "DEL", "Done setting up approximant.", 5)
+
diff --git a/rrompy/reduction_methods/pivoted/__init__.py b/rrompy/reduction_methods/pivoted/__init__.py
index 6237733..4ea30f9 100644
--- a/rrompy/reduction_methods/pivoted/__init__.py
+++ b/rrompy/reduction_methods/pivoted/__init__.py
@@ -1,29 +1,27 @@
# 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 .generic_pivoted_approximant import GenericPivotedApproximant
from .rational_interpolant_pivoted import RationalInterpolantPivoted
-from .reduced_basis_pivoted import ReducedBasisPivoted
__all__ = [
'GenericPivotedApproximant',
- 'RationalInterpolantPivoted',
- 'ReducedBasisPivoted'
+ 'RationalInterpolantPivoted'
]
diff --git a/rrompy/reduction_methods/pivoted/generic_pivoted_approximant.py b/rrompy/reduction_methods/pivoted/generic_pivoted_approximant.py
index 57576d0..5e30e3d 100644
--- a/rrompy/reduction_methods/pivoted/generic_pivoted_approximant.py
+++ b/rrompy/reduction_methods/pivoted/generic_pivoted_approximant.py
@@ -1,480 +1,547 @@
# 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.utilities.poly_fitting.polynomial import (polybases,
- nextDerivativeIndices,
+from rrompy.utilities.poly_fitting.polynomial import (polybases as ppb,
PolynomialInterpolator as PI)
-from rrompy.utilities.poly_fitting.radial_basis import (
+from rrompy.utilities.poly_fitting.radial_basis import (polybases as rbpb,
RadialBasisInterpolator as RBI)
-from rrompy.utilities.poly_fitting.radial_basis import rbbases
+from rrompy.utilities.poly_fitting.moving_least_squares import (
+ polybases as mlspb,
+ MovingLeastSquaresInterpolator as MLSI)
from rrompy.sampling.pivoted import (SamplingEnginePivoted,
SamplingEnginePivotedPOD)
from rrompy.utilities.base.types import (ListAny, DictAny, HFEng, paramVal,
paramList)
from rrompy.utilities.base import verbosityManager as vbMng
+from rrompy.utilities.numerical import (fullDegreeN, totalDegreeN,
+ nextDerivativeIndices)
from rrompy.utilities.exception_manager import (RROMPyException, RROMPyAssert,
RROMPyWarning)
from rrompy.parameter import emptyParameterList
__all__ = ['GenericPivotedApproximant']
class GenericPivotedApproximant(GenericApproximant):
"""
- ROM pivoted approximant computation for parametric problems (ABSTRACT).
+ 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;
+ - 'matchingWeight': weight for pole matching optimization; defaults
+ to 1;
+ - 'cutOffTolerance': tolerance for ignoring parasitic poles;
+ defaults to np.inf;
+ - 'cutOffType': rule for tolerance computation for parasitic poles;
+ defaults to 'MAGNITUDE';
- '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 0;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant; defaults to 0, i.e. no radial basis;
- - 'radialBasisWeightsMarginal': radial basis weights for marginal
- interpolant; defaults to 0, i.e. identity;
+ - 'polydegreetypeMarginal': type of polynomial degree for marginal;
+ defaults to 'TOTAL';
+ - 'radialDirectionalWeightsMarginal': radial basis weights for
+ marginal interpolant; defaults to 0, i.e. identity;
+ - 'nNearestNeighborMarginal': number of marginal nearest neighbors
+ considered if polybasisMarginal allows; defaults to -1;
- 'interpRcondMarginal': tolerance for marginal interpolation;
defaults to None.
Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. 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.
musPivot: Array of pivot snapshot parameters.
musMarginal: Array of marginal snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
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;
+ - 'matchingWeight': weight for pole matching optimization;
+ - 'cutOffTolerance': tolerance for ignoring parasitic poles;
+ - 'cutOffType': rule for tolerance computation for parasitic poles;
- 'polybasisMarginal': type of polynomial basis for marginal
interpolation;
- 'MMarginal': degree of marginal interpolant;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant;
- - 'radialBasisWeightsMarginal': radial basis weights for marginal
- interpolant;
+ - 'polydegreetypeMarginal': type of polynomial degree for marginal;
+ - 'radialDirectionalWeightsMarginal': radial basis weights for
+ marginal interpolant;
+ - 'nNearestNeighborMarginal': number of marginal nearest neighbors
+ considered if polybasisMarginal allows;
- '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.
POD: Whether to compute POD of snapshots.
+ matchingWeight: Weight for pole matching optimization.
+ cutOffTolerance: Tolerance for ignoring parasitic poles.
+ cutOffType: Rule for tolerance computation for 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.
polybasisMarginal: Type of polynomial basis for marginal interpolation.
MMarginal: Degree of marginal interpolant.
- radialBasisMarginal: Radial basis family for marginal interpolant.
- radialBasisWeightsMarginal: Radial basis weights for marginal
+ polydegreetypeMarginal: Type of polynomial degree for marginal.
+ radialDirectionalWeightsMarginal: Radial basis weights for marginal
interpolant.
+ nNearestNeighborMarginal: Number of marginal nearest neighbors
+ considered if polybasisMarginal allows.
interpRcondMarginal: Tolerance for marginal interpolation.
muBoundsPivot: 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, HFEngine:HFEng, mu0 : paramVal = None,
directionPivot : ListAny = [0],
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
+ approxParameters : DictAny = {}, verbosity : int = 10,
+ timestamp : bool = True):
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(
- ["polybasisMarginal", "MMarginal", "radialBasisMarginal",
- "radialBasisWeightsMarginal", "interpRcondMarginal"],
- ["MONOMIAL", 0, 0, 1, -1],
- ["samplerPivot", "SMarginal", "samplerMarginal"],
- [QSBase, [1], QSBase])
+ self._addParametersToList(["matchingWeight", "cutOffTolerance",
+ "cutOffType", "polybasisMarginal",
+ "MMarginal", "polydegreetypeMarginal",
+ "radialDirectionalWeightsMarginal",
+ "nNearestNeighborMarginal",
+ "interpRcondMarginal"],
+ [1, np.inf, "MAGNITUDE", "MONOMIAL", 0,
+ "TOTAL", 1, -1, -1],
+ ["samplerPivot", "SMarginal",
+ "samplerMarginal"], [QSBase, [1], QSBase])
del QS
self._directionPivot = directionPivot
super().__init__(HFEngine = HFEngine, mu0 = mu0,
approxParameters = approxParameters,
- homogeneized = homogeneized,
verbosity = verbosity, timestamp = timestamp)
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:
SamplingEngine = SamplingEnginePivotedPOD
else:
SamplingEngine = SamplingEnginePivoted
self.samplingEngine = SamplingEngine(self.HFEngine,
self.directionPivot,
- verbosity = self.verbosity,
- allowRepeatedSamples = True)
+ verbosity = self.verbosity)
+
+ @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 cutOffTolerance(self):
+ """Value of cutOffTolerance."""
+ return self._cutOffTolerance
+ @cutOffTolerance.setter
+ def cutOffTolerance(self, cutOffTolerance):
+ self._cutOffTolerance = cutOffTolerance
+ self._approxParameters["cutOffTolerance"] = self.cutOffTolerance
+
+ @property
+ def cutOffType(self):
+ """Value of cutOffType."""
+ return self._cutOffType
+ @cutOffType.setter
+ def cutOffType(self, cutOffType):
+ try:
+ cutOffType = cutOffType.upper().strip().replace(" ","")
+ if cutOffType not in ["MAGNITUDE", "POTENTIAL"]:
+ raise RROMPyException("Prescribed cutOffType not recognized.")
+ self._cutOffType = cutOffType
+ except:
+ RROMPyWarning(("Prescribed cutOffType not recognized. Overriding "
+ "to 'MAGNITUDE'."))
+ self._cutOffType = "MAGNITUDE"
+ self._approxParameters["cutOffType"] = self.cutOffType
@property
def SMarginal(self):
"""Value of SMarginal."""
return self._SMarginal
@SMarginal.setter
def SMarginal(self, SMarginal):
- if not hasattr(SMarginal, "__len__"): SMarginal = [SMarginal]
- if any([s <= 0 for s in SMarginal]):
+ if SMarginal <= 0:
raise RROMPyException("SMarginal must be positive.")
if hasattr(self, "_SMarginal") and self._SMarginal is not None:
- Sold = tuple(self.SMarginal)
+ Sold = self.SMarginal
else: Sold = -1
self._SMarginal = SMarginal
self._approxParameters["SMarginal"] = self.SMarginal
- if Sold != tuple(self.SMarginal):
- self.resetSamples()
+ if Sold != self.SMarginal: self.resetSamples()
@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 polybases:
+ if polybasisMarginal not in ppb + rbpb + mlspb:
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 MMarginal < 0:
raise RROMPyException("MMarginal must be non-negative.")
self._MMarginal = MMarginal
self._approxParameters["MMarginal"] = self.MMarginal
@property
- def radialBasisMarginal(self):
- """Value of radialBasisMarginal."""
- return self._radialBasisMarginal
- @radialBasisMarginal.setter
- def radialBasisMarginal(self, radialBasisMarginal):
+ def polydegreetypeMarginal(self):
+ """Value of polydegreetypeMarginal."""
+ return self._polydegreetypeMarginal
+ @polydegreetypeMarginal.setter
+ def polydegreetypeMarginal(self, polydegreetypeM):
try:
- if radialBasisMarginal != 0:
- radialBasisMarginal = radialBasisMarginal.upper().strip()\
- .replace(" ","")
- if radialBasisMarginal not in rbbases:
- raise RROMPyException(("Prescribed marginal radialBasis "
- "not recognized."))
- self._radialBasisMarginal = radialBasisMarginal
+ polydegreetypeM = polydegreetypeM.upper().strip().replace(" ","")
+ if polydegreetypeM not in ["TOTAL", "FULL"]:
+ raise RROMPyException(("Prescribed polydegreetypeMarginal not "
+ "recognized."))
+ self._polydegreetypeMarginal = polydegreetypeM
except:
- RROMPyWarning(("Prescribed marginal radialBasis not recognized. "
- "Overriding to 0."))
- self._radialBasisMarginal = 0
- self._approxParameters["radialBasisMarginal"] = (
- self.radialBasisMarginal)
+ RROMPyWarning(("Prescribed polydegreetypeMarginal not recognized. "
+ "Overriding to 'TOTAL'."))
+ self._polydegreetypeMarginal = "TOTAL"
+ self._approxParameters["polydegreetypeMarginal"] = (
+ self.polydegreetypeMarginal)
@property
- def radialBasisWeightsMarginal(self):
- """Value of radialBasisWeightsMarginal."""
- return self._radialBasisWeightsMarginal
- @radialBasisWeightsMarginal.setter
- def radialBasisWeightsMarginal(self, radialBasisWeightsMarginal):
- self._radialBasisWeightsMarginal = radialBasisWeightsMarginal
- self._approxParameters["radialBasisWeightsMarginal"] = (
- self.radialBasisWeightsMarginal)
+ def radialDirectionalWeightsMarginal(self):
+ """Value of radialDirectionalWeightsMarginal."""
+ return self._radialDirectionalWeightsMarginal
+ @radialDirectionalWeightsMarginal.setter
+ def radialDirectionalWeightsMarginal(self, radialDirWeightsMarginal):
+ self._radialDirectionalWeightsMarginal = radialDirWeightsMarginal
+ self._approxParameters["radialDirectionalWeightsMarginal"] = (
+ self.radialDirectionalWeightsMarginal)
@property
- def polybasisMarginalP(self):
- if self.radialBasisMarginal == 0:
- return self._polybasisMarginal
- return self._polybasisMarginal + "_" + self.radialBasisMarginal
+ def nNearestNeighborMarginal(self):
+ """Value of nNearestNeighborMarginal."""
+ return self._nNearestNeighborMarginal
+ @nNearestNeighborMarginal.setter
+ def nNearestNeighborMarginal(self, nNearestNeighborMarginal):
+ self._nNearestNeighborMarginal = nNearestNeighborMarginal
+ self._approxParameters["nNearestNeighborMarginal"] = (
+ self.nNearestNeighborMarginal)
@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 muBoundsPivot(self):
"""Value of muBoundsPivot."""
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.__str__()
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.__str__())
if not 'samplerOld' in locals() or samplerOld != self.samplerMarginal:
self.resetSamples()
def resetSamples(self):
"""Reset samples."""
super().resetSamples()
self._musMUniqueCN = None
self._derMIdxs = None
self._reorderM = None
def setSamples(self, samplingEngine):
"""Copy samplingEngine and samples."""
super().setSamples(samplingEngine)
self.mus = copy(self.samplingEngine[0].mus)
for sEj in self.samplingEngine[1:]:
self.mus.append(sEj.mus)
def computeSnapshots(self):
"""Compute snapshots of solution map."""
RROMPyAssert(self._mode,
message = "Cannot start snapshot computation.")
- Sp = np.prod(self.S)
- Seff = Sp * np.prod(self.SMarginal)
- if self.samplingEngine.nsamplesTot != Seff:
+ if self.samplingEngine.nsamplesTot != self.S * self.SMarginal:
+ self.computeScaleFactor()
self.resetSamples()
vbMng(self, "INIT", "Starting computation of snapshots.", 5)
- if self.HFEngine.As[0] is None: self.HFEngine.A(self.mu0)
- if self.HFEngine.bs[0] is None: self.HFEngine.b(self.mu0)
+ self.HFEngine.buildA()
+ self.HFEngine.buildb()
self.musPivot = self.samplerPivot.generatePoints(self.S)
self.musMarginal = self.samplerMarginal.generatePoints(
self.SMarginal)
self.mus = emptyParameterList()
- self.mus.reset((Seff, self.HFEngine.npar))
- self.samplingEngine.resetHistory(Seff // Sp)
+ self.mus.reset((self.S * self.SMarginal, self.HFEngine.npar))
+ self.samplingEngine.resetHistory(self.SMarginal)
for j, muMarg in enumerate(self.musMarginal):
- for k in range(j * Sp, (j + 1) * Sp):
+ for k in range(j * self.S, (j + 1) * self.S):
self.mus.data[k, self.directionPivot] = (
- self.musPivot[k - j * Sp].data)
+ self.musPivot[k - j * self.S].data)
self.mus.data[k, self.directionMarginal] = muMarg.data
- self.samplingEngine.iterSample(self.musPivot, self.musMarginal,
- homogeneized = self.homogeneized)
+ self.samplingEngine.iterSample(self.musPivot, self.musMarginal)
if self.POD:
self.samplingEngine.coalesceSamples(self.interpRcondMarginal)
else:
self.samplingEngine.coalesceSamples()
vbMng(self, "DEL", "Done computing snapshots.", 5)
def _setupMarginalInterpolationIndices(self):
"""Setup parameters for polyvander."""
RROMPyAssert(self._mode,
message = "Cannot setup interpolation indices.")
if (self._musMUniqueCN is None
or len(self._reorderM) != len(self.musMarginal)):
self._musMUniqueCN, musMIdxsTo, musMIdxs, musMCount = (
- self.centerNormalizeMarginal(self.musMarginal).unique(
- return_index = True,
- return_inverse = True,
- return_counts = True))
+ self.trainedModel.centerNormalizeMarginal(self.musMarginal)\
+ .unique(return_index = True, return_inverse = True,
+ return_counts = True))
self._musMUnique = self.musMarginal[musMIdxsTo]
self._derMIdxs = [None] * len(self._musMUniqueCN)
self._reorderM = np.empty(len(musMIdxs), dtype = int)
filled = 0
for j, cnt in enumerate(musMCount):
self._derMIdxs[j] = nextDerivativeIndices([],
- self.musMarginal.shape[1], cnt)
+ self.nparMarginal, cnt)
jIdx = np.nonzero(musMIdxs == j)[0]
self._reorderM[jIdx] = np.arange(filled, filled + cnt)
filled += cnt
def _setupMarginalInterp(self):
"""Compute marginal interpolator."""
RROMPyAssert(self._mode, message = "Cannot setup numerator.")
vbMng(self, "INIT", "Starting computation of marginal interpolator.",
7)
self._setupMarginalInterpolationIndices()
- MMarginal0 = copy(self.MMarginal)
+ if self.polydegreetypeMarginal == "TOTAL":
+ cfun = totalDegreeN
+ else:
+ cfun = fullDegreeN
+ MM = copy(self.MMarginal)
+ while len(self.musMarginal) < cfun(MM, self.nparMarginal): MM -= 1
+ if MM < self.MMarginal:
+ RROMPyWarning(
+ ("MMarginal too large compared to SMarginal. "
+ "Reducing MMarginal by {}").format(self.MMarginal - MM))
+ self.MMarginal = MM
mI = []
for j in range(len(self.musMarginal)):
canonicalj = 1. * (np.arange(len(self.musMarginal)) == j)
- self._MMarginal = MMarginal0
+ self._MMarginal = MM
while self.MMarginal >= 0:
- if self.radialBasisMarginal == 0:
+ if self.polybasisMarginal in ppb:
p = PI()
wellCond, msg = p.setupByInterpolation(
- self._musMUniqueCN, canonicalj, self.MMarginal,
- self.polybasisMarginal, self.verbosity >= 5, True,
- {"derIdxs": self._derMIdxs,
- "reorder": self._reorderM,
- "scl": np.power(self.scaleFactorMarginal, -1.)},
- {"rcond": self.interpRcondMarginal})
- else:
+ self._musMUniqueCN, canonicalj, self.MMarginal,
+ self.polybasisMarginal, self.verbosity >= 5,
+ self.polydegreetypeMarginal == "TOTAL",
+ {"derIdxs": self._derMIdxs,
+ "reorder": self._reorderM,
+ "scl": np.power(self.scaleFactorMarginal, -1.)},
+ {"rcond": self.interpRcondMarginal})
+ elif self.polybasisMarginal in rbpb:
p = RBI()
wellCond, msg = p.setupByInterpolation(
self._musMUniqueCN, canonicalj, self.MMarginal,
- self.polybasisMarginalP,
- self.radialBasisWeightsMarginal,
- self.verbosity >= 5, True,
+ self.polybasisMarginal,
+ self.radialDirectionalWeightsMarginal,
+ self.verbosity >= 5,
+ self.polydegreetypeMarginal == "TOTAL",
{"derIdxs": self._derMIdxs,
- "reorder": self._reorderM,
- "scl": np.power(self.scaleFactorMarginal, -1.)},
+ "reorder": self._reorderM,
+ "scl": np.power(self.scaleFactorMarginal, -1.),
+ "nNearestNeighbor" : self.nNearestNeighborMarginal},
{"rcond": self.interpRcondMarginal})
+ else:# if self.polybasisMarginal in mlspb:
+ p = MLSI()
+ wellCond, msg = p.setupByInterpolation(
+ self._musMUniqueCN, canonicalj, self.MMarginal,
+ self.polybasisMarginal,
+ self.radialDirectionalWeightsMarginal,
+ self.verbosity >= 5,
+ self.polydegreetypeMarginal == "TOTAL",
+ {"derIdxs": self._derMIdxs,
+ "reorder": self._reorderM,
+ "scl": np.power(self.scaleFactorMarginal, -1.),
+ "nNearestNeighbor" : self.nNearestNeighborMarginal})
vbMng(self, "MAIN", msg, 5)
if wellCond: break
RROMPyWarning(("Polyfit is poorly conditioned. Reducing "
"MMarginal by 1."))
- self.MMarginal -= 1
- if self.MMarginal < 0:
- raise RROMPyException(("Instability in computation of "
- "marginal interpolator. Aborting."))
+ self.MMarginal = self.MMarginal - 1
mI = mI + [copy(p)]
vbMng(self, "DEL", "Done computing marginal interpolator.", 7)
return mI
- def normApprox(self, mu:paramList, homogeneized : bool = False) -> float:
+ def normApprox(self, mu:paramList) -> float:
"""
Compute norm of approximant at arbitrary parameter.
Args:
mu: Target parameter.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
Returns:
Target norm of approximant.
"""
- if not self.POD or self.homogeneized != homogeneized:
- return super().normApprox(mu, homogeneized)
+ if not self.POD: return super().normApprox(mu)
return np.linalg.norm(self.getApproxReduced(mu).data, axis = 0)
def computeScaleFactor(self):
"""Compute parameter rescaling factor."""
RROMPyAssert(self._mode, message = "Cannot compute rescaling factor.")
self.scaleFactorPivot = .5 * np.abs(
self.muBoundsPivot[0] ** self.rescalingExpPivot
- self.muBoundsPivot[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 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.mu0.
-
- Returns:
- Normalized parameter.
- """
- return self.trainedModel.centerNormalizeMarginal(mu, mu0)
-
diff --git a/rrompy/reduction_methods/pivoted/rational_interpolant_pivoted.py b/rrompy/reduction_methods/pivoted/rational_interpolant_pivoted.py
index 33ec944..fccec16 100644
--- a/rrompy/reduction_methods/pivoted/rational_interpolant_pivoted.py
+++ b/rrompy/reduction_methods/pivoted/rational_interpolant_pivoted.py
@@ -1,614 +1,624 @@
# 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_pivoted_approximant import GenericPivotedApproximant
from rrompy.reduction_methods.standard.rational_interpolant import (
RationalInterpolant as RI)
-from rrompy.utilities.poly_fitting.polynomial import (polybases, polyfitname,
- nextDerivativeIndices,
- hashDerivativeToIdx as hashD,
- hashIdxToDerivative as hashI,
- homogeneizedpolyvander as hpvP,
- homogeneizedToFull,
- PolynomialInterpolator as PI)
-from rrompy.utilities.poly_fitting.radial_basis import (rbbases,
+from rrompy.utilities.poly_fitting.polynomial import (
+ polybases as ppb, polyfitname,
+ polyvander as pvP, polyvanderTotal as pvTP,
+ 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 (
+ polybases as mlspb,
+ MovingLeastSquaresInterpolator as MLSI)
from rrompy.reduction_methods.trained_model import (TrainedModelPivotedData,
TrainedModelPivotedRational as tModel)
from rrompy.utilities.base.types import (Np1D, Np2D, HFEng, DictAny, Tuple,
- List, ListAny, paramVal, paramList)
+ List, ListAny, paramVal)
from rrompy.utilities.base import verbosityManager as vbMng, freepar as fp
-from rrompy.utilities.numerical import multifactorial, customPInv
+from rrompy.utilities.numerical import (multifactorial, customPInv, dot,
+ fullDegreeN, totalDegreeN,
+ degreeTotalToFull, fullDegreeMaxMask,
+ totalDegreeMaxMask,
+ nextDerivativeIndices,
+ hashDerivativeToIdx as hashD,
+ hashIdxToDerivative as hashI)
from rrompy.utilities.exception_manager import (RROMPyException, RROMPyAssert,
RROMPyWarning)
from rrompy.parameter import checkParameter
__all__ = ['RationalInterpolantPivoted']
class RationalInterpolantPivoted(GenericPivotedApproximant):
"""
- ROM pivoted rational interpolant computation for parametric problems.
+ ROM pivoted rational interpolant (with pole matching) computation for
+ parametric problems.
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;
+ - 'matchingWeight': weight for pole matching optimization; defaults
+ to 1;
+ - 'cutOffTolerance': tolerance for ignoring parasitic poles;
+ defaults to np.inf;
+ - 'cutOffType': rule for tolerance computation for parasitic poles;
+ defaults to 'MAGNITUDE';
- '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;
- 'polybasisPivot': type of polynomial basis for pivot
- interpolation; allowed values include 'MONOMIAL', 'CHEBYSHEV'
- and 'LEGENDRE'; defaults to 'MONOMIAL';
+ interpolation; defaults to 'MONOMIAL';
- 'polybasisMarginal': type of polynomial basis for marginal
interpolation; allowed values include 'MONOMIAL', 'CHEBYSHEV'
and 'LEGENDRE'; defaults to 'MONOMIAL';
- - 'E': number of derivatives used to compute interpolant; defaults
- to 0;
- 'M': degree of rational interpolant numerator; defaults to 0;
- 'N': degree of rational interpolant denominator; defaults to 0;
+ - 'polydegreetype': type of polynomial degree; defaults to 'TOTAL';
- 'MMarginal': degree of marginal interpolant; defaults to 0;
- - 'radialBasisPivot': radial basis family for pivot numerator;
- defaults to 0, i.e. no radial basis;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant; defaults to 0, i.e. no radial basis;
- - 'radialBasisWeightsPivot': radial basis weights for pivot
+ - 'polydegreetypeMarginal': type of polynomial degree for marginal;
+ defaults to 'TOTAL';
+ - 'radialDirectionalWeightsPivot': radial basis weights for pivot
numerator; defaults to 0, i.e. identity;
- - 'radialBasisWeightsMarginal': radial basis weights for marginal
- interpolant; defaults to 0, i.e. identity;
+ - 'radialDirectionalWeightsMarginal': radial basis weights for
+ marginal interpolant; defaults to 0, i.e. identity;
+ - 'nNearestNeighborPivot': number of pivot nearest neighbors
+ considered if polybasisPivot allows; defaults to -1;
+ - 'nNearestNeighborMarginal': number of marginal nearest neighbors
+ considered if polybasisMarginal allows; defaults to -1;
- 'interpRcondPivot': tolerance for pivot interpolation; defaults
to None;
- 'interpRcondMarginal': tolerance for marginal interpolation;
defaults to None;
- 'robustTol': tolerance for robust rational denominator
management; defaults to 0.
Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. 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.
musPivot: Array of pivot snapshot parameters.
musMarginal: Array of marginal snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
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;
+ - 'matchingWeight': weight for pole matching optimization;
+ - 'cutOffTolerance': tolerance for ignoring parasitic poles;
+ - 'cutOffType': rule for tolerance computation for parasitic poles;
- 'polybasisPivot': type of polynomial basis for pivot
interpolation;
- 'polybasisMarginal': type of polynomial basis for marginal
interpolation;
- - 'E': number of derivatives used to compute interpolant;
- 'M': degree of rational interpolant numerator;
- 'N': degree of rational interpolant denominator;
+ - 'polydegreetype': type of polynomial degree;
- 'MMarginal': degree of marginal interpolant;
- - 'radialBasisPivot': radial basis family for pivot numerator;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant;
- - 'radialBasisWeightsPivot': radial basis weights for pivot
+ - 'polydegreetypeMarginal': type of polynomial degree for marginal;
+ - 'radialDirectionalWeightsPivot': radial basis weights for pivot
numerator;
- - 'radialBasisWeightsMarginal': radial basis weights for marginal
- interpolant;
+ - 'radialDirectionalWeightsMarginal': radial basis weights for
+ marginal interpolant;
+ - 'nNearestNeighborPivot': number of pivot nearest neighbors
+ considered if polybasisPivot allows;
+ - 'nNearestNeighborMarginal': number of marginal nearest neighbors
+ considered if polybasisMarginal allows;
- 'interpRcondPivot': tolerance for pivot interpolation;
- 'interpRcondMarginal': tolerance for marginal interpolation;
- 'robustTol': tolerance for robust rational denominator
management.
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.
POD: Whether to compute POD of snapshots.
+ matchingWeight: Weight for pole matching optimization.
+ cutOffTolerance: Tolerance for ignoring parasitic poles.
+ cutOffType: Rule for tolerance computation for parasitic poles.
S: Total number of pivot samples current approximant relies upon.
sampler: Pivot sample point generator.
polybasisPivot: Type of polynomial basis for pivot interpolation.
polybasisMarginal: Type of polynomial basis for marginal interpolation.
M: Numerator degree of approximant.
N: Denominator degree of approximant.
+ polydegreetype: Type of polynomial degree.
MMarginal: Degree of marginal interpolant.
- radialBasisPivot: Radial basis family for pivot numerator.
- radialBasisMarginal: Radial basis family for marginal interpolant.
- radialBasisWeightsPivot: Radial basis weights for pivot numerator.
- radialBasisWeightsMarginal: Radial basis weights for marginal
+ polydegreetypeMarginal: Type of polynomial degree for marginal.
+ radialDirectionalWeightsPivot: Radial basis weights for pivot
+ numerator.
+ radialDirectionalWeightsMarginal: Radial basis weights for marginal
interpolant.
+ nNearestNeighborPivot: Number of pivot nearest neighbors considered if
+ polybasisPivot allows.
+ nNearestNeighborMarginal: Number of marginal nearest neighbors
+ considered if polybasisMarginal allows.
interpRcondPivot: Tolerance for pivot interpolation.
interpRcondMarginal: Tolerance for marginal interpolation.
robustTol: Tolerance for robust rational denominator management.
- E: Complete derivative depth level of S.
muBoundsPivot: 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.
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, HFEngine:HFEng, mu0 : paramVal = None,
directionPivot : ListAny = [0],
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
+ approxParameters : DictAny = {}, verbosity : int = 10,
+ timestamp : bool = True):
self._preInit()
- self._addParametersToList(
- ["polybasisPivot", "E", "M", "N",
- "radialBasisPivot", "radialBasisWeightsPivot",
- "interpRcondPivot", "robustTol"],
- ["MONOMIAL", -1, 0, 0, 0, 1, -1, 0])
+ self._addParametersToList(["polybasisPivot", "M", "N",
+ "polydegreetype",
+ "radialDirectionalWeightsPivot",
+ "nNearestNeighborPivot",
+ "interpRcondPivot", "robustTol"],
+ ["MONOMIAL", 0, 0, "TOTAL", 1, -1, -1, 0])
super().__init__(HFEngine = HFEngine, mu0 = mu0,
directionPivot = directionPivot,
approxParameters = approxParameters,
- homogeneized = homogeneized,
verbosity = verbosity, timestamp = timestamp)
self._postInit()
@property
def polybasisPivot(self):
"""Value of polybasisPivot."""
return self._polybasisPivot
@polybasisPivot.setter
def polybasisPivot(self, polybasisPivot):
try:
polybasisPivot = polybasisPivot.upper().strip().replace(" ","")
- if polybasisPivot not in polybases:
+ if polybasisPivot not in ppb + rbpb + mlspb:
raise RROMPyException(
"Prescribed pivot polybasis not recognized.")
self._polybasisPivot = polybasisPivot
except:
RROMPyWarning(("Prescribed pivot polybasis not recognized. "
"Overriding to 'MONOMIAL'."))
self._polybasisPivot = "MONOMIAL"
self._approxParameters["polybasisPivot"] = self.polybasisPivot
@property
- def radialBasisPivot(self):
- """Value of radialBasisPivot."""
- return self._radialBasisPivot
- @radialBasisPivot.setter
- def radialBasisPivot(self, radialBasisPivot):
- try:
- if radialBasisPivot != 0:
- radialBasisPivot = radialBasisPivot.upper().strip().replace(
- " ","")
- if radialBasisPivot not in rbbases:
- raise RROMPyException(("Prescribed pivot radialBasis not "
- "recognized."))
- self._radialBasisPivot = radialBasisPivot
- except:
- RROMPyWarning(("Prescribed pivot radialBasis not recognized. "
- "Overriding to 0."))
- self._radialBasisPivot = 0
- self._approxParameters["radialBasisPivot"] = self.radialBasisPivot
+ def polybasisPivot0(self):
+ if "_" in self.polybasisPivot:
+ return self.polybasisPivot.split("_")[0]
+ return self.polybasisPivot
@property
- def radialBasisWeightsPivot(self):
- """Value of radialBasisWeightsPivot."""
- return self._radialBasisWeightsPivot
- @radialBasisWeightsPivot.setter
- def radialBasisWeightsPivot(self, radialBasisWeightsPivot):
- self._radialBasisWeightsPivot = radialBasisWeightsPivot
- self._approxParameters["radialBasisWeightsPivot"] = (
- self.radialBasisWeightsPivot)
+ def radialDirectionalWeightsPivot(self):
+ """Value of radialDirectionalWeightsPivot."""
+ return self._radialDirectionalWeightsPivot
+ @radialDirectionalWeightsPivot.setter
+ def radialDirectionalWeightsPivot(self, radialDirectionalWeightsPivot):
+ self._radialDirectionalWeightsPivot = radialDirectionalWeightsPivot
+ self._approxParameters["radialDirectionalWeightsPivot"] = (
+ self.radialDirectionalWeightsPivot)
@property
- def polybasisPivotP(self):
- if self.radialBasisPivot == 0:
- return self._polybasisPivot
- return self._polybasisPivot + "_" + self.radialBasisPivot
+ def nNearestNeighborPivot(self):
+ """Value of nNearestNeighborPivot."""
+ return self._nNearestNeighborPivot
+ @nNearestNeighborPivot.setter
+ def nNearestNeighborPivot(self, nNearestNeighborPivot):
+ self._nNearestNeighborPivot = nNearestNeighborPivot
+ self._approxParameters["nNearestNeighborPivot"] = (
+ self.nNearestNeighborPivot)
@property
def interpRcondPivot(self):
"""Value of interpRcondPivot."""
return self._interpRcondPivot
@interpRcondPivot.setter
def interpRcondPivot(self, interpRcondPivot):
self._interpRcondPivot = interpRcondPivot
self._approxParameters["interpRcondPivot"] = self.interpRcondPivot
@property
def M(self):
- """Value of M. Its assignment may change S."""
+ """Value of M."""
return self._M
@M.setter
def M(self, M):
if M < 0: raise RROMPyException("M must be non-negative.")
self._M = M
self._approxParameters["M"] = self.M
- if hasattr(self, "_E") and self.E >= 0 and self.E < self.M:
- RROMPyWarning("Prescribed S is too small. Decreasing M.")
- self.M = self.E
@property
def N(self):
- """Value of N. Its assignment may change S."""
+ """Value of N."""
return self._N
@N.setter
def N(self, N):
if N < 0: raise RROMPyException("N must be non-negative.")
self._N = N
self._approxParameters["N"] = self.N
- if hasattr(self, "_E") and self.E >= 0 and self.E < self.N:
- RROMPyWarning("Prescribed S is too small. Decreasing N.")
- self.N = self.E
@property
- def E(self):
- """Value of E."""
- return self._E
- @E.setter
- def E(self, E):
- if E < 0:
- if not hasattr(self, "_S"):
- raise RROMPyException(("Value of E must be positive if S is "
- "not yet assigned."))
- E = np.sum(hashI(np.prod(self.S), len(self.directionPivot))) - 1
- self._E = E
- self._approxParameters["E"] = self.E
- if (hasattr(self, "_S")
- and self.E >= np.sum(hashI(np.prod(self.S),len(self.directionPivot)))):
- RROMPyWarning("Prescribed S is too small. Decreasing E.")
- self.E = -1
- if hasattr(self, "_M"): self.M = self.M
- if hasattr(self, "_N"): self.N = self.N
+ 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 S(self):
- """Value of S."""
- return self._S
- @S.setter
- def S(self, S):
- GenericPivotedApproximant.S.fset(self, S)
- if hasattr(self, "_M"): self.M = self.M
- if hasattr(self, "_N"): self.N = self.N
- if hasattr(self, "_E"): self.E = self.E
-
def resetSamples(self):
"""Reset samples."""
super().resetSamples()
self._musPUniqueCN = None
self._derPIdxs = None
self._reorderP = None
def _setupPivotInterpolationIndices(self):
"""Setup parameters for polyvander."""
RROMPyAssert(self._mode,
message = "Cannot setup interpolation indices.")
if (self._musPUniqueCN is None
or len(self._reorderP) != len(self.musPivot)):
self._musPUniqueCN, musPIdxsTo, musPIdxs, musPCount = (
- self.centerNormalizePivot(self.musPivot).unique(
- return_index = True,
- return_inverse = True,
- return_counts = True))
+ self.trainedModel.centerNormalizePivot(self.musPivot).unique(
+ return_index = True, return_inverse = True,
+ return_counts = True))
self._musPUnique = self.mus[musPIdxsTo]
self._derPIdxs = [None] * len(self._musPUniqueCN)
self._reorderP = np.empty(len(musPIdxs), dtype = int)
filled = 0
for j, cnt in enumerate(musPCount):
self._derPIdxs[j] = nextDerivativeIndices([],
- self.musPivot.shape[1], cnt)
+ self.nparPivot, cnt)
jIdx = np.nonzero(musPIdxs == j)[0]
self._reorderP[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)
NinvD = None
N0 = copy(self.N)
qs = []
self.verbosity -= 10
for j in range(len(self.musMarginal)):
self._N = N0
while self.N > 0:
if NinvD != self.N:
invD, fitinvP = self._computeInterpolantInverseBlocks()
NinvD = self.N
if self.POD:
ev, eV = RI.findeveVGQR(self, self.samplingEngine.RPOD[j],
invD)
else:
ev, eV = RI.findeveVGExplicit(self,
self.samplingEngine.samples[j], invD)
nevBad = checkRobustTolerance(ev, self.robustTol)
if nevBad <= 1: break
if self.catchInstability:
raise RROMPyException(("Instability in denominator "
"computation: eigenproblem is "
"poorly conditioned."))
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.musPivot.shape[1]
- q.polybasis = self.polybasisPivot
- q.coeffs = homogeneizedToFull(tuple([self.N + 1] * q.npar),
- q.npar, eV[:, 0])
+ q.npar = self.nparPivot
+ q.polybasis = self.polybasisPivot0
+ if self.polydegreetype == "TOTAL":
+ q.coeffs = degreeTotalToFull(tuple([self.N + 1] * q.npar),
+ q.npar, eV[:, 0])
+ else:
+ q.coeffs = eV[:, 0].reshape([self.N + 1] * q.npar)
qs = qs + [copy(q)]
self.verbosity += 10
vbMng(self, "DEL", "Done computing denominator.", 7)
return qs, fitinvP
def _setupNumerator(self):
"""Compute rational numerator."""
RROMPyAssert(self._mode, message = "Cannot setup numerator.")
vbMng(self, "INIT", "Starting computation of numerator.", 7)
Qevaldiag = np.zeros((len(self.musPivot), len(self.musPivot)),
dtype = np.complex)
verb = self.trainedModel.verbosity
self.trainedModel.verbosity = 0
self._setupPivotInterpolationIndices()
- M0 = copy(self.M)
+ cfun = totalDegreeN if self.polydegreetype == "TOTAL" else fullDegreeN
+ M = copy(self.M)
+ while len(self.musPivot) < cfun(M, self.nparPivot): M -= 1
+ if M < self.M:
+ RROMPyWarning(("M too large compared to S. Reducing M by "
+ "{}").format(self.M - M))
+ self.M = M
tensor_idx = 0
ps = []
for k, muM in enumerate(self.musMarginal):
- self._M = M0
+ self._M = M
idxGlob = 0
for j, derIdxs in enumerate(self._derPIdxs):
mujEff = [fp] * self.npar
for jj, kk in enumerate(self.directionPivot):
mujEff[kk] = self._musPUnique[j, jj]
for jj, kk in enumerate(self.directionMarginal):
mujEff[kk] = muM(0, jj)
mujEff = checkParameter(mujEff, self.npar)
nder = len(derIdxs)
idxLoc = np.arange(len(self.musPivot))[
(self._reorderP >= idxGlob)
* (self._reorderP < idxGlob + nder)]
idxGlob += nder
Qval = [0] * nder
for der in range(nder):
- derIdx = hashI(der, self.musPivot.shape[1])
+ derIdx = hashI(der, self.nparPivot)
derIdxEff = [0] * self.npar
sclEff = [0] * self.npar
for jj, kk in enumerate(self.directionPivot):
derIdxEff[kk] = derIdx[jj]
sclEff[kk] = self.scaleFactorPivot[jj] ** -1.
Qval[der] = (self.trainedModel.getQVal(mujEff, derIdxEff,
scl = sclEff)
/ multifactorial(derIdx))
for derU, derUIdx in enumerate(derIdxs):
for derQ, derQIdx in enumerate(derIdxs):
diffIdx = [x - y for (x, y) in zip(derUIdx, derQIdx)]
if all([x >= 0 for x in diffIdx]):
diffj = hashD(diffIdx)
Qevaldiag[idxLoc[derU], idxLoc[derQ]] = Qval[diffj]
while self.M >= 0:
- if self.radialBasisPivot == 0:
+ if self.polybasisPivot in ppb:
p = PI()
wellCond, msg = p.setupByInterpolation(
- self._musPUniqueCN, Qevaldiag, self.M,
- self.polybasisPivotP, self.verbosity >= 5, True,
- {"derIdxs": self._derPIdxs,
- "reorder": self._reorderP,
- "scl": np.power(self.scaleFactorPivot, -1.)},
- {"rcond": self.interpRcondPivot})
- else:
+ self._musPUniqueCN, Qevaldiag, self.M,
+ self.polybasisPivot, self.verbosity >= 5,
+ self.polydegreetype == "TOTAL",
+ {"derIdxs": self._derPIdxs,
+ "reorder": self._reorderP,
+ "scl": np.power(self.scaleFactorPivot, -1.)},
+ {"rcond": self.interpRcondPivot})
+ elif self.polybasisPivot in rbpb:
p = RBI()
wellCond, msg = p.setupByInterpolation(
self._musPUniqueCN, Qevaldiag, self.M,
- self.polybasisPivotP,
- self.radialBasisWeightsPivot,
- self.verbosity >= 5, True,
+ self.polybasisPivot,
+ self.radialDirectionalWeightsPivot,
+ self.verbosity >= 5,
+ self.polydegreetype == "TOTAL",
{"derIdxs": self._derPIdxs,
- "reorder": self._reorderP,
- "scl": np.power(self.scaleFactorPivot, -1.)},
+ "reorder": self._reorderP,
+ "scl": np.power(self.scaleFactorPivot, -1.),
+ "nNearestNeighbor" : self.nNearestNeighborPivot},
{"rcond": self.interpRcondPivot})
+ else:# if self.polybasisPivot in mlspb:
+ p = MLSI()
+ wellCond, msg = p.setupByInterpolation(
+ self._musPUniqueCN, Qevaldiag, self.M,
+ self.polybasisPivot,
+ self.radialDirectionalWeightsPivot,
+ self.verbosity >= 5,
+ self.polydegreetype == "TOTAL",
+ {"derIdxs": self._derPIdxs,
+ "reorder": self._reorderP,
+ "scl": np.power(self.scaleFactorPivot, -1.),
+ "nNearestNeighbor" : self.nNearestNeighborPivot})
vbMng(self, "MAIN", msg, 5)
if wellCond: break
if self.catchInstability:
raise RROMPyException(("Instability in numerator "
"computation: polyfit is "
"poorly conditioned."))
RROMPyWarning(("Polyfit is poorly conditioned. "
"Reducing M by 1."))
- self.M -= 1
- if self.M < 0:
- raise RROMPyException(("Instability in computation of "
- "numerator. Aborting."))
+ self.M = self.M - 1
tensor_idx_new = tensor_idx + Qevaldiag.shape[1]
if self.POD:
p.postmultiplyTensorize(self.samplingEngine.RPODCoalesced.T[
tensor_idx : tensor_idx_new, :])
else:
p.pad(tensor_idx, len(self.mus) - tensor_idx_new)
tensor_idx = tensor_idx_new
ps = ps + [copy(p)]
self.trainedModel.verbosity = verb
vbMng(self, "DEL", "Done computing numerator.", 7)
return ps
def setupApprox(self):
"""
Compute rational interpolant.
SVD-based robust eigenvalue management.
"""
if self.checkComputedApprox():
return
RROMPyAssert(self._mode, message = "Cannot setup approximant.")
vbMng(self, "INIT", "Setting up {}.". format(self.name()), 5)
- self.computeScaleFactor()
self.computeSnapshots()
if self.trainedModel is None:
self.trainedModel = tModel()
self.trainedModel.verbosity = self.verbosity
self.trainedModel.timestamp = self.timestamp
data = TrainedModelPivotedData(self.trainedModel.name(), self.mu0,
self.samplingEngine.samplesCoalesced,
self.scaleFactor,
self.HFEngine.rescalingExp,
self.directionPivot)
data.musPivot = copy(self.musPivot)
data.musMarginal = copy(self.musMarginal)
self.trainedModel.data = data
else:
self.trainedModel = self.trainedModel
- self.trainedModel.data.projMat = copy(self.samplingEngine.samples)
+ self.trainedModel.data.projMat = copy(
+ self.samplingEngine.samplesCoalesced)
self.trainedModel.data.marginalInterp = self._setupMarginalInterp()
if self.N > 0:
Qs = self._setupDenominator()[0]
else:
Q = PI()
- Q.npar = self.musPivot.shape[1]
- Q.coeffs = np.ones(tuple([1] * Q.npar), dtype = np.complex)
- Q.polybasis = self.polybasisPivot
+ Q.npar = self.nparPivot
+ Q.coeffs = np.ones(tuple([1] * Q.npar),
+ dtype = self.musMarginal.dtype)
+ Q.polybasis = self.polybasisPivot0
Qs = [Q for _ in range(len(self.musMarginal))]
+ self.trainedModel.data._temporary = True
self.trainedModel.data.Qs = Qs
self.trainedModel.data.Ps = self._setupNumerator()
+ vbMng(self, "INIT", "Matching poles.", 10)
+ self.trainedModel.initializeFromRational(self.HFEngine,
+ self.matchingWeight, self.POD)
+ vbMng(self, "DEL", "Done matching poles.", 10)
+ if not np.isinf(self.cutOffTolerance):
+ vbMng(self, "INIT", "Recompressing by cut-off.", 10)
+ msg = self.trainedModel.recompressByCutOff([-1., 1.],
+ self.cutOffTolerance,
+ self.cutOffType)
+ vbMng(self, "DEL", "Done recompressing." + msg, 10)
self.trainedModel.data.approxParameters = copy(self.approxParameters)
vbMng(self, "DEL", "Done setting up approximant.", 5)
def _computeInterpolantInverseBlocks(self) -> Tuple[List[Np2D], Np2D]:
"""
Compute inverse factors for minimal interpolant target functional.
"""
RROMPyAssert(self._mode, message = "Cannot solve eigenvalue problem.")
self._setupPivotInterpolationIndices()
- while self.E >= 0:
- eWidth = (hashD([self.E + 1] + [0] * (self.musPivot.shape[1] - 1))
- - hashD([self.E] + [0] * (self.musPivot.shape[1] - 1)))
- TE, _, argIdxs = hpvP(self._musPUniqueCN, self.E,
- self.polybasisPivot, self._derPIdxs,
- self._reorderP,
- scl = np.power(self.scaleFactorPivot, -1.))
- fitOut = customPInv(TE[:, argIdxs], rcond = self.interpRcondPivot,
+ cfun = totalDegreeN if self.polydegreetype == "TOTAL" else fullDegreeN
+ N = copy(self.N)
+ while len(self.musPivot) < cfun(N, self.nparPivot): N -= 1
+ 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:
+ if self.polydegreetype == "TOTAL":
+ TE, _, argIdxs = pvTP(self._musPUniqueCN, self.N,
+ self.polybasisPivot0, self._derPIdxs,
+ self._reorderP,
+ scl = np.power(self.scaleFactorPivot, -1.))
+ TE = TE[:, argIdxs]
+ idxsB = totalDegreeMaxMask(self.N, self.nparPivot)
+ else: #if self.polydegreetype == "FULL":
+ TE = pvP(self._musPUniqueCN, [self.N] * self.nparPivot,
+ self.polybasisPivot0, self._derPIdxs, self._reorderP,
+ scl = np.power(self.scaleFactorPivot, -1.))
+ idxsB = fullDegreeMaxMask(self.N, self.nparPivot)
+ fitOut = customPInv(TE, rcond = self.interpRcondPivot,
full = True)
vbMng(self, "MAIN",
("Fitting {} samples with degree {} through {}... "
"Conditioning of pseudoinverse system: {:.4e}.").format(
- TE.shape[0], self.E,
- polyfitname(self.polybasisPivot),
+ TE.shape[0], self.N,
+ polyfitname(self.polybasisPivot0),
fitOut[1][1][0] / fitOut[1][1][-1]),
5)
- if fitOut[1][0] == len(argIdxs):
- fitinvP = fitOut[0][- eWidth : , :]
+ if fitOut[1][0] == TE.shape[1]:
+ fitinvP = fitOut[0][idxsB, :]
break
- RROMPyWarning("Polyfit is poorly conditioned. Reducing E by 1.")
- self.E -= 1
- if self.E < 0:
+ RROMPyWarning("Polyfit is poorly conditioned. Reducing N by 1.")
+ self.N -= 1
+ if self.N < 0:
raise RROMPyException(("Instability in computation of "
"denominator. Aborting."))
- TN, _, argIdxs = hpvP(self._musPUniqueCN, self.N, self.polybasisPivot,
+ TN, _, argIdxs = pvTP(self._musPUniqueCN, self.N, self.polybasisPivot0,
self._derPIdxs, self._reorderP,
scl = np.power(self.scaleFactorPivot, -1.))
TN = TN[:, argIdxs]
- invD = [None] * (eWidth)
- for k in range(eWidth):
+ invD = [None] * (len(idxsB))
+ for k in range(len(idxsB)):
pseudoInv = np.diag(fitinvP[k, :])
idxGlob = 0
for j, derIdxs in enumerate(self._derPIdxs):
nder = len(derIdxs)
idxGlob += nder
if nder > 1:
idxLoc = np.arange(len(self.musPivot))[
(self._reorderP >= idxGlob - nder)
* (self._reorderP < idxGlob)]
invLoc = fitinvP[k, idxLoc]
pseudoInv[np.ix_(idxLoc, idxLoc)] = 0.
for diffj, diffjIdx in enumerate(derIdxs):
for derQ, derQIdx in enumerate(derIdxs):
derUIdx = [x - y for (x, y) in
zip(diffjIdx, derQIdx)]
if all([x >= 0 for x in derUIdx]):
derU = hashD(derUIdx)
pseudoInv[idxLoc[derU], idxLoc[derQ]] = (
invLoc[diffj])
- invD[k] = pseudoInv.dot(TN)
+ invD[k] = dot(pseudoInv, TN)
return invD, fitinvP
- def centerNormalize(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.mu0.
-
- Returns:
- Normalized parameter.
- """
- return self.trainedModel.centerNormalize(mu, mu0)
-
- def centerNormalizePivot(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.mu0.
-
- Returns:
- Normalized parameter.
- """
- return self.trainedModel.centerNormalizePivot(mu, mu0)
-
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/pivoted/reduced_basis_pivoted.py b/rrompy/reduction_methods/pivoted/reduced_basis_pivoted.py
deleted file mode 100644
index 1200f83..0000000
--- a/rrompy/reduction_methods/pivoted/reduced_basis_pivoted.py
+++ /dev/null
@@ -1,285 +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 .generic_pivoted_approximant import GenericPivotedApproximant
-from rrompy.hfengines.base import MarginalProxyEngine
-from rrompy.reduction_methods.trained_model import (TrainedModelPivotedData,
- TrainedModelPivotedReducedBasis as tModel)
-from rrompy.reduction_methods.base.reduced_basis_utils import \
- projectAffineDecomposition
-from rrompy.utilities.base.types import (Np1D, Np2D, List, ListAny, Tuple,
- DictAny, HFEng, paramVal, sampList)
-from rrompy.utilities.base import verbosityManager as vbMng, freepar as fp
-from rrompy.utilities.numerical import customPInv
-from rrompy.utilities.exception_manager import (RROMPyWarning, RROMPyException,
- RROMPyAssert)
-
-__all__ = ['ReducedBasisPivoted']
-
-class ReducedBasisPivoted(GenericPivotedApproximant):
- """
- ROM pivoted RB approximant computation for parametric problems.
-
- 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;
- - '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;
- - 'R': rank for pivot Galerkin projection; defaults to prod(S);
- - 'PODTolerance': tolerance for pivot snapshots POD; defaults to
- -1;
- - '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 0;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant; defaults to 0, i.e. no radial basis;
- - 'radialBasisWeightsMarginal': radial basis weights for marginal
- interpolant; defaults to 0, i.e. identity;
- - 'interpRcondMarginal': tolerance for marginal interpolation;
- defaults to None.
- Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. 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.
- homogeneized: Whether to homogeneize Dirichlet BCs.
- approxRadius: Dummy radius of approximant (i.e. distance from mu0 to
- farthest sample point).
- 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;
- - 'R': rank for Galerkin projection;
- - 'PODTolerance': tolerance for snapshots POD;
- - 'polybasisMarginal': type of polynomial basis for marginal
- interpolation;
- - 'MMarginal': degree of marginal interpolant;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant;
- - 'radialBasisWeightsMarginal': 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.
- POD: Whether to compute POD of snapshots.
- 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.
- R: Rank for Galerkin projection.
- PODTolerance: Tolerance for pivot snapshots POD.
- polybasisMarginal: Type of polynomial basis for marginal interpolation.
- MMarginal: Degree of marginal interpolant.
- radialBasisMarginal: Radial basis family for marginal interpolant.
- radialBasisWeightsMarginal: Radial basis weights for marginal
- interpolant.
- interpRcondMarginal: Tolerance for marginal interpolation.
- muBoundsPivot: 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.
- As: List of sparse matrices (in CSC format) representing coefficients
- of linear system matrix.
- bs: List of numpy vectors representing coefficients of linear system
- RHS.
- ARBs: List of sparse matrices (in CSC format) representing coefficients
- of compressed linear system matrix.
- bRBs: List of numpy vectors representing coefficients of compressed
- linear system RHS.
- """
-
- def __init__(self, HFEngine:HFEng, mu0 : paramVal = None,
- directionPivot : ListAny = [0],
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
- self._preInit()
- self._addParametersToList(["R", "PODTolerance"], [1, -1])
- super().__init__(HFEngine = HFEngine, mu0 = mu0,
- directionPivot = directionPivot,
- approxParameters = approxParameters,
- homogeneized = homogeneized,
- verbosity = verbosity, timestamp = timestamp)
- self._postInit()
-
- @property
- def S(self):
- """Value of S."""
- return self._S
- @S.setter
- def S(self, S):
- GenericPivotedApproximant.S.fset(self, S)
- if not hasattr(self, "_R"):
- self._R = np.prod(self.S) * np.prod(self.SMarginal)
-
- @property
- def R(self):
- """Value of R. Its assignment may change S."""
- return self._R
- @R.setter
- def R(self, R):
- if R < 0: raise RROMPyException("R must be non-negative.")
- self._R = R
- self._approxParameters["R"] = self.R
- if (hasattr(self, "_S") and hasattr(self, "_SMarginal")
- and np.prod(self.S) * np.prod(self.SMarginal) < self.R):
- RROMPyWarning(("Prescribed S and SMarginal are too small. "
- "Decreasing R."))
- self.R = np.prod(self.S) * np.prod(self.SMarginal)
-
- @property
- def PODTolerance(self):
- """Value of PODTolerance."""
- return self._PODTolerance
- @PODTolerance.setter
- def PODTolerance(self, PODTolerance):
- self._PODTolerance = PODTolerance
- self._approxParameters["PODTolerance"] = self.PODTolerance
-
- def _setupProjectionMatrix(self):
- """Compute projection matrix."""
- RROMPyAssert(self._mode, message = "Cannot setup numerator.")
- vbMng(self, "INIT", "Starting computation of projection matrix.", 7)
- if self.POD:
- U, s, _ = np.linalg.svd(self.samplingEngine.RPODCoalesced)
- s = s ** 2.
- else:
- Gramian = self.HFEngine.innerProduct(
- self.samplingEngine.samplesCoalesced,
- self.samplingEngine.samplesCoalesced)
- U, s, _ = np.linalg.svd(Gramian)
- nsamples = self.samplingEngine.samplesCoalesced.shape[1]
- snorm = np.cumsum(s[::-1]) / np.sum(s)
- nPODTrunc = min(nsamples - np.argmax(snorm > self.PODTolerance),
- self.R)
- pMat = self.samplingEngine.samplesCoalesced.dot(U[:, : nPODTrunc])
- vbMng(self, "MAIN",
- "Assembling {}x{} projection matrix from {} samples.".format(
- *(pMat.shape), nsamples), 5)
- vbMng(self, "DEL", "Done computing projection matrix.", 7)
- return pMat
-
- def _setupAffineBlocks(self):
- """Compute list of marginalized affine blocks of system."""
- hasAs = hasattr(self, "AsList") and self.AsList is not None
- hasbs = hasattr(self, "bsList") and self.bsList is not None
- if hasAs and hasbs: return
- vbMng(self, "INIT", "Computing affine blocks of system.", 10)
- mu0Eff = self.mu0.data[0, self.directionPivot]
- if not hasAs: self.AsList = [None] * len(self.musMarginal)
- if not hasbs: self.bsList = [None] * len(self.musMarginal)
- for k, muM in enumerate(self.musMarginal):
- muEff = [fp] * self.npar
- for jj, kk in enumerate(self.directionMarginal):
- muEff[kk] = muM(0, jj)
- MEnginek = MarginalProxyEngine(self.HFEngine, muEff)
- if not hasAs:
- self.AsList[k] = MEnginek.affineLinearSystemA(mu0Eff,
- self.scaleFactorPivot)
- if not hasbs:
- self.bsList[k] = MEnginek.affineLinearSystemb(mu0Eff,
- self.scaleFactorPivot,
- self.homogeneized)
- vbMng(self, "DEL", "Done computing affine blocks.", 10)
-
- def setupApprox(self):
- """Compute RB projection matrix."""
- if self.checkComputedApprox():
- return
- RROMPyAssert(self._mode, message = "Cannot setup approximant.")
- vbMng(self, "INIT", "Setting up {}.".format(self.name()), 5)
- self.computeScaleFactor()
- self.computeSnapshots()
- self._setupAffineBlocks()
- pMat = self._setupProjectionMatrix()
- ARBsList, bRBsList, pList = self.assembleReducedSystemMarginal(pMat)
- if self.trainedModel is None:
- self.trainedModel = tModel()
- self.trainedModel.verbosity = self.verbosity
- self.trainedModel.timestamp = self.timestamp
- data = TrainedModelPivotedData(self.trainedModel.name(), self.mu0,
- pList, self.scaleFactor,
- self.HFEngine.rescalingExp,
- self.directionPivot)
- data.musPivot = copy(self.musPivot)
- data.musMarginal = copy(self.musMarginal)
- self.trainedModel.data = data
- else:
- self.trainedModel = self.trainedModel
- self.trainedModel.data.projMat = copy(pList)
- self.trainedModel.data.marginalInterp = self._setupMarginalInterp()
- self.trainedModel.data.ARBsList = ARBsList
- self.trainedModel.data.bRBsList = bRBsList
- self.trainedModel.data.approxParameters = copy(self.approxParameters)
- vbMng(self, "DEL", "Done setting up approximant.", 5)
-
- def assembleReducedSystemMarginal(self, pMat : sampList = None)\
- -> Tuple[List[List[Np2D]],
- List[List[Np1D]], List[Np2D]]:
- """Build affine blocks of RB linear system through projections."""
- if pMat is None:
- self.setupApprox()
- ARBsList = self.trainedModel.data.ARBsList
- bRBsList = self.trainedModel.data.bRBsList
- else:
- vbMng(self, "INIT", "Projecting affine terms of HF model.", 10)
- ARBsList = [None] * len(self.musMarginal)
- bRBsList = [None] * len(self.musMarginal)
- projList = [None] * len(self.musMarginal)
- for k, (As, bs, sample) in enumerate(zip(self.AsList, self.bsList,
- self.samplingEngine.samples)):
- compLocal = self.HFEngine.innerProduct(sample, pMat)
- projList[k] = sample.dot(customPInv(compLocal))
- ARBsList[k], bRBsList[k] = projectAffineDecomposition(As, bs,
- projList[k])
- vbMng(self, "DEL", "Done projecting affine terms.", 10)
- return ARBsList, bRBsList, projList
-
diff --git a/rrompy/reduction_methods/pole_matching/generic_pole_matching_approximant.py b/rrompy/reduction_methods/pole_matching/generic_pole_matching_approximant.py
deleted file mode 100644
index 660e7d9..0000000
--- a/rrompy/reduction_methods/pole_matching/generic_pole_matching_approximant.py
+++ /dev/null
@@ -1,179 +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 numpy import inf
-from rrompy.reduction_methods.pivoted.generic_pivoted_approximant import (
- GenericPivotedApproximant)
-from rrompy.utilities.base.types import ListAny, DictAny, HFEng, paramVal
-from rrompy.utilities.exception_manager import RROMPyException, RROMPyWarning
-
-__all__ = ['GenericPoleMatchingApproximant']
-
-class GenericPoleMatchingApproximant(GenericPivotedApproximant):
- """
- ROM pole matching approximant 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;
- - 'matchingWeight': weight for pole matching optimization; defaults
- to 1;
- - 'cutOffTolerance': tolerance for ignoring parasitic poles;
- defaults to np.inf;
- - 'cutOffType': rule for tolerance computation for parasitic poles;
- defaults to 'MAGNITUDE';
- - '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 0;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant; defaults to 0, i.e. no radial basis;
- - 'radialBasisWeightsMarginal': radial basis weights for marginal
- interpolant; defaults to 0, i.e. identity;
- - 'interpRcondMarginal': tolerance for marginal interpolation;
- defaults to None.
- Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. 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.
- musPivot: Array of pivot snapshot parameters.
- musMarginal: Array of marginal snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
- 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;
- - 'matchingWeight': weight for pole matching optimization;
- - 'cutOffTolerance': tolerance for ignoring parasitic poles;
- - 'cutOffType': rule for tolerance computation for parasitic poles;
- - 'polybasisMarginal': type of polynomial basis for marginal
- interpolation;
- - 'MMarginal': degree of marginal interpolant;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant;
- - 'radialBasisWeightsMarginal': 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.
- POD: Whether to compute POD of snapshots.
- matchingWeight: Weight for pole matching optimization.
- cutOffTolerance: Tolerance for ignoring parasitic poles.
- cutOffType: Rule for tolerance computation for 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.
- polybasisMarginal: Type of polynomial basis for marginal interpolation.
- MMarginal: Degree of marginal interpolant.
- radialBasisMarginal: Radial basis family for marginal interpolant.
- radialBasisWeightsMarginal: Radial basis weights for marginal
- interpolant.
- interpRcondMarginal: Tolerance for marginal interpolation.
- muBoundsPivot: 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, HFEngine:HFEng, mu0 : paramVal = None,
- directionPivot : ListAny = [0],
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
- self._preInit()
- if len(directionPivot) > 1:
- raise RROMPyException(("Exactly 1 pivot parameter allowed in pole "
- "matching."))
- self._addParametersToList(["matchingWeight", "cutOffTolerance",
- "cutOffType"], [1, inf, "MAGNITUDE"])
- super().__init__(HFEngine = HFEngine, mu0 = mu0,
- directionPivot = directionPivot,
- approxParameters = approxParameters,
- homogeneized = homogeneized,
- verbosity = verbosity, timestamp = timestamp)
- self._postInit()
-
- @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 cutOffTolerance(self):
- """Value of cutOffTolerance."""
- return self._cutOffTolerance
- @cutOffTolerance.setter
- def cutOffTolerance(self, cutOffTolerance):
- self._cutOffTolerance = cutOffTolerance
- self._approxParameters["cutOffTolerance"] = self.cutOffTolerance
-
- @property
- def cutOffType(self):
- """Value of cutOffType."""
- return self._cutOffType
- @cutOffType.setter
- def cutOffType(self, cutOffType):
- try:
- cutOffType = cutOffType.upper().strip().replace(" ","")
- if cutOffType not in ["MAGNITUDE", "POTENTIAL"]:
- raise RROMPyException("Prescribed cutOffType not recognized.")
- self._cutOffType = cutOffType
- except:
- RROMPyWarning(("Prescribed cutOffType not recognized. Overriding "
- "to 'MAGNITUDE'."))
- self._cutOffType = "MAGNITUDE"
- self._approxParameters["cutOffType"] = self.cutOffType
diff --git a/rrompy/reduction_methods/pole_matching/rational_interpolant_pole_matching.py b/rrompy/reduction_methods/pole_matching/rational_interpolant_pole_matching.py
deleted file mode 100644
index 5e33c96..0000000
--- a/rrompy/reduction_methods/pole_matching/rational_interpolant_pole_matching.py
+++ /dev/null
@@ -1,222 +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 rrompy.reduction_methods.pivoted.rational_interpolant_pivoted import \
- RationalInterpolantPivoted
-from .generic_pole_matching_approximant import GenericPoleMatchingApproximant
-from rrompy.utilities.poly_fitting.polynomial import (
- PolynomialInterpolator as PI)
-from rrompy.reduction_methods.trained_model import (TrainedModelPivotedData,
- TrainedModelPoleMatchingRational as tModel)
-from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.exception_manager import RROMPyAssert
-
-__all__ = ['RationalInterpolantPoleMatching']
-
-class RationalInterpolantPoleMatching(GenericPoleMatchingApproximant,
- RationalInterpolantPivoted):
- """
- ROM pivoted rational interpolant computation for parametric problems with
- pole matching.
-
- 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;
- - 'matchingWeight': weight for pole matching optimization; defaults
- to 1;
- - 'cutOffTolerance': tolerance for ignoring parasitic poles;
- defaults to np.inf;
- - 'cutOffType': rule for tolerance computation for parasitic poles;
- defaults to 'MAGNITUDE';
- - '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;
- - 'polybasisPivot': type of polynomial basis for pivot
- interpolation; allowed values include 'MONOMIAL', 'CHEBYSHEV'
- and 'LEGENDRE'; defaults to 'MONOMIAL';
- - 'polybasisMarginal': type of polynomial basis for marginal
- interpolation; allowed values include 'MONOMIAL', 'CHEBYSHEV'
- and 'LEGENDRE'; defaults to 'MONOMIAL';
- - 'E': number of derivatives used to compute interpolant; defaults
- to 0;
- - 'M': degree of rational interpolant numerator; defaults to 0;
- - 'N': degree of rational interpolant denominator; defaults to 0;
- - 'MMarginal': degree of marginal interpolant; defaults to 0;
- - 'radialBasisPivot': radial basis family for pivot numerator;
- defaults to 0, i.e. no radial basis;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant; defaults to 0, i.e. no radial basis;
- - 'radialBasisWeightsPivot': radial basis weights for pivot
- numerator; defaults to 0, i.e. identity;
- - 'radialBasisWeightsMarginal': radial basis weights for marginal
- interpolant; defaults to 0, i.e. identity;
- - 'interpRcondPivot': tolerance for pivot interpolation; defaults
- to None;
- - 'interpRcondMarginal': tolerance for marginal interpolation;
- defaults to None;
- - 'robustTol': tolerance for robust rational denominator
- management; defaults to 0.
- Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. 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.
- musPivot: Array of pivot snapshot parameters.
- musMarginal: Array of marginal snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
- 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;
- - 'matchingWeight': weight for pole matching optimization;
- - 'cutOffTolerance': tolerance for ignoring parasitic poles;
- - 'cutOffType': rule for tolerance computation for parasitic poles;
- - 'polybasisPivot': type of polynomial basis for pivot
- interpolation;
- - 'polybasisMarginal': type of polynomial basis for marginal
- interpolation;
- - 'E': number of derivatives used to compute interpolant;
- - 'M': degree of rational interpolant numerator;
- - 'N': degree of rational interpolant denominator;
- - 'MMarginal': degree of marginal interpolant;
- - 'radialBasisPivot': radial basis family for pivot numerator;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant;
- - 'radialBasisWeightsPivot': radial basis weights for pivot
- numerator;
- - 'radialBasisWeightsMarginal': radial basis weights for marginal
- interpolant;
- - 'interpRcondPivot': tolerance for pivot interpolation;
- - 'interpRcondMarginal': tolerance for marginal interpolation;
- - 'robustTol': tolerance for robust rational denominator
- management.
- 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.
- POD: Whether to compute POD of snapshots.
- matchingWeight: Weight for pole matching optimization.
- cutOffTolerance: Tolerance for ignoring parasitic poles.
- cutOffType: Rule for tolerance computation for parasitic poles.
- S: Total number of pivot samples current approximant relies upon.
- sampler: Pivot sample point generator.
- polybasisPivot: Type of polynomial basis for pivot interpolation.
- polybasisMarginal: Type of polynomial basis for marginal interpolation.
- M: Numerator degree of approximant.
- N: Denominator degree of approximant.
- MMarginal: Degree of marginal interpolant.
- radialBasisPivot: Radial basis family for pivot numerator.
- radialBasisMarginal: Radial basis family for marginal interpolant.
- radialBasisWeightsPivot: Radial basis weights for pivot numerator.
- radialBasisWeightsMarginal: Radial basis weights for marginal
- interpolant.
- interpRcondPivot: Tolerance for pivot interpolation.
- interpRcondMarginal: Tolerance for marginal interpolation.
- robustTol: Tolerance for robust rational denominator management.
- E: Complete derivative depth level of S.
- muBoundsPivot: 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.
- 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 setupApprox(self):
- """
- Compute rational interpolant.
- SVD-based robust eigenvalue management.
- """
- if self.checkComputedApprox():
- return
- RROMPyAssert(self._mode, message = "Cannot setup approximant.")
- vbMng(self, "INIT", "Setting up {}.". format(self.name()), 5)
- self.computeScaleFactor()
- self.computeSnapshots()
- if self.trainedModel is None:
- self.trainedModel = tModel()
- self.trainedModel.verbosity = self.verbosity
- self.trainedModel.timestamp = self.timestamp
- data = TrainedModelPivotedData(self.trainedModel.name(), self.mu0,
- self.samplingEngine.samplesCoalesced,
- self.scaleFactor,
- self.HFEngine.rescalingExp,
- self.directionPivot)
- data.musPivot = copy(self.musPivot)
- data.musMarginal = copy(self.musMarginal)
- self.trainedModel.data = data
- else:
- self.trainedModel = self.trainedModel
- self.trainedModel.data.projMat = copy(
- self.samplingEngine.samplesCoalesced)
- self.trainedModel.data.marginalInterp = self._setupMarginalInterp()
- if self.N > 0:
- Qs = self._setupDenominator()[0]
- else:
- Q = PI()
- Q.npar = self.musPivot.shape[1]
- Q.coeffs = np.ones(tuple([1] * Q.npar), dtype = np.complex)
- Q.polybasis = self.polybasisPivot
- Qs = [Q for _ in range(len(self.musMarginal))]
- self.trainedModel.data._temporary = True
- self.trainedModel.data.Qs = Qs
- self.trainedModel.data.Ps = self._setupNumerator()
- vbMng(self, "INIT", "Matching poles.", 10)
- self.trainedModel.initializeFromRational(self.HFEngine,
- self.matchingWeight, self.POD)
- vbMng(self, "DEL", "Done matching poles.", 10)
- if not np.isinf(self.cutOffTolerance):
- vbMng(self, "INIT", "Recompressing by cut-off.", 10)
- msg = self.trainedModel.recompressByCutOff([-1., 1.],
- self.cutOffTolerance,
- self.cutOffType)
- vbMng(self, "DEL", "Done recompressing." + msg, 10)
- self.trainedModel.data.approxParameters = copy(self.approxParameters)
- vbMng(self, "DEL", "Done setting up approximant.", 5)
-
diff --git a/rrompy/reduction_methods/pole_matching/reduced_basis_pole_matching.py b/rrompy/reduction_methods/pole_matching/reduced_basis_pole_matching.py
deleted file mode 100644
index 4cf1d65..0000000
--- a/rrompy/reduction_methods/pole_matching/reduced_basis_pole_matching.py
+++ /dev/null
@@ -1,190 +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 numpy import isinf
-from copy import deepcopy as copy
-from rrompy.reduction_methods.pivoted.reduced_basis_pivoted import \
- ReducedBasisPivoted
-from .generic_pole_matching_approximant import GenericPoleMatchingApproximant
-from rrompy.reduction_methods.trained_model import (TrainedModelPivotedData,
- TrainedModelPoleMatchingReducedBasis as tModel)
-from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.exception_manager import RROMPyAssert
-
-__all__ = ['ReducedBasisPoleMatching']
-
-class ReducedBasisPoleMatching(GenericPoleMatchingApproximant,
- ReducedBasisPivoted):
- """
- ROM pivoted RB approximant computation for parametric problems with pole
- matching.
-
- 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;
- - 'matchingWeight': weight for pole matching optimization; defaults
- to 1;
- - 'cutOffTolerance': tolerance for ignoring parasitic poles;
- defaults to np.inf;
- - 'cutOffType': rule for tolerance computation for parasitic poles;
- defaults to 'MAGNITUDE';
- - '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;
- - 'R': rank for pivot Galerkin projection; defaults to prod(S);
- - 'PODTolerance': tolerance for pivot snapshots POD; defaults to
- -1;
- - '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 0;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant; defaults to 0, i.e. no radial basis;
- - 'radialBasisWeightsMarginal': radial basis weights for marginal
- interpolant; defaults to 0, i.e. identity;
- - 'interpRcondMarginal': tolerance for marginal interpolation;
- defaults to None.
- Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. 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.
- musPivot: Array of pivot snapshot parameters.
- musMarginal: Array of marginal snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
- 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;
- - 'matchingWeight': weight for pole matching optimization;
- - 'cutOffTolerance': tolerance for ignoring parasitic poles;
- - 'cutOffType': rule for tolerance computation for parasitic poles;
- - 'R': rank for Galerkin projection;
- - 'PODTolerance': tolerance for snapshots POD;
- - 'polybasisMarginal': type of polynomial basis for marginal
- interpolation;
- - 'MMarginal': degree of marginal interpolant;
- - 'radialBasisMarginal': radial basis family for marginal
- interpolant;
- - 'radialBasisWeightsMarginal': 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.
- POD: Whether to compute POD of snapshots.
- matchingWeight: Weight for pole matching optimization.
- cutOffTolerance: Tolerance for ignoring parasitic poles.
- cutOffType: Rule for tolerance computation for 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.
- R: Rank for Galerkin projection.
- PODTolerance: Tolerance for pivot snapshots POD.
- polybasisMarginal: Type of polynomial basis for marginal interpolation.
- MMarginal: Degree of marginal interpolant.
- radialBasisMarginal: Radial basis family for marginal interpolant.
- radialBasisWeightsMarginal: Radial basis weights for marginal
- interpolant.
- interpRcondMarginal: Tolerance for marginal interpolation.
- muBoundsPivot: 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.
- 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.
- As: List of sparse matrices (in CSC format) representing coefficients
- of linear system matrix.
- bs: List of numpy vectors representing coefficients of linear system
- RHS.
- ARBs: List of sparse matrices (in CSC format) representing coefficients
- of compressed linear system matrix.
- bRBs: List of numpy vectors representing coefficients of compressed
- linear system RHS.
- """
-
- def setupApprox(self):
- """Compute RB projection matrix."""
- if self.checkComputedApprox():
- return
- RROMPyAssert(self._mode, message = "Cannot setup approximant.")
- vbMng(self, "INIT", "Setting up {}.".format(self.name()), 5)
- self.computeScaleFactor()
- self.computeSnapshots()
- self._setupAffineBlocks()
- pMat = self._setupProjectionMatrix()
- ARBsList, bRBsList, pList = self.assembleReducedSystemMarginal(pMat)
- if self.trainedModel is None:
- self.trainedModel = tModel()
- self.trainedModel.verbosity = self.verbosity
- self.trainedModel.timestamp = self.timestamp
- data = TrainedModelPivotedData(self.trainedModel.name(), self.mu0,
- pList, self.scaleFactor,
- self.HFEngine.rescalingExp,
- self.directionPivot)
- data.musPivot = copy(self.musPivot)
- data.musMarginal = copy(self.musMarginal)
- self.trainedModel.data = data
- else:
- self.trainedModel = self.trainedModel
- self.trainedModel.data.projMat = copy(pList)
- self.trainedModel.data.marginalInterp = self._setupMarginalInterp()
- self.trainedModel.data.ARBsList = ARBsList
- self.trainedModel.data.bRBsList = bRBsList
- vbMng(self, "INIT", "Matching poles.", 10)
- self.trainedModel.initializeFromAffine(self.HFEngine,
- self.matchingWeight, self.POD)
- vbMng(self, "DEL", "Done matching poles.", 10)
- if not isinf(self.cutOffTolerance):
- vbMng(self, "INIT", "Recompressing by cut-off.", 10)
- msg = self.trainedModel.recompressByCutOff([- 1., 1.],
- self.cutOffTolerance,
- self.cutOffType)
- vbMng(self, "DEL", "Done recompressing." + msg, 10)
- self.trainedModel.data.approxParameters = copy(self.approxParameters)
- vbMng(self, "DEL", "Done setting up approximant.", 5)
diff --git a/rrompy/reduction_methods/standard/__init__.py b/rrompy/reduction_methods/standard/__init__.py
index 0ddf98c..a9a5e6a 100644
--- a/rrompy/reduction_methods/standard/__init__.py
+++ b/rrompy/reduction_methods/standard/__init__.py
@@ -1,29 +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 .generic_standard_approximant import GenericStandardApproximant
from .rational_interpolant import RationalInterpolant
+from .rational_moving_least_squares import RationalMovingLeastSquares
from .reduced_basis import ReducedBasis
__all__ = [
'GenericStandardApproximant',
'RationalInterpolant',
+ 'RationalMovingLeastSquares',
'ReducedBasis'
]
diff --git a/rrompy/reduction_methods/standard/generic_standard_approximant.py b/rrompy/reduction_methods/standard/generic_standard_approximant.py
index 7ce4a2e..cd2bb5d 100644
--- a/rrompy/reduction_methods/standard/generic_standard_approximant.py
+++ b/rrompy/reduction_methods/standard/generic_standard_approximant.py
@@ -1,163 +1,156 @@
# 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.utilities.base.types import DictAny, HFEng, paramVal, paramList
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
from rrompy.parameter import checkParameterList
__all__ = ['GenericStandardApproximant']
class GenericStandardApproximant(GenericApproximant):
"""
ROM interpolant computation for parametric problems (ABSTRACT).
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;
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator.
Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. Defaults
- to False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
mus: Array of snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
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.
parameterListCritical: Recognized keys of critical approximant
parameters:
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator.
POD: Whether to compute POD of snapshots.
S: Number of solution snapshots over which current approximant is
based upon.
sampler: Sample point generator.
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.
"""
def __init__(self, HFEngine:HFEng, mu0 : paramVal = None,
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
+ approxParameters : DictAny = {}, verbosity : int = 10,
+ timestamp : bool = True):
self._preInit()
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
self._addParametersToList([], [], ["sampler"],
[QS([[0], [1]], "UNIFORM")])
del QS
super().__init__(HFEngine = HFEngine, mu0 = mu0,
approxParameters = approxParameters,
- homogeneized = homogeneized,
verbosity = verbosity, timestamp = timestamp)
self._postInit()
@property
def mus(self):
"""Value of mus. Its assignment may reset snapshots."""
return self._mus
@mus.setter
def mus(self, mus):
mus = checkParameterList(mus, self.npar)[0]
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 muBounds(self):
"""Value of muBounds."""
return self.sampler.lims
@property
def sampler(self):
"""Value of sampler."""
return self._sampler
@sampler.setter
def sampler(self, sampler):
if 'generatePoints' not in dir(sampler):
raise RROMPyException("Sampler type not recognized.")
if hasattr(self, '_sampler') and self._sampler is not None:
samplerOld = self.sampler
self._sampler = sampler
self._approxParameters["sampler"] = self.sampler.__str__()
if not 'samplerOld' in locals() or samplerOld != self.sampler:
self.resetSamples()
def setSamples(self, samplingEngine):
"""Copy samplingEngine and samples."""
super().setSamples(samplingEngine)
self.mus = copy(self.samplingEngine.mus)
def computeSnapshots(self):
"""Compute snapshots of solution map."""
RROMPyAssert(self._mode,
message = "Cannot start snapshot computation.")
- if self.samplingEngine.nsamples != np.prod(self.S):
+ if self.samplingEngine.nsamples != self.S:
+ self.computeScaleFactor()
vbMng(self, "INIT", "Starting computation of snapshots.", 5)
self.mus = self.sampler.generatePoints(self.S)
- self.samplingEngine.iterSample(self.mus,
- homogeneized = self.homogeneized)
+ self.samplingEngine.iterSample(self.mus)
vbMng(self, "DEL", "Done computing snapshots.", 5)
- def normApprox(self, mu:paramList, homogeneized : bool = False) -> float:
+ def normApprox(self, mu:paramList) -> float:
"""
Compute norm of approximant at arbitrary parameter.
Args:
mu: Target parameter.
- homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
- False.
Returns:
Target norm of approximant.
"""
- if not self.POD or self.homogeneized != homogeneized:
- return super().normApprox(mu, homogeneized)
+ if not self.POD: return super().normApprox(mu)
return np.linalg.norm(self.getApproxReduced(mu).data, axis = 0)
def computeScaleFactor(self):
"""Compute parameter rescaling factor."""
RROMPyAssert(self._mode, message = "Cannot compute rescaling factor.")
self.scaleFactor = .5 * np.abs(
self.muBounds[0] ** self.HFEngine.rescalingExp
- self.muBounds[1] ** self.HFEngine.rescalingExp)
diff --git a/rrompy/reduction_methods/standard/rational_interpolant.py b/rrompy/reduction_methods/standard/rational_interpolant.py
index 434f291..0f50c33 100644
--- a/rrompy/reduction_methods/standard/rational_interpolant.py
+++ b/rrompy/reduction_methods/standard/rational_interpolant.py
@@ -1,559 +1,561 @@
# 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, polyfitname,
- nextDerivativeIndices,
- hashDerivativeToIdx as hashD,
- hashIdxToDerivative as hashI,
- homogeneizedpolyvander as hpvP,
- homogeneizedToFull,
- PolynomialInterpolator as PI)
-from rrompy.utilities.poly_fitting.radial_basis import (rbbases,
+from rrompy.utilities.poly_fitting.polynomial import (
+ polybases as ppb, polyfitname,
+ polyvander as pvP, polyvanderTotal as pvTP,
+ 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 (
+ polybases as mlspb,
+ MovingLeastSquaresInterpolator as MLSI)
from rrompy.reduction_methods.trained_model import (
TrainedModelRational as tModel)
from rrompy.reduction_methods.trained_model import TrainedModelData
from rrompy.utilities.base.types import (Np1D, Np2D, HFEng, DictAny, Tuple,
- List, paramVal, paramList, sampList)
+ List, paramVal, sampList)
from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.numerical import multifactorial, customPInv
+from rrompy.utilities.numerical import (multifactorial, customPInv, dot,
+ fullDegreeN, totalDegreeN,
+ degreeTotalToFull, fullDegreeMaxMask,
+ totalDegreeMaxMask,
+ nextDerivativeIndices,
+ hashDerivativeToIdx as hashD,
+ hashIdxToDerivative as hashI)
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;
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator;
- - 'polybasis': type of polynomial basis for interpolation; allowed
- values include 'MONOMIAL', 'CHEBYSHEV' and 'LEGENDRE'; defaults
+ - 'polybasis': type of polynomial basis for interpolation; defaults
to 'MONOMIAL';
- - 'E': number of derivatives used to compute interpolant; defaults
- to 0;
- 'M': degree of rational interpolant numerator; defaults to 0;
- 'N': degree of rational interpolant denominator; defaults to 0;
- - 'radialBasis': radial basis family for interpolant numerator;
- defaults to 0, i.e. no radial basis;
- - 'radialBasisWeights': radial basis weights for interpolant
+ - 'polydegreetype': type of polynomial degree; defaults to 'TOTAL';
+ - 'radialDirectionalWeights': radial basis weights for interpolant
numerator; defaults to 0, i.e. identity;
+ - 'nNearestNeighbor': mumber of nearest neighbors considered in
+ numerator if polybasis allows; defaults to -1;
- 'interpRcond': tolerance for interpolation; defaults to None;
- 'robustTol': tolerance for robust rational denominator
management; defaults to 0.
Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. Defaults
- to False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
mus: Array of snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
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;
- 'polybasis': type of polynomial basis for interpolation;
- - 'E': number of derivatives used to compute interpolant;
- 'M': degree of rational interpolant numerator;
- 'N': degree of rational interpolant denominator;
- - 'radialBasis': radial basis family for interpolant numerator;
- - 'radialBasisWeights': radial basis weights for interpolant
+ - 'polydegreetype': type of polynomial degree;
+ - 'radialDirectionalWeights': radial basis weights for interpolant
numerator;
+ - 'nNearestNeighbor': mumber of nearest neighbors considered in
+ numerator if polybasis allows;
- '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.
POD: Whether to compute POD of snapshots.
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.
- radialBasis: Radial basis family for interpolant numerator.
- radialBasisWeights: Radial basis weights for interpolant numerator.
+ polydegreetype: Type of polynomial degree.
+ radialDirectionalWeights: Radial basis weights for interpolant
+ numerator.
+ nNearestNeighbor: Number of nearest neighbors considered in numerator
+ if polybasis allows.
interpRcond: Tolerance for interpolation via numpy.polyfit.
robustTol: Tolerance for robust rational denominator management.
- E: Complete derivative depth level of S.
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, HFEngine:HFEng, mu0 : paramVal = None,
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
+ approxParameters : DictAny = {}, verbosity : int = 10,
+ timestamp : bool = True):
self._preInit()
- self._addParametersToList(["polybasis", "E", "M", "N", "radialBasis",
- "radialBasisWeights", "interpRcond",
+ self._addParametersToList(["polybasis", "M", "N", "polydegreetype",
+ "radialDirectionalWeights",
+ "nNearestNeighbor", "interpRcond",
"robustTol"],
- ["MONOMIAL", -1, 0, 0, 0, 1, -1, 0])
+ ["MONOMIAL", 0, 0, "TOTAL", 1, -1, -1, 0])
super().__init__(HFEngine = HFEngine, mu0 = mu0,
approxParameters = approxParameters,
- homogeneized = homogeneized,
verbosity = verbosity, timestamp = timestamp)
self.catchInstability = False
self._postInit()
@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 polybases:
+ if polybasis not in ppb + rbpb + mlspb:
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):
- try:
- if radialBasis != 0:
- radialBasis = radialBasis.upper().strip().replace(" ","")
- if radialBasis not in rbbases:
- raise RROMPyException(("Prescribed radialBasis not "
- "recognized."))
- self._radialBasis = radialBasis
- except:
- RROMPyWarning(("Prescribed radialBasis not recognized. Overriding "
- "to 0."))
- self._radialBasis = 0
- self._approxParameters["radialBasis"] = self.radialBasis
-
- @property
- def polybasisP(self):
- if self.radialBasis == 0:
- return self._polybasis
- return self._polybasis + "_" + self.radialBasis
+ 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 radialBasisWeights(self):
- """Value of radialBasisWeights."""
- return self._radialBasisWeights
- @radialBasisWeights.setter
- def radialBasisWeights(self, radialBasisWeights):
- self._radialBasisWeights = radialBasisWeights
- self._approxParameters["radialBasisWeights"] = self.radialBasisWeights
+ def radialDirectionalWeights(self):
+ """Value of radialDirectionalWeights."""
+ return self._radialDirectionalWeights
+ @radialDirectionalWeights.setter
+ def radialDirectionalWeights(self, radialDirectionalWeights):
+ self._radialDirectionalWeights = radialDirectionalWeights
+ self._approxParameters["radialDirectionalWeights"] = (
+ self.radialDirectionalWeights)
+
+ @property
+ def nNearestNeighbor(self):
+ """Value of nNearestNeighbor."""
+ return self._nNearestNeighbor
+ @nNearestNeighbor.setter
+ def nNearestNeighbor(self, nNearestNeighbor):
+ self._nNearestNeighbor = nNearestNeighbor
+ self._approxParameters["nNearestNeighbor"] = self.nNearestNeighbor
@property
def M(self):
- """Value of M. Its assignment may change S."""
+ """Value of M."""
return self._M
@M.setter
def M(self, M):
if M < 0: raise RROMPyException("M must be non-negative.")
self._M = M
self._approxParameters["M"] = self.M
- if hasattr(self, "_E") and self.E >= 0 and self.E < self.M:
- RROMPyWarning("Prescribed S is too small. Decreasing M.")
- self.M = self.E
@property
def N(self):
- """Value of N. Its assignment may change S."""
+ """Value of N."""
return self._N
@N.setter
def N(self, N):
if N < 0: raise RROMPyException("N must be non-negative.")
self._N = N
self._approxParameters["N"] = self.N
- if hasattr(self, "_E") and self.E >= 0 and self.E < self.N:
- RROMPyWarning("Prescribed S is too small. Decreasing N.")
- self.N = self.E
@property
- def E(self):
- """Value of E."""
- return self._E
- @E.setter
- def E(self, E):
- if E < 0:
- if not hasattr(self, "_S"):
- raise RROMPyException(("Value of E must be positive if S is "
- "not yet assigned."))
- E = np.sum(hashI(np.prod(self.S), self.npar)) - 1
- self._E = E
- self._approxParameters["E"] = self.E
- if (hasattr(self, "_S")
- and self.E >= np.sum(hashI(np.prod(self.S), self.npar))):
- RROMPyWarning("Prescribed S is too small. Decreasing E.")
- self.E = -1
- if hasattr(self, "_M"): self.M = self.M
- if hasattr(self, "_N"): self.N = self.N
+ 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 S(self):
- """Value of S."""
- return self._S
- @S.setter
- def S(self, S):
- GenericStandardApproximant.S.fset(self, S)
- if hasattr(self, "_M"): self.M = self.M
- if hasattr(self, "_N"): self.N = self.N
- if hasattr(self, "_E"): self.E = self.E
-
def resetSamples(self):
"""Reset samples."""
super().resetSamples()
self._musUniqueCN = None
self._derIdxs = None
self._reorder = None
def _setupInterpolationIndices(self):
"""Setup parameters for polyvander."""
RROMPyAssert(self._mode,
message = "Cannot setup interpolation indices.")
if self._musUniqueCN is None or len(self._reorder) != len(self.mus):
self._musUniqueCN, musIdxsTo, musIdxs, musCount = (
- self.centerNormalize(self.mus).unique(return_index = True,
- return_inverse = True,
- return_counts = True))
+ 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)
while self.N > 0:
invD, fitinv = self._computeInterpolantInverseBlocks()
if self.POD:
ev, eV = self.findeveVGQR(self.samplingEngine.RPOD, invD)
else:
ev, eV = self.findeveVGExplicit(self.samplingEngine.samples,
invD)
nevBad = checkRobustTolerance(ev, self.robustTol)
if nevBad <= 1: break
if self.catchInstability:
raise RROMPyException(("Instability in denominator "
"computation: eigenproblem is poorly "
"conditioned."))
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.polybasis
- q.coeffs = homogeneizedToFull(tuple([self.N + 1] * self.npar),
- self.npar, eV[:, 0])
+ 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)
Qevaldiag = np.zeros((len(self.mus), len(self.mus)),
dtype = np.complex)
verb = self.trainedModel.verbosity
self.trainedModel.verbosity = 0
-
self._setupInterpolationIndices()
idxGlob = 0
for j, derIdxs in enumerate(self._derIdxs):
nder = len(derIdxs)
idxLoc = np.arange(len(self.mus))[(self._reorder >= idxGlob)
* (self._reorder < idxGlob + nder)]
idxGlob += nder
Qval = [0] * nder
for der in range(nder):
derIdx = hashI(der, self.npar)
Qval[der] = (self.trainedModel.getQVal(
self._musUnique[j], derIdx,
scl = np.power(self.scaleFactor, -1.))
/ multifactorial(derIdx))
for derU, derUIdx in enumerate(derIdxs):
for derQ, derQIdx in enumerate(derIdxs):
diffIdx = [x - y for (x, y) in zip(derUIdx, derQIdx)]
if all([x >= 0 for x in diffIdx]):
diffj = hashD(diffIdx)
Qevaldiag[idxLoc[derU], idxLoc[derQ]] = Qval[diffj]
if self.POD:
Qevaldiag = Qevaldiag.dot(self.samplingEngine.RPOD.T)
self.trainedModel.verbosity = verb
+ cfun = totalDegreeN if self.polydegreetype == "TOTAL" else fullDegreeN
+ M = copy(self.M)
+ while len(self.mus) < cfun(M, self.npar): M -= 1
+ 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:
- if self.radialBasis == 0:
+ if self.polybasis in ppb:
p = PI()
wellCond, msg = p.setupByInterpolation(
- self._musUniqueCN, Qevaldiag, self.M,
- self.polybasisP, self.verbosity >= 5, True,
- {"derIdxs": self._derIdxs, "reorder": self._reorder,
- "scl": np.power(self.scaleFactor, -1.)},
- {"rcond": self.interpRcond})
- else:
+ self._musUniqueCN, Qevaldiag, self.M,
+ self.polybasis, self.verbosity >= 5,
+ self.polydegreetype == "TOTAL",
+ {"derIdxs": self._derIdxs,
+ "reorder": self._reorder,
+ "scl": np.power(self.scaleFactor, -1.)},
+ {"rcond": self.interpRcond})
+ elif self.polybasis in rbpb:
p = RBI()
wellCond, msg = p.setupByInterpolation(
- self._musUniqueCN, Qevaldiag, self.M, self.polybasisP,
- self.radialBasisWeights, self.verbosity >= 5, True,
- {"derIdxs": self._derIdxs, "reorder": self._reorder,
- "scl": np.power(self.scaleFactor, -1.)},
- {"rcond": self.interpRcond})
+ self._musUniqueCN, Qevaldiag, self.M, self.polybasis,
+ self.radialDirectionalWeights, self.verbosity >= 5,
+ self.polydegreetype == "TOTAL",
+ {"derIdxs": self._derIdxs, "reorder": self._reorder,
+ "scl": np.power(self.scaleFactor, -1.),
+ "nNearestNeighbor": self.nNearestNeighbor},
+ {"rcond": self.interpRcond})
+ else:# if self.polybasis in mlspb:
+ p = MLSI()
+ wellCond, msg = p.setupByInterpolation(
+ self._musUniqueCN, Qevaldiag, self.M, self.polybasis,
+ self.radialDirectionalWeights, self.verbosity >= 5,
+ self.polydegreetype == "TOTAL",
+ {"derIdxs": self._derIdxs, "reorder": self._reorder,
+ "scl": np.power(self.scaleFactor, -1.),
+ "nNearestNeighbor": self.nNearestNeighbor})
vbMng(self, "MAIN", msg, 5)
if wellCond: break
if self.catchInstability:
raise RROMPyException(("Instability in numerator computation: "
"polyfit is poorly conditioned."))
RROMPyWarning("Polyfit is poorly conditioned. Reducing M by 1.")
- self.M -= 1
+ self.M = self.M - 1
if self.M < 0:
raise RROMPyException(("Instability in computation of numerator. "
"Aborting."))
vbMng(self, "DEL", "Done computing numerator.", 7)
return p
def setupApprox(self):
"""
Compute rational interpolant.
SVD-based robust eigenvalue management.
"""
if self.checkComputedApprox():
return
RROMPyAssert(self._mode, message = "Cannot setup approximant.")
vbMng(self, "INIT", "Setting up {}.". format(self.name()), 5)
- self.computeScaleFactor()
self.computeSnapshots()
if self.trainedModel is None:
self.trainedModel = tModel()
self.trainedModel.verbosity = self.verbosity
self.trainedModel.timestamp = self.timestamp
data = TrainedModelData(self.trainedModel.name(), self.mu0,
self.samplingEngine.samples,
self.scaleFactor,
self.HFEngine.rescalingExp)
data.mus = copy(self.mus)
self.trainedModel.data = data
else:
self.trainedModel = self.trainedModel
self.trainedModel.data.projMat = copy(self.samplingEngine.samples)
if self.N > 0:
Q = self._setupDenominator()[0]
else:
Q = PI()
Q.coeffs = np.ones(tuple([1] * self.npar), dtype = np.complex)
Q.npar = self.npar
Q.polybasis = self.polybasis
self.trainedModel.data.Q = Q
self.trainedModel.data.P = self._setupNumerator()
self.trainedModel.data.approxParameters = copy(self.approxParameters)
vbMng(self, "DEL", "Done setting up approximant.", 5)
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()
- while self.E >= 0:
- eWidth = (hashD([self.E + 1] + [0] * (self.npar - 1))
- - hashD([self.E] + [0] * (self.npar - 1)))
- TE, _, argIdxs = hpvP(self._musUniqueCN, self.E, self.polybasis,
- self._derIdxs, self._reorder,
- scl = np.power(self.scaleFactor, -1.))
- fitOut = customPInv(TE[:, argIdxs], rcond = self.interpRcond,
- full = True)
+ cfun = totalDegreeN if self.polydegreetype == "TOTAL" else fullDegreeN
+ N = copy(self.N)
+ while len(self.mus) < cfun(N, self.npar): N -= 1
+ 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:
+ if self.polydegreetype == "TOTAL":
+ TE, _, argIdxs = pvTP(self._musUniqueCN, self.N,
+ self.polybasis0, self._derIdxs,
+ self._reorder,
+ scl = np.power(self.scaleFactor, -1.))
+ TE = TE[:, argIdxs]
+ idxsB = totalDegreeMaxMask(self.N, self.npar)
+ else: #if self.polydegreetype == "FULL":
+ TE = pvP(self._musUniqueCN, [self.N] * self.npar,
+ self.polybasis0, self._derIdxs, self._reorder,
+ scl = np.power(self.scaleFactor, -1.))
+ idxsB = fullDegreeMaxMask(self.N, self.npar)
+ 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], self.E,
- polyfitname(self.polybasis),
+ TE.shape[0], self.N,
+ polyfitname(self.polybasis0),
fitOut[1][1][0] / fitOut[1][1][-1]),
5)
- if fitOut[1][0] == len(argIdxs):
- fitinv = fitOut[0][- eWidth : , :]
+ if fitOut[1][0] == TE.shape[1]:
+ fitinv = fitOut[0][idxsB, :]
break
- RROMPyWarning("Polyfit is poorly conditioned. Reducing E by 1.")
- self.E -= 1
- if self.E < 0:
- raise RROMPyException(("Instability in computation of "
- "denominator. Aborting."))
- TN, _, argIdxs = hpvP(self._musUniqueCN, self.N, self.polybasis,
- self._derIdxs, self._reorder,
- scl = np.power(self.scaleFactor, -1.))
- TN = TN[:, argIdxs]
- invD = [None] * (eWidth)
- for k in range(eWidth):
+ if self.catchInstability:
+ raise RROMPyException(("Instability in denominator "
+ "computation: polyfit is poorly "
+ "conditioned."))
+ RROMPyWarning("Polyfit is poorly conditioned. Reducing N by 1.")
+ self.N = self.N - 1
+ if self.polydegreetype == "TOTAL":
+ TN, _, argIdxs = pvTP(self._musUniqueCN, self.N, self.polybasis0,
+ self._derIdxs, self._reorder,
+ scl = np.power(self.scaleFactor, -1.))
+ TN = TN[:, argIdxs]
+ else: #if self.polydegreetype == "FULL":
+ TN = pvP(self._musUniqueCN, [self.N] * self.npar,
+ self.polybasis0, self._derIdxs, self._reorder,
+ scl = np.power(self.scaleFactor, -1.))
+ invD = [None] * (len(idxsB))
+ for k in range(len(idxsB)):
pseudoInv = np.diag(fitinv[k, :])
idxGlob = 0
for j, derIdxs in enumerate(self._derIdxs):
nder = len(derIdxs)
idxGlob += nder
if nder > 1:
idxLoc = np.arange(len(self.mus))[
(self._reorder >= idxGlob - nder)
* (self._reorder < idxGlob)]
invLoc = fitinv[k, idxLoc]
pseudoInv[np.ix_(idxLoc, idxLoc)] = 0.
for diffj, diffjIdx in enumerate(derIdxs):
for derQ, derQIdx in enumerate(derIdxs):
derUIdx = [x - y for (x, y) in
- zip(diffjIdx, derQIdx)]
+ zip(diffjIdx, derQIdx)]
if all([x >= 0 for x in derUIdx]):
derU = hashD(derUIdx)
pseudoInv[idxLoc[derU], idxLoc[derQ]] = (
- invLoc[diffj])
- invD[k] = pseudoInv.dot(TN)
+ invLoc[diffj])
+ invD[k] = dot(pseudoInv, 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)
G = np.zeros((nEnd, nEnd), dtype = np.complex)
for k in range(eWidth):
- G += invD[k].T.conj().dot(gramian.dot(invD[k]))
+ 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)
ev, eV = np.linalg.eigh(G)
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, :] = RPODE.dot(invD[k])
+ 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)
_, s, eV = np.linalg.svd(Rstack, full_matrices = False)
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 centerNormalize(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.mu0.
-
- Returns:
- Normalized parameter.
- """
- return self.trainedModel.centerNormalize(mu, mu0)
-
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
new file mode 100644
index 0000000..7ce711d
--- /dev/null
+++ b/rrompy/reduction_methods/standard/rational_moving_least_squares.py
@@ -0,0 +1,301 @@
+# 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.reduction_methods.trained_model import (
+ TrainedModelRationalMLS as tModel)
+from rrompy.reduction_methods.trained_model import TrainedModelData
+from rrompy.utilities.base.types import Np2D, HFEng, DictAny, paramVal
+from rrompy.utilities.base import verbosityManager as vbMng
+from rrompy.utilities.numerical import (fullDegreeMaxMask, totalDegreeMaxMask,
+ dot)
+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;
+ - '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 0;
+ - 'N': degree of rational interpolant denominator; defaults to 0;
+ - '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 0, i.e. identity;
+ - 'nNearestNeighbor': number of nearest neighbors considered in
+ numerator if radialBasis allows; defaults to -1;
+ - 'radialBasisDen': denominator radial basis type; defaults to
+ 'GAUSSIAN';
+ - 'radialDirectionalWeightsDen': radial basis weights for
+ interpolant denominator; defaults to 0, i.e. identity;
+ - 'nNearestNeighborDen': number of nearest neighbors considered in
+ denominator if radialBasisDen allows; defaults to -1;
+ - 'interpRcond': tolerance for interpolation; defaults to None;
+ - 'robustTol': tolerance for robust rational denominator
+ management; defaults to 0.
+ Defaults to empty dict.
+ 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;
+ - '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;
+ - 'nNearestNeighbor': number of nearest neighbors considered in
+ numerator if radialBasis allows;
+ - 'radialBasisDen': denominator radial basis type;
+ - 'radialDirectionalWeightsDen': radial basis weights for
+ interpolant denominator;
+ - 'nNearestNeighborDen': number of nearest neighbors considered in
+ denominator if radialBasisDen allows;
+ - '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.
+ POD: Whether to compute POD of snapshots.
+ 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.
+ nNearestNeighbor: Number of nearest neighbors considered in numerator
+ if radialBasis allows.
+ radialBasisDen: Denominator radial basis type.
+ radialDirectionalWeightsDen: Radial basis weights for interpolant
+ denominator.
+ nNearestNeighborDen: Number of nearest neighbors considered in
+ denominator if radialBasisDen allows.
+ 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, HFEngine:HFEng, mu0 : paramVal = None,
+ approxParameters : DictAny = {}, verbosity : int = 10,
+ timestamp : bool = True):
+ self._preInit()
+ self._addParametersToList(["radialBasis", "radialBasisDen",
+ "radialDirectionalWeightsDen",
+ "nNearestNeighborDen"],
+ ["GAUSSIAN", "GAUSSIAN", 1, -1])
+ super().__init__(HFEngine = HFEngine, mu0 = mu0,
+ approxParameters = approxParameters,
+ verbosity = verbosity, timestamp = timestamp)
+ self.catchInstability = False
+ self._postInit()
+
+ @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)
+
+ @property
+ def nNearestNeighborDen(self):
+ """Value of nNearestNeighborDen."""
+ return self._nNearestNeighborDen
+ @nNearestNeighborDen.setter
+ def nNearestNeighborDen(self, nNearestNeighborDen):
+ self._nNearestNeighborDen = nNearestNeighborDen
+ self._approxParameters["nNearestNeighborDen"] = (
+ self.nNearestNeighborDen)
+
+ 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()
+ if self.polydegreetype == "TOTAL":
+ TN, _, argIdxs = pvTP(self._musUniqueCN, self.N, self.polybasis0,
+ self._derIdxs, self._reorder,
+ scl = np.power(self.scaleFactor, -1.))
+ TN = TN[:, argIdxs]
+ else: #if self.polydegreetype == "FULL":
+ TN = pvP(self._musUniqueCN, [self.N] * self.npar,
+ self.polybasis0, self._derIdxs, self._reorder,
+ scl = np.power(self.scaleFactor, -1.))
+ 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()
+ if self.polydegreetype == "TOTAL":
+ TM, _, argIdxs = pvTP(self._musUniqueCN, self.M, self.polybasis0,
+ self._derIdxs, self._reorder,
+ scl = np.power(self.scaleFactor, -1.))
+ TM = TM[:, argIdxs]
+ else: #if self.polydegreetype == "FULL":
+ TM = pvP(self._musUniqueCN, [self.M] * self.npar,
+ self.polybasis0, self._derIdxs, self._reorder,
+ scl = np.power(self.scaleFactor, -1.))
+ vbMng(self, "DEL", "Done computing denominator-related blocks.", 7)
+ return TM
+
+ def setupApprox(self):
+ """
+ Compute rational interpolant.
+ SVD-based robust eigenvalue management.
+ """
+ if self.checkComputedApprox():
+ return
+ RROMPyAssert(self._mode, message = "Cannot setup approximant.")
+ vbMng(self, "INIT", "Setting up {}.". format(self.name()), 5)
+ self.computeSnapshots()
+ if self.trainedModel is None:
+ self.trainedModel = tModel()
+ self.trainedModel.verbosity = self.verbosity
+ self.trainedModel.timestamp = self.timestamp
+ data = TrainedModelData(self.trainedModel.name(), self.mu0,
+ self.samplingEngine.samples,
+ self.scaleFactor,
+ self.HFEngine.rescalingExp)
+ data.POD = self.POD
+ data.polybasis = self.polybasis
+ data.polydegreetype = self.polydegreetype
+ data.radialBasis = self.radialBasis
+ data.radialWeights = self.radialDirectionalWeights
+ data.nNearestNeighbor = self.nNearestNeighbor
+ data.radialBasisDen = self.radialBasisDen
+ data.radialWeightsDen = self.radialDirectionalWeightsDen
+ data.nNearestNeighborDen = self.nNearestNeighborDen
+ data.interpRcond = self.interpRcond
+ self.trainedModel.data = data
+ else:
+ self.trainedModel = self.trainedModel
+ self.trainedModel.data.projMat = copy(self.samplingEngine.samples)
+ if not self.POD:
+ self.trainedModel.data.gramian = self.HFEngine.innerProduct(
+ self.samplingEngine.samples,
+ self.samplingEngine.samples)
+ 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)
+
diff --git a/rrompy/reduction_methods/standard/reduced_basis.py b/rrompy/reduction_methods/standard/reduced_basis.py
index ac53d48..efcb121 100644
--- a/rrompy/reduction_methods/standard/reduced_basis.py
+++ b/rrompy/reduction_methods/standard/reduced_basis.py
@@ -1,209 +1,202 @@
# 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 .generic_standard_approximant import GenericStandardApproximant
from rrompy.reduction_methods.trained_model import \
TrainedModelReducedBasis as tModel
from rrompy.reduction_methods.trained_model import TrainedModelData
from rrompy.reduction_methods.base.reduced_basis_utils import \
projectAffineDecomposition
-from rrompy.utilities.base.types import (Np1D, Np2D, List, ListAny, Tuple,
- DictAny, HFEng, paramVal, sampList)
+from rrompy.utilities.base.types import (Np1D, Np2D, List, Tuple, DictAny,
+ HFEng, paramVal, sampList)
from rrompy.utilities.base import verbosityManager as vbMng
+from rrompy.utilities.numerical import dot
from rrompy.utilities.exception_manager import (RROMPyWarning, RROMPyException,
RROMPyAssert)
__all__ = ['ReducedBasis']
class ReducedBasis(GenericStandardApproximant):
"""
ROM RB approximant computation for parametric problems.
Args:
HFEngine: HF problem solver.
mu0(optional): Default parameter. Defaults to 0.
approxParameters(optional): Dictionary containing values for main
parameters of approximant. Recognized keys are:
- 'POD': whether to compute POD of snapshots; defaults to True;
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator;
- - 'R': rank for Galerkin projection; defaults to prod(S);
+ - 'R': rank for Galerkin projection; defaults to S;
- 'PODTolerance': tolerance for snapshots POD; defaults to -1.
Defaults to empty dict.
- homogeneized(optional): Whether to homogeneize Dirichlet BCs. Defaults
- to False.
verbosity(optional): Verbosity level. Defaults to 10.
Attributes:
HFEngine: HF problem solver.
mu0: Default parameter.
mus: Array of snapshot parameters.
- homogeneized: Whether to homogeneize Dirichlet BCs.
approxRadius: Dummy radius of approximant (i.e. distance from mu0 to
farthest sample point).
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.
- 'R': rank for Galerkin projection;
- 'PODTolerance': tolerance for snapshots POD.
parameterListCritical: Recognized keys of critical approximant
parameters:
- 'S': total number of samples current approximant relies upon;
- 'sampler': sample point generator;
POD: Whether to compute POD of snapshots.
S: Number of solution snapshots over which current approximant is
based upon.
sampler: Sample point generator.
R: Rank for Galerkin projection.
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.
As: List of sparse matrices (in CSC format) representing coefficients
of linear system matrix.
bs: List of numpy vectors representing coefficients of linear system
RHS.
ARBs: List of sparse matrices (in CSC format) representing coefficients
of compressed linear system matrix.
bRBs: List of numpy vectors representing coefficients of compressed
linear system RHS.
"""
def __init__(self, HFEngine:HFEng, mu0 : paramVal = None,
- approxParameters : DictAny = {}, homogeneized : bool = False,
- verbosity : int = 10, timestamp : bool = True):
+ approxParameters : DictAny = {}, verbosity : int = 10,
+ timestamp : bool = True):
self._preInit()
- self._addParametersToList(["R", "PODTolerance"], [1, -1])
+ self._addParametersToList(["R", "PODTolerance"], ["AUTO", -1])
super().__init__(HFEngine = HFEngine, mu0 = mu0,
approxParameters = approxParameters,
- homogeneized = homogeneized,
verbosity = verbosity, timestamp = timestamp)
- vbMng(self, "INIT", "Computing affine blocks of system.", 10)
- vbMng(self, "DEL", "Done computing affine blocks.", 10)
self._postInit()
- @property
- def S(self):
- """Value of S."""
- return self._S
- @S.setter
- def S(self, S):
- GenericStandardApproximant.S.fset(self, S)
- if not hasattr(self, "_R"): self._R = np.prod(self.S)
-
@property
def R(self):
"""Value of R. Its assignment may change S."""
return self._R
@R.setter
def R(self, R):
+ if R == "AUTO":
+ if not hasattr(self, "_S"):
+ raise RROMPyException(("Cannot assign R automatically without "
+ "S."))
+ R = self.S
if R < 0: raise RROMPyException("R must be non-negative.")
self._R = R
self._approxParameters["R"] = self.R
- if hasattr(self, "_S") and np.prod(self.S) < self.R:
- RROMPyWarning("Prescribed S is too small. Decreasing R.")
- self.R = np.prod(self.S)
@property
def PODTolerance(self):
"""Value of PODTolerance."""
return self._PODTolerance
@PODTolerance.setter
def PODTolerance(self, PODTolerance):
self._PODTolerance = PODTolerance
self._approxParameters["PODTolerance"] = self.PODTolerance
- def setupApprox(self):
- """Compute RB projection matrix."""
- if self.checkComputedApprox():
- return
- RROMPyAssert(self._mode, message = "Cannot setup approximant.")
- vbMng(self, "INIT", "Setting up {}.". format(self.name()), 5)
- self.computeScaleFactor()
- self.computeSnapshots()
- vbMng(self, "INIT", "Computing projection matrix.", 7)
+ def _setupProjectionMatrix(self):
+ """Compute projection matrix."""
+ RROMPyAssert(self._mode, message = "Cannot setup numerator.")
+ vbMng(self, "INIT", "Starting computation of projection matrix.", 7)
+ nsamples = self.samplingEngine.nsamples
+ if self.R > nsamples:
+ RROMPyWarning(("R too large compared to S. Reducing R by "
+ "{}").format(self.R - nsamples))
+ self.R = nsamples
if self.POD:
U, s, _ = np.linalg.svd(self.samplingEngine.RPOD)
s = s ** 2.
else:
Gramian = self.HFEngine.innerProduct(self.samplingEngine.samples,
self.samplingEngine.samples)
U, s, _ = np.linalg.svd(Gramian)
- nsamples = self.samplingEngine.nsamples
snorm = np.cumsum(s[::-1]) / np.sum(s)
nPODTrunc = min(nsamples - np.argmax(snorm > self.PODTolerance),
self.R)
- pMat = self.samplingEngine.samples.dot(U[:, : nPODTrunc])
+ pMat = dot(self.samplingEngine.samples, U[:, : nPODTrunc])
vbMng(self, "MAIN",
("Assembling {}x{} projection matrix from {} "
"samples.").format(*(pMat.shape), nsamples), 5)
+ vbMng(self, "DEL", "Done computing projection matrix.", 7)
+ return pMat
+
+ def setupApprox(self):
+ """Compute RB projection matrix."""
+ if self.checkComputedApprox():
+ return
+ RROMPyAssert(self._mode, message = "Cannot setup approximant.")
+ vbMng(self, "INIT", "Setting up {}.". format(self.name()), 5)
+ self.computeSnapshots()
+ pMat = self._setupProjectionMatrix()
if self.trainedModel is None:
self.trainedModel = tModel()
self.trainedModel.verbosity = self.verbosity
self.trainedModel.timestamp = self.timestamp
data = TrainedModelData(self.trainedModel.name(), self.mu0,
pMat, self.scaleFactor,
self.HFEngine.rescalingExp)
+ data.affinePoly = self.HFEngine.affinePoly
data.mus = copy(self.mus)
+ data.thAs, data.thbs = self.HFEngine.thAs, self.HFEngine.thbs
self.trainedModel.data = data
else:
self.trainedModel = self.trainedModel
self.trainedModel.data.projMat = copy(pMat)
- vbMng(self, "INIT", "Computing affine blocks of system.", 10)
- self.As = self.HFEngine.affineLinearSystemA(self.mu0, self.scaleFactor)
- self.bs = self.HFEngine.affineLinearSystemb(self.mu0, self.scaleFactor,
- self.homogeneized)
- vbMng(self, "DEL", "Done computing affine blocks.", 10)
ARBs, bRBs = self.assembleReducedSystem(pMat)
self.trainedModel.data.ARBs = ARBs
self.trainedModel.data.bRBs = bRBs
-
- vbMng(self, "DEL", "Done computing projection matrix.", 7)
self.trainedModel.data.approxParameters = copy(self.approxParameters)
vbMng(self, "DEL", "Done setting up approximant.", 5)
def assembleReducedSystem(self, pMat : sampList = None,
pMatOld : sampList = None)\
-> Tuple[List[Np2D], List[Np1D]]:
"""Build affine blocks of RB linear system through projections."""
if pMat is None:
self.setupApprox()
ARBs = self.trainedModel.data.ARBs
bRBs = self.trainedModel.data.bRBs
else:
vbMng(self, "INIT", "Projecting affine terms of HF model.", 10)
ARBsOld = None if pMatOld is None else self.trainedModel.data.ARBs
bRBsOld = None if pMatOld is None else self.trainedModel.data.bRBs
- ARBs, bRBs = projectAffineDecomposition(self.As, self.bs, pMat,
+ ARBs, bRBs = projectAffineDecomposition(self.HFEngine.As,
+ self.HFEngine.bs, pMat,
ARBsOld, bRBsOld, pMatOld)
vbMng(self, "DEL", "Done projecting affine terms.", 10)
return ARBs, bRBs
-
diff --git a/rrompy/reduction_methods/trained_model/__init__.py b/rrompy/reduction_methods/trained_model/__init__.py
index a80b481..ca0c25b 100644
--- a/rrompy/reduction_methods/trained_model/__init__.py
+++ b/rrompy/reduction_methods/trained_model/__init__.py
@@ -1,47 +1,35 @@
# 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 .trained_model import TrainedModel
from .trained_model_data import TrainedModelData
from .trained_model_rational import TrainedModelRational
+from .trained_model_rational_mls import TrainedModelRationalMLS
from .trained_model_reduced_basis import TrainedModelReducedBasis
from .trained_model_pivoted_data import TrainedModelPivotedData
from .trained_model_pivoted_rational import TrainedModelPivotedRational
-from .trained_model_pivoted_reduced_basis import \
- TrainedModelPivotedReducedBasis
-from .trained_model_pole_matching_general import \
- TrainedModelPoleMatchingGeneral
-from .trained_model_pole_matching_rational import \
- TrainedModelPoleMatchingRational
-from .trained_model_pole_matching_reduced_basis import \
- TrainedModelPoleMatchingReducedBasis
__all__ = [
- 'TrainedModel',
'TrainedModelData',
'TrainedModelRational',
+ 'TrainedModelRationalMLS',
'TrainedModelReducedBasis',
'TrainedModelPivotedData',
- 'TrainedModelPivotedRational',
- 'TrainedModelPivotedReducedBasis',
- 'TrainedModelPoleMatchingGeneral',
- 'TrainedModelPoleMatchingRational',
- 'TrainedModelPoleMatchingReducedBasis'
+ 'TrainedModelPivotedRational'
]
diff --git a/rrompy/reduction_methods/trained_model/trained_model.py b/rrompy/reduction_methods/trained_model/trained_model.py
index dfc80ee..0c6a4bb 100644
--- a/rrompy/reduction_methods/trained_model/trained_model.py
+++ b/rrompy/reduction_methods/trained_model/trained_model.py
@@ -1,89 +1,96 @@
# 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 abc import abstractmethod
from rrompy.utilities.base.types import Np1D, paramList, sampList
from rrompy.parameter import checkParameterList
from rrompy.sampling import sampleList, emptySampleList
__all__ = ['TrainedModel']
class TrainedModel:
"""
ABSTRACT
ROM approximant evaluation.
Attributes:
Data: dictionary with all that can be pickled.
"""
def name(self) -> str:
return self.__class__.__name__
def __str__(self) -> str:
return self.name()
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
+ @property
+ def npar(self):
+ """Number of parameters."""
+ return self.data.mu0.shape[1]
+
@abstractmethod
def getApproxReduced(self, mu : paramList = []) -> sampList:
"""
Evaluate reduced representation of approximant at arbitrary parameter.
(ABSTRACT)
Args:
mu: Target parameter.
"""
pass
def getApprox(self, mu : paramList = []) -> sampList:
"""
Evaluate approximant at arbitrary parameter.
Args:
mu: Target parameter.
"""
mu = checkParameterList(mu, self.data.npar)[0]
if (not hasattr(self, "lastSolvedApprox")
or self.lastSolvedApprox != mu):
uApproxR = self.getApproxReduced(mu)
self.uApprox = emptySampleList()
- self.uApprox.reset((self.data.projMat.shape[0], len(mu)),
- self.data.projMat.dtype)
for i in range(len(mu)):
if isinstance(self.data.projMat, (list, sampleList,)):
- self.uApprox[i] = uApproxR[i][0] * self.data.projMat[0]
+ uApp = uApproxR[i][0] * self.data.projMat[0]
for j in range(1, uApproxR.shape[0]):
- self.uApprox[i] += (uApproxR[i][j]
- * self.data.projMat[j])
+ uApp += uApproxR[i][j] * self.data.projMat[j]
else:
- self.uApprox[i] = self.data.projMat.dot(uApproxR[i])
+ uApp = self.data.projMat.dot(uApproxR[i])
+ if i == 0:
+ #self.data.projMat.shape[0], len(mu)
+ self.uApprox.reset((len(uApp), len(mu)),
+ dtype = uApp.dtype)
+ self.uApprox[i] = uApp
self.lastSolvedApprox = mu
return self.uApprox
@abstractmethod
def getPoles(self) -> Np1D:
"""
Obtain approximant poles.
Returns:
Numpy complex vector of poles.
"""
pass
diff --git a/rrompy/reduction_methods/trained_model/trained_model_pivoted_data.py b/rrompy/reduction_methods/trained_model/trained_model_pivoted_data.py
index d8ba156..79b8803 100644
--- a/rrompy/reduction_methods/trained_model/trained_model_pivoted_data.py
+++ b/rrompy/reduction_methods/trained_model/trained_model_pivoted_data.py
@@ -1,70 +1,72 @@
# 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 .trained_model_data import TrainedModelData
from rrompy.utilities.base.types import Np2D, List, ListAny, paramVal
from rrompy.parameter import checkParameterList
__all__ = ['TrainedModelPivotedData']
class TrainedModelPivotedData(TrainedModelData):
"""ROM approximant evaluation data (must be pickle-able)."""
def __init__(self, name:str, mu0:paramVal, projMat:Np2D,
scaleFactor : ListAny = [1.],
rescalingExp : List[float] = [1.],
directionPivot : ListAny = [0]):
super().__init__(name, mu0, projMat, scaleFactor, rescalingExp)
self.directionPivot = directionPivot
@property
def directionMarginal(self):
return tuple([x for x in range(self.npar) \
if x not in self.directionPivot])
@property
def mu0Pivot(self):
- return checkParameterList(self.mu0(0, self.directionPivot))[0]
+ return checkParameterList(self.mu0(0, self.directionPivot),
+ self.nparPivot)[0]
@property
def mu0Marginal(self):
- return checkParameterList(self.mu0(0, self.directionMarginal))[0]
+ return checkParameterList(self.mu0(0, self.directionMarginal),
+ self.nparMarginal)[0]
@property
def nparPivot(self):
return len(self.directionPivot)
@property
def nparMarginal(self):
return self.npar - self.nparPivot
@property
def rescalingExpPivot(self):
return [self.rescalingExp[x] for x in self.directionPivot]
@property
def rescalingExpMarginal(self):
return [self.rescalingExp[x] for x in self.directionMarginal]
@property
def scaleFactorPivot(self):
return [self.scaleFactor[x] for x in self.directionPivot]
@property
def scaleFactorMarginal(self):
return [self.scaleFactor[x] for x in self.directionMarginal]
diff --git a/rrompy/reduction_methods/trained_model/trained_model_pole_matching_general.py b/rrompy/reduction_methods/trained_model/trained_model_pivoted_general.py
similarity index 60%
rename from rrompy/reduction_methods/trained_model/trained_model_pole_matching_general.py
rename to rrompy/reduction_methods/trained_model/trained_model_pivoted_general.py
index 3f088c5..9cddbce 100644
--- a/rrompy/reduction_methods/trained_model/trained_model_pole_matching_general.py
+++ b/rrompy/reduction_methods/trained_model/trained_model_pivoted_general.py
@@ -1,244 +1,375 @@
# 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 scipy.special import factorial as fact
+from itertools import combinations
from .trained_model import TrainedModel
-from rrompy.utilities.base.types import (Np1D, Tuple, ListAny, paramVal,
+from rrompy.utilities.base.types import (Np1D, Tuple, List, ListAny, paramVal,
paramList, sampList, HFEng)
from rrompy.utilities.base import verbosityManager as vbMng, freepar as fp
from rrompy.utilities.numerical import pointMatching
from rrompy.utilities.poly_fitting.heaviside import HeavisideInterpolator as HI
from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
from rrompy.parameter import checkParameter, checkParameterList
-from rrompy.sampling import emptySampleList
+from rrompy.sampling import emptySampleList, sampleList
-__all__ = ['TrainedModelPoleMatchingGeneral']
-class TrainedModelPoleMatchingGeneral(TrainedModel):
+__all__ = ['TrainedModelPivotedGeneral']
+
+class TrainedModelPivotedGeneral(TrainedModel):
"""
- ROM approximant evaluation for pivoted approximants with pole matching.
+ ROM approximant evaluation for pivoted approximants (with pole matching).
Attributes:
Data: dictionary with all that can be pickled.
"""
+ def centerNormalizePivot(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.mu0Pivot.
+
+ Returns:
+ Normalized parameter.
+ """
+ mu = checkParameterList(mu, self.data.nparPivot)[0]
+ if mu0 is None: mu0 = self.data.mu0Pivot
+ rad = ((mu ** self.data.rescalingExpPivot
+ - mu0 ** self.data.rescalingExpPivot)
+ / self.data.scaleFactorPivot)
+ return rad
+
+ 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 initializeFromLists(self, poles:ListAny, coeffs:ListAny, basis:str,
HFEngine:HFEng, matchingWeight : float = 1.,
POD : bool = True):
"""Initialize Heaviside representation."""
musM = self.data.musMarginal
- margAbsDist = np.sum(np.abs(np.tile(musM.data.reshape(len(musM),1,-1),
- [1, len(musM), 1])
- - np.tile(musM.data.reshape(1,len(musM),-1),
- [len(musM), 1, 1])), axis = 2)
+ 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))
N = len(poles[0])
explored = [0]
unexplored = list(range(1, len(musM)))
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)]
dist = np.abs(np.tile(poles[minIex].reshape(-1, 1), N)
- - poles[minIunex].reshape(1, -1))
+ - poles[minIunex].reshape(1, -1))
if matchingWeight != 0:
resex = coeffs[minIex][: N]
resunex = coeffs[minIunex][: N]
if POD:
distR = resex.dot(resunex.T.conj())
distR = (distR.T / np.linalg.norm(resex, axis = 1)).T
distR = distR / np.linalg.norm(resunex, axis = 1)
else:
resex = self.data.projMat.dot(resex.T)
resunex = self.data.projMat.dot(resunex.T)
distR = HFEngine.innerProduct(resex, resunex).T
distR = (distR.T / HFEngine.norm(resex)).T
distR = distR / HFEngine.norm(resunex)
distR = np.abs(distR)
distR[distR > 1.] = 1.
dist += 2. / np.pi * matchingWeight * np.arccos(distR)
- reordering = pointMatching(dist, verbObj = self)
+ reordering = pointMatching(dist)
poles[minIunex] = poles[minIunex][reordering]
coeffs[minIunex][: N] = coeffs[minIunex][reordering]
explored += [minIunex]
unexplored.remove(minIunex)
-# explored = np.append(explored, minIunex)
-# unexplored = unexplored[unexplored != minIunex]
HIs = []
for pls, cfs in zip(poles, coeffs):
hsi = HI()
hsi.poles = pls
hsi.coeffs = cfs
hsi.npar = 1
hsi.polybasis = basis
HIs += [hsi]
self.data.HIs = HIs
def recompressByCutOff(self, murange : Tuple[float, float] = [- 1., 1.],
tol : float = np.inf, rtype : str = "MAGNITUDE"):
if np.isinf(tol): return " No poles erased."
N = len(self.data.HIs[0].poles)
mu0 = np.mean(murange)
musig = murange[0] - mu0
if np.isclose(musig, 0.):
radius = lambda x: np.abs(x - mu0)
else:
if rtype == "MAGNITUDE":
murdir = (murange[0] - mu0) / np.abs(musig)
def radius(x):
scalprod = (x - mu0) * murdir.conj() / np.abs(musig)
rescalepar = np.abs(np.real(scalprod))
rescaleort = np.abs(np.imag(scalprod))
return ((rescalepar - 1.) ** 2. * (rescalepar > 1.)
+ rescaleort ** 2.) ** .5
else:#if rtype == "POTENTIAL":
def radius(x):
rescale = (x - mu0) / musig
return np.max(np.abs(rescale * np.array([-1., 1.])
+ (rescale ** 2. - 1) ** .5)) - 1.
keepPole, removePole = [], []
for j in range(N):
for hi in self.data.HIs:
if radius(hi.poles[j]) <= tol:
keepPole += [j]
break
if len(keepPole) == 0 or keepPole[-1] != j: removePole += [j]
if len(keepPole) == N: return " No poles erased."
keepCoeff = keepPole + [N]
keepCoeff = keepCoeff + list(range(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:
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, :]
return (" Erased {} pole".format(len(removePole))
+ "s" * (len(removePole) > 1) + ".")
+ def interpolateMarginal(self, mu : paramList = [],
+ samples : ListAny = [], der : List[int] = None,
+ scl : Np1D = None) -> sampList:
+ """
+ Evaluate marginal interpolator at arbitrary marginal parameter.
+
+ Args:
+ mu: Target parameter.
+ samples: Objects to interpolate.
+ der(optional): Derivatives to take before evaluation.
+ """
+ mu = checkParameterList(mu, self.data.nparMarginal)[0]
+ sList = isinstance(samples[0], sampleList)
+ sEff = [None] * len(samples)
+ for j in range(len(samples)):
+ if sList:
+ sEff[j] = samples[j].data
+ else:
+ sEff[j] = samples[j]
+ try:
+ dtype = sEff[0].dtype
+ except:
+ dtype = sEff[0][0].dtype
+ vbMng(self, "INIT", "Interpolating marginal at mu = {}.".format(mu),
+ 95)
+ muC = self.centerNormalizeMarginal(mu)
+ p = emptySampleList()
+ p.reset((len(sEff[0]), len(muC)), dtype = dtype)
+ p.data[:] = 0.
+ if len(sEff[0]) > 0:
+ for mIj, spj in zip(self.data.marginalInterp, sEff):
+ p = p + spj.reshape(len(sEff[0]), - 1) * mIj(muC, der, scl)
+ vbMng(self, "DEL", "Done interpolating marginal.", 95)
+ if not sList:
+ p = p.data.flatten()
+ return p
+
def interpolateMarginalInterpolator(self, mu : paramVal = []) -> Np1D:
"""Obtain interpolated approximant interpolator."""
mu = checkParameter(mu, self.data.nparMarginal)[0]
hsi = HI()
hsi.poles = self.interpolateMarginalPoles(mu)
hsi.coeffs = self.interpolateMarginalCoeffs(mu)
hsi.npar = 1
hsi.polybasis = self.data.HIs[0].polybasis
return hsi
def interpolateMarginalPoles(self, mu : paramList = []) -> Np1D:
"""Obtain interpolated approximant poles."""
mu = checkParameterList(mu, self.data.nparMarginal)[0]
return self.interpolateMarginal(mu, [hi.poles for hi in self.data.HIs])
def interpolateMarginalCoeffs(self, mu : paramList = []) -> Np1D:
"""Obtain interpolated approximant coefficients."""
mu = checkParameterList(mu, self.data.nparMarginal)[0]
cs = self.interpolateMarginal(mu, [hi.coeffs for hi in self.data.HIs])
if isinstance(cs, (list, tuple,)): cs = np.array(cs)
return cs.reshape(self.data.HIs[0].coeffs.shape)
def getApproxReduced(self, mu : paramList = []) -> sampList:
"""
Evaluate reduced representation of approximant at arbitrary parameter.
Args:
mu: Target parameter.
"""
RROMPyAssert(self.data.nparPivot, 1, "Number of pivot parameters")
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()
- self.uApproxReduced.reset((self.data.HIs[0].coeffs.shape[1],
- len(mu)), self.data.projMat[0].dtype)
-
for i, muPL in enumerate(mu):
muL = self.centerNormalizePivot([muPL(0, x) \
for x in self.data.directionPivot])
muM = [muPL(0, x) for x in self.data.directionMarginal]
vbMng(self, "INIT",
"Assembling reduced model for mu = {}.".format(muPL), 87)
hsL = self.interpolateMarginalInterpolator(muM)
vbMng(self, "DEL", "Done assembling reduced model.", 87)
- self.uApproxReduced[i] = hsL(muL)
+ uAppR = hsL(muL)
+ if i == 0:
+ #self.data.HIs[0].coeffs.shape[1], len(mu)
+ self.uApproxReduced.reset((len(uAppR), len(mu)),
+ dtype = uAppR.dtype)
+ self.uApproxReduced[i] = uAppR
vbMng(self, "DEL", "Done evaluating approximant.", 12)
self.lastSolvedApproxReduced = mu
return self.uApproxReduced
+ def getPVal(self, mu : paramList = []) -> sampList:
+ """
+ Evaluate rational numerator at arbitrary parameter.
+
+ Args:
+ mu: Target parameter.
+ """
+ RROMPyAssert(self.data.nparPivot, 1, "Number of pivot parameters")
+ mu = checkParameterList(mu, self.data.npar)[0]
+ p = emptySampleList()
+ p.reset((len(self.data.HIs[0].coeffs.shape[1]), len(mu)))
+ for i, muPL in enumerate(mu):
+ muL = self.centerNormalizePivot([muPL(0, x) \
+ for x in self.data.directionPivot])
+ muM = [muPL(0, x) for x in self.data.directionMarginal]
+ hsL = self.interpolateMarginalInterpolator(muM)
+ p[i] = hsL(muL) * np.prod(muL(0, 0) - hsL.poles)
+ return p
+
+ def getQVal(self, mu:Np1D, der : List[int] = None,
+ scl : Np1D = None) -> Np1D:
+ """
+ Evaluate rational denominator at arbitrary parameter.
+
+ Args:
+ mu: Target parameter.
+ der(optional): Derivatives to take before evaluation.
+ """
+ RROMPyAssert(self.data.nparPivot, 1, "Number of pivot parameters")
+ mu = checkParameterList(mu, self.data.npar)[0]
+ muP = self.centerNormalizePivot(checkParameterList(
+ mu.data[:, self.data.directionPivot],
+ self.data.nparPivot)[0])
+ muM = checkParameterList(mu.data[:, self.data.directionMarginal],
+ self.data.nparMarginal)[0]
+ if der is None:
+ derP, derM = 0, [0]
+ else:
+ derP = der[self.data.directionPivot[0]]
+ derM = [der[x] for x in self.data.directionMarginal]
+ if np.any(np.array(derM) != 0):
+ raise RROMPyException(("Derivatives of Q with respect to marginal "
+ "parameters not allowed."))
+ sclP = 1 if scl is None else scl[self.data.directionPivot[0]]
+ derVal = np.zeros(len(mu), dtype = np.complex)
+ N = len(self.data.HIs[0].poles)
+ if derP == N: derVal[:] = 1.
+ elif derP >= 0 and derP < N:
+ pls = self.interpolateMarginalPoles(muM).reshape(-1, len(mu)).T
+ plsDist = muP.data.reshape(-1, 1) - pls
+ for terms in combinations(np.arange(N), N - derP):
+ derVal += np.prod(plsDist[:, list(terms)], axis = 1)
+ return sclP ** derP * fact(derP) * derVal
+
def getPoles(self, *args, **kwargs) -> Np1D:
"""
Obtain approximant poles.
Returns:
Numpy complex vector of poles.
"""
RROMPyAssert(self.data.nparPivot, 1, "Number of pivot parameters")
if len(args) + len(kwargs) > 1:
raise RROMPyException(("Wrong number of parameters passed. "
"Only 1 available."))
elif len(args) + len(kwargs) == 1:
if len(args) == 1:
mVals = args[0]
else:
mVals = kwargs["marginalVals"]
if not hasattr(mVals, "__len__"): mVals = [mVals]
mVals = list(mVals)
else:
mVals = [fp]
try:
rDim = mVals.index(fp)
if rDim < len(mVals) - 1 and fp in mVals[rDim + 1 :]:
raise
except:
raise RROMPyException(("Exactly 1 'freepar' entry in "
"marginalVals must be provided."))
if rDim != self.data.directionPivot[0]:
raise RROMPyException(("'freepar' entry in marginalVals must "
"coincide with pivot direction."))
mVals[rDim] = self.data.mu0(rDim)
mMarg = [mVals[j] for j in range(len(mVals)) if j != rDim]
- roots = np.array(self.interpolateMarginalPoles(mMarg))
+ roots = np.sort(np.array(self.interpolateMarginalPoles(mMarg)))
return np.power(self.data.mu0(rDim) ** self.data.rescalingExp[rDim]
+ self.data.scaleFactor[rDim] * roots,
1. / self.data.rescalingExp[rDim])
def getResidues(self, *args, **kwargs) -> Np1D:
"""
Obtain approximant residues.
Returns:
Numpy matrix with residues as columns.
"""
pls = self.getPoles(*args, **kwargs)
if len(args) == 1:
mVals = args[0]
else:
mVals = kwargs["marginalVals"]
if not hasattr(mVals, "__len__"): mVals = [mVals]
mVals = list(mVals)
rDim = mVals.index(fp)
mMarg = [mVals[j] for j in range(len(mVals)) if j != rDim]
residues = self.interpolateMarginalCoeffs(mMarg)[: len(pls)]
- res = self.data.projMat.dot(residues)
+ res = self.data.projMat.dot(residues.T)
return pls, res
diff --git a/rrompy/reduction_methods/trained_model/trained_model_pivoted_rational.py b/rrompy/reduction_methods/trained_model/trained_model_pivoted_rational.py
index 2417a25..e8c519f 100644
--- a/rrompy/reduction_methods/trained_model/trained_model_pivoted_rational.py
+++ b/rrompy/reduction_methods/trained_model/trained_model_pivoted_rational.py
@@ -1,225 +1,106 @@
# 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_pivoted_general import TrainedModelPivotedGeneral
from .trained_model_rational import TrainedModelRational
-from rrompy.utilities.base.types import (Np1D, List, ListAny, paramVal,
- paramList, sampList)
-from rrompy.utilities.base import verbosityManager as vbMng, freepar as fp
-from rrompy.utilities.poly_fitting.polynomial import polyroots
-from rrompy.utilities.exception_manager import RROMPyException
-from rrompy.parameter import checkParameter, checkParameterList
-from rrompy.sampling import sampleList, emptySampleList
+from rrompy.utilities.base.types import Np1D, List, paramList, sampList, HFEng
+from rrompy.utilities.base import verbosityManager as vbMng
+from rrompy.utilities.poly_fitting.heaviside import rational2heaviside
+from rrompy.utilities.exception_manager import RROMPyAssert
+from rrompy.parameter import checkParameterList
+from rrompy.sampling import sampleList
__all__ = ['TrainedModelPivotedRational']
-class TrainedModelPivotedRational(TrainedModelRational):
+class TrainedModelPivotedRational(TrainedModelPivotedGeneral,
+ TrainedModelRational):
"""
- ROM approximant evaluation for pivoted Rational approximant.
+ ROM approximant evaluation for pivoted Rational approximant (with pole
+ matching).
Attributes:
Data: dictionary with all that can be pickled.
"""
- def centerNormalizePivot(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.mu0.
-
- Returns:
- Normalized parameter.
- """
- mu = checkParameterList(mu, self.data.nparPivot)[0]
- if mu0 is None: mu0 = self.data.mu0(self.data.directionPivot)
- rad = ((mu ** self.data.rescalingExpPivot
- - mu0 ** self.data.rescalingExpPivot)
- / self.data.scaleFactorPivot)
- return rad
-
- 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.mu0.
-
- Returns:
- Normalized parameter.
- """
- mu = checkParameterList(mu, self.data.nparMarginal)[0]
- if mu0 is None: mu0 = self.data.mu0(self.data.directionMarginal)
- rad = ((mu ** self.data.rescalingExpMarginal
- - mu0 ** self.data.rescalingExpMarginal)
- / self.data.scaleFactorMarginal)
- return rad
-
- def interpolateMarginal(self, mu : paramList = [],
- samples : ListAny = [], der : List[int] = None,
- scl : Np1D = None) -> sampList:
- """
- Evaluate marginal interpolator at arbitrary marginal parameter.
-
- Args:
- mu: Target parameter.
- samples: Objects to interpolate.
- der(optional): Derivatives to take before evaluation.
- """
- mu = checkParameterList(mu, self.data.nparMarginal)[0]
- sList = isinstance(samples[0], sampleList)
- sEff = [None] * len(samples)
- for j in range(len(samples)):
- if sList:
- sEff[j] = samples[j].data
- else:
- sEff[j] = samples[j]
- vbMng(self, "INIT", "Interpolating marginal at mu = {}.".format(mu),
- 95)
- muC = self.centerNormalizeMarginal(mu)
- p = emptySampleList()
- p.reset((len(sEff[0]), len(muC)))
- p.data[:] = 0.
- if len(sEff[0]) > 0:
- for mIj, spj in zip(self.data.marginalInterp, sEff):
- p = p + spj.reshape(len(sEff[0]), - 1) * mIj(muC, der, scl)
- vbMng(self, "DEL", "Done interpolating marginal.", 95)
- if not sList:
- p = p.data.flatten()
- return p
-
- def getPValsPivot(self, mu : paramList = []) -> sampList:
- """
- Evaluate rational numerators at arbitrary pivot parameter.
-
- Args:
- mu: Target parameter.
- """
- mu = checkParameterList(mu, self.data.nparPivot)[0]
- vbMng(self, "INIT", "Evaluating numerator at mu = {}.".format(mu), 17)
- muC = self.centerNormalizePivot(mu)
- pP = [sampleList(P(muC)) for P in self.data.Ps]
- vbMng(self, "DEL", "Done evaluating numerator.", 17)
- return pP
+ def initializeFromRational(self, HFEngine:HFEng,
+ matchingWeight : float = 1., POD : 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)
+ self.data._temporary = False
def getPVal(self, mu : paramList = []) -> sampList:
"""
Evaluate rational numerator at arbitrary parameter.
Args:
mu: Target parameter.
"""
+ RROMPyAssert(self.data.nparPivot, 1, "Number of pivot parameters")
+ if not self.data._temporary: return super().getPVal(mu)
mu = checkParameterList(mu, self.data.npar)[0]
muP = checkParameterList(mu.data[:, self.data.directionPivot],
self.data.nparPivot)[0]
muM = checkParameterList(mu.data[:, self.data.directionMarginal],
self.data.nparMarginal)[0]
- pP = self.getPValsPivot(muP)
+ muP = checkParameterList(muP, self.data.nparPivot)[0]
+ vbMng(self, "INIT", "Evaluating numerator at mu = {}.".format(muP), 17)
+ muPC = self.centerNormalizePivot(muP)
+ pP = [sampleList(P(muPC)) for P in self.data.Ps]
+ vbMng(self, "DEL", "Done evaluating numerator.", 17)
return self.interpolateMarginal(muM, pP)
- def getQValsPivot(self, mu:Np1D, der : List[int] = None,
- scl : Np1D = None) -> Np1D:
- """
- Evaluate rational denominators at arbitrary pivot parameter.
-
- Args:
- mu: Target parameter.
- der(optional): Derivatives to take before evaluation.
- """
- mu = checkParameterList(mu, self.data.nparPivot)[0]
- vbMng(self, "INIT", "Evaluating denominator at mu = {}.".format(mu),
- 17)
- muC = self.centerNormalizePivot(mu)
- qP = [Q(muC, der, scl).reshape(1, -1) for Q in self.data.Qs]
- vbMng(self, "DEL", "Done evaluating denominator.", 17)
- return qP
-
def getQVal(self, mu:Np1D, der : List[int] = None,
scl : Np1D = None) -> Np1D:
"""
Evaluate rational denominator at arbitrary parameter.
Args:
mu: Target parameter.
der(optional): Derivatives to take before evaluation.
"""
+ RROMPyAssert(self.data.nparPivot, 1, "Number of pivot parameters")
+ if not self.data._temporary: return super().getQVal(mu, der, scl)
mu = checkParameterList(mu, self.data.npar)[0]
muP = checkParameterList(mu.data[:, self.data.directionPivot],
self.data.nparPivot)[0]
muM = checkParameterList(mu.data[:, self.data.directionMarginal],
self.data.nparMarginal)[0]
if der is None:
derP, derM = None, None
else:
derP = [der[x] for x in self.data.directionPivot]
derM = [der[x] for x in self.data.directionMarginal]
if scl is None:
sclP, sclM = None, None
else:
sclP = [scl[x] for x in self.data.directionPivot]
sclM = [scl[x] for x in self.data.directionMarginal]
- qP = self.getQValsPivot(muP, derP, sclP)
+ muP = checkParameterList(muP, self.data.nparPivot)[0]
+ vbMng(self, "INIT", "Evaluating denominator at mu = {}.".format(muP),
+ 17)
+ muPC = self.centerNormalizePivot(muP)
+ qP = [Q(muPC, derP, sclP).reshape(1, -1) for Q in self.data.Qs]
+ vbMng(self, "DEL", "Done evaluating denominator.", 17)
return self.interpolateMarginal(muM, qP, derM, sclM)
-
- def getPoles(self, *args, **kwargs) -> Np1D:
- """
- Obtain approximant poles.
-
- Returns:
- Numpy complex vector of poles.
- """
- if len(args) + len(kwargs) > 1:
- raise RROMPyException(("Wrong number of parameters passed. "
- "Only 1 available."))
- elif len(args) + len(kwargs) == 1:
- if len(args) == 1:
- mVals = args[0]
- else:
- mVals = kwargs["marginalVals"]
- if not hasattr(mVals, "__len__"): mVals = [mVals]
- mVals = list(mVals)
- else:
- mVals = [fp]
- mValsP = [mVals[x] for x in self.data.directionPivot]
- mValsM = [mVals[x] for x in self.data.directionMarginal]
- try:
- rDim = mValsP.index(fp)
- if rDim < len(mValsP) - 1 and fp in mValsP[rDim + 1 :]:
- raise
- except:
- raise RROMPyException(("Exactly 1 'freepar' entry in "
- "marginalVals must be provided."))
- if fp in mValsM:
- raise RROMPyException(("'freepar' entry in marginalVals must be "
- "pivot dimension."))
- rDimB = self.data.directionPivot[rDim]
- Qeff = self.interpolateMarginal(mValsM, [Q.coeffs[:, np.newaxis] \
- for Q in self.data.Qs])
- Qeff = Qeff.reshape(self.data.Qs[0].coeffs.shape)
- mValsP[rDim] = self.data.mu0(rDimB)
- mValsP = self.centerNormalizePivot(checkParameter(mValsP))
- mValsP = list(mValsP.data.flatten())
- mValsP[rDim] = fp
- return np.power(self.data.mu0(rDimB) ** self.data.rescalingExp[rDimB]
- + self.data.scaleFactor[rDimB]
- * polyroots(Qeff, self.data.Qs[0].polybasis, mValsP),
- 1. / self.data.rescalingExp[rDimB])
diff --git a/rrompy/reduction_methods/trained_model/trained_model_pivoted_reduced_basis.py b/rrompy/reduction_methods/trained_model/trained_model_pivoted_reduced_basis.py
deleted file mode 100644
index 490a1b0..0000000
--- a/rrompy/reduction_methods/trained_model/trained_model_pivoted_reduced_basis.py
+++ /dev/null
@@ -1,202 +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_reduced_basis import TrainedModelReducedBasis
-from rrompy.utilities.base.types import (Np1D, ListAny, paramVal, paramList,
- sampList)
-from rrompy.utilities.base import verbosityManager as vbMng, freepar as fp
-from rrompy.utilities.poly_fitting.polynomial import (
- hashIdxToDerivative as hashI)
-from rrompy.utilities.numerical import (eigvalsNonlinearDense,
- marginalizePolyList)
-from rrompy.utilities.exception_manager import RROMPyException
-from rrompy.parameter import checkParameter, checkParameterList
-from rrompy.sampling import emptySampleList, sampleList
-
-__all__ = ['TrainedModelPivotedReducedBasis']
-
-class TrainedModelPivotedReducedBasis(TrainedModelReducedBasis):
- """
- ROM approximant evaluation for pivoted RB approximant.
-
- Attributes:
- Data: dictionary with all that can be pickled.
- """
-
- def centerNormalizePivot(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.mu0.
-
- Returns:
- Normalized parameter.
- """
- mu = checkParameterList(mu, self.data.nparPivot)[0]
- if mu0 is None: mu0 = self.data.mu0Pivot
- rad = ((mu ** self.data.rescalingExpPivot
- - mu0 ** self.data.rescalingExpPivot)
- / self.data.scaleFactorPivot)
- return rad
-
- 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.mu0.
-
- 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 interpolateMarginal(self, mu : paramVal = [],
- samples : ListAny = []) -> ListAny:
- """
- Evaluate marginal interpolator at arbitrary marginal parameter.
-
- Args:
- mu: Target parameter.
- samples: Objects to interpolate.
- """
- mu = checkParameter(mu, self.data.nparMarginal)
- sList = isinstance(samples[0], sampleList)
- sEff = [None] * len(samples)
- for j in range(len(samples)):
- if sList:
- sEff[j] = samples[j].data
- else:
- sEff[j] = samples[j]
- vbMng(self, "INIT", "Interpolating marginal at mu = {}.".format(mu),
- 95)
- muC = self.centerNormalizeMarginal(mu)
- p = np.zeros_like(sEff[0], dtype = sEff[0].dtype)
- for mIj, spj in zip(self.data.marginalInterp, sEff):
- p += mIj(muC) * spj
- vbMng(self, "DEL", "Done interpolating marginal.", 95)
-# if sList: p = sampleList(p)
- return p
-
- 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",
- "Computing RB solution at mu = {}.".format(mu), 12)
- self.uApproxReduced = emptySampleList()
- self.uApproxReduced.reset((self.data.ARBsList[0][0].shape[0],
- len(mu)), self.data.projMat[0].dtype)
- for i, muPL in enumerate(mu):
- muP = checkParameter([muPL(0, x) \
- for x in self.data.directionPivot])
- muM = [muPL(0, x) for x in self.data.directionMarginal]
- vbMng(self, "INIT",
- "Assembling reduced model for mu = {}.".format(muPL), 87)
- ARBs = self.interpolateMarginal(muM, self.data.ARBsList)
- bRBs = self.interpolateMarginal(muM, self.data.bRBsList)
- ARBmu = ARBs[0]
- bRBmu = bRBs[0]
- for j in range(1, max(len(ARBs), len(bRBs))):
- theta = np.prod(self.centerNormalizePivot(muP)
- ** hashI(j, self.data.nparPivot))
- if j < len(ARBs):
- ARBmu += theta * ARBs[j]
- if j < len(bRBs):
- bRBmu += theta * bRBs[j]
- vbMng(self, "DEL", "Done assembling reduced model.", 87)
- vbMng(self, "INIT",
- "Solving reduced model for mu = {}.".format(muPL), 75)
- self.uApproxReduced[i] = np.linalg.solve(ARBmu, bRBmu)
- vbMng(self, "DEL", "Done solving reduced model.", 75)
- vbMng(self, "DEL", "Done computing RB solution.", 12)
- self.lastSolvedApproxReduced = mu
- return self.uApproxReduced
-
- def getApprox(self, mu : paramList = []) -> sampList:
- """
- Evaluate approximant at arbitrary parameter.
-
- Args:
- mu: Target parameter.
- """
- mu = checkParameterList(mu, self.data.npar)[0]
- if (not hasattr(self, "lastSolvedApprox")
- or self.lastSolvedApprox != mu):
- uApproxR = self.getApproxReduced(mu)
- self.uApprox = emptySampleList()
- self.uApprox.reset((self.data.projMat[0].shape[0], len(mu)),
- self.data.projMat[0].dtype)
- for i in range(len(mu)):
- muM = [mu(i, x) for x in self.data.directionMarginal]
- projLoc = self.interpolateMarginal(muM, self.data.projMat)[0]
- self.uApprox[i] = projLoc.dot(uApproxR[i])
- self.lastSolvedApprox = mu
- return self.uApprox
-
- def getPoles(self, marginalVals : ListAny = [fp], jSupp : int = 1,
- **kwargs) -> Np1D:
- """
- Obtain approximant poles.
-
- Returns:
- Numpy complex vector of poles.
- """
- if not hasattr(marginalVals, "__len__"): marginalVals = [marginalVals]
- marginalVals = list(marginalVals)
- try:
- rDim = marginalVals.index(fp)
- if rDim < len(marginalVals) - 1 and fp in marginalVals[rDim + 1 :]:
- raise
- except:
- raise RROMPyException(("Exactly 1 'freepar' entry in "
- "marginalVals must be provided."))
- if rDim in self.data.directionMarginal:
- raise RROMPyException(("'freepar' entry in marginalVals must be "
- "in pivot dimension."))
- mValsP = [marginalVals[x] for x in self.data.directionPivot]
- rDimP = mValsP.index(fp)
- mValsM = [marginalVals[x] for x in self.data.directionMarginal]
- ARBs = self.interpolateMarginal(mValsM, self.data.ARBsList)
- if self.data.nparPivot > 1:
- mValsP[rDimP] = self.data.mu0Pivot(rDimP)
- mValsP = self.centerNormalizePivot(mValsP)
- mValsP = mValsP.data.flatten()
- mValsP[rDimP] = fp
- ARBs = marginalizePolyList(ARBs, mValsP, "auto")
- ev = eigvalsNonlinearDense(ARBs, jSupp = jSupp, **kwargs)
- return np.power(self.data.mu0(rDim) ** self.data.rescalingExp[rDim]
- + ev * self.scaleFactor[rDim],
- 1. / self.data.rescalingExp[rDim])
diff --git a/rrompy/reduction_methods/trained_model/trained_model_pole_matching_rational.py b/rrompy/reduction_methods/trained_model/trained_model_pole_matching_rational.py
deleted file mode 100644
index c24171f..0000000
--- a/rrompy/reduction_methods/trained_model/trained_model_pole_matching_rational.py
+++ /dev/null
@@ -1,109 +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 scipy.special import factorial as fact
-from itertools import combinations
-from .trained_model_pole_matching_general import \
- TrainedModelPoleMatchingGeneral
-from .trained_model_pivoted_rational import TrainedModelPivotedRational
-from rrompy.utilities.base.types import Np1D, List, paramList, sampList, HFEng
-from rrompy.utilities.poly_fitting.heaviside import rational2heaviside
-from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
-from rrompy.parameter import checkParameterList
-from rrompy.sampling import emptySampleList
-
-__all__ = ['TrainedModelPoleMatchingRational']
-
-class TrainedModelPoleMatchingRational(TrainedModelPoleMatchingGeneral,
- TrainedModelPivotedRational):
- """
- ROM approximant evaluation for pivoted Rational approximant with pole
- matching.
-
- Attributes:
- Data: dictionary with all that can be pickled.
- """
-
- def initializeFromRational(self, HFEngine:HFEng,
- matchingWeight : float = 1., POD : 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)
- self.data._temporary = False
-
- def getPVal(self, mu : paramList = []) -> sampList:
- """
- Evaluate rational numerator at arbitrary parameter.
-
- Args:
- mu: Target parameter.
- """
- if self.data._temporary: return super().getPVal(mu)
- RROMPyAssert(self.data.nparPivot, 1, "Number of pivot parameters")
- mu = checkParameterList(mu, self.data.npar)[0]
- p = emptySampleList()
- p.reset((len(self.data.HIs[0].coeffs.shape[1]), len(mu)))
- for i, muPL in enumerate(mu):
- muL = self.centerNormalizePivot([muPL(0, x) \
- for x in self.data.directionPivot])
- muM = [muPL(0, x) for x in self.data.directionMarginal]
- hsL = self.interpolateMarginalInterpolator(muM)
- p[i] = hsL(muL) * np.prod(muL(0, 0) - hsL.poles)
- return p
-
- def getQVal(self, mu:Np1D, der : List[int] = None,
- scl : Np1D = None) -> Np1D:
- """
- Evaluate rational denominator at arbitrary parameter.
-
- Args:
- mu: Target parameter.
- der(optional): Derivatives to take before evaluation.
- """
- if self.data._temporary: return super().getQVal(mu, der, scl)
- RROMPyAssert(self.data.nparPivot, 1, "Number of pivot parameters")
- mu = checkParameterList(mu, self.data.npar)[0]
- muP = self.centerNormalizePivot(checkParameterList(
- mu.data[:, self.data.directionPivot], 1)[0])
- muM = checkParameterList(mu.data[:, self.data.directionMarginal],
- self.data.npar - 1)[0]
- if der is None:
- derP, derM = 0, [0]
- else:
- derP = der[self.data.directionPivot[0]]
- derM = [der[x] for x in self.data.directionMarginal]
- if np.any(np.array(derM) != 0):
- raise RROMPyException(("Derivatives of Q with respect to marginal "
- "parameters not allowed."))
- sclP = 1 if scl is None else scl[self.data.directionPivot[0]]
- derVal = np.zeros(len(mu), dtype = self.data.HIs[0].poles.dtype)
- N = len(self.data.HIs[0].poles)
- if derP == N: derVal[:] = 1.
- elif derP >= 0 and derP < N:
- pls = self.interpolateMarginalPoles(muM).reshape(-1, len(mu)).T
- plsDist = muP.data.reshape(-1, 1) - pls
- for terms in combinations(np.arange(N), N - derP):
- derVal += np.prod(plsDist[:, list(terms)], axis = 1)
- return sclP ** derP * fact(derP) * derVal
diff --git a/rrompy/reduction_methods/trained_model/trained_model_pole_matching_reduced_basis.py b/rrompy/reduction_methods/trained_model/trained_model_pole_matching_reduced_basis.py
deleted file mode 100644
index 23802b1..0000000
--- a/rrompy/reduction_methods/trained_model/trained_model_pole_matching_reduced_basis.py
+++ /dev/null
@@ -1,56 +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_pole_matching_general import \
- TrainedModelPoleMatchingGeneral
-from .trained_model_pivoted_reduced_basis import \
- TrainedModelPivotedReducedBasis
-from rrompy.utilities.base.types import HFEng
-from rrompy.utilities.poly_fitting.heaviside import affine2heaviside
-from rrompy.utilities.exception_manager import RROMPyAssert
-
-__all__ = ['TrainedModelPoleMatchingReducedBasis']
-
-class TrainedModelPoleMatchingReducedBasis(TrainedModelPoleMatchingGeneral,
- TrainedModelPivotedReducedBasis):
- """
- ROM approximant evaluation for pivoted RB approximant with pole matching.
-
- Attributes:
- Data: dictionary with all that can be pickled.
- """
-
- def initializeFromAffine(self, HFEngine:HFEng, matchingWeight : float = 1.,
- POD : bool = True, jSupp : int = 1):
- """Initialize Heaviside representation."""
- RROMPyAssert(self.data.nparPivot, 1, "Number of pivot parameters")
- poles, coeffs = [], []
- nbadpls = 0
- for As, bs in zip(self.data.ARBsList, self.data.bRBsList):
- cfs, pls, basis = affine2heaviside(As, bs, jSupp)
- poles += [pls]
- coeffs += [cfs]
- nbadpls = max(nbadpls, np.sum(np.isinf(pls)))
- if nbadpls > 0:
- for j in range(len(poles)):
- plsgood = np.argsort(np.abs(pls))[: - nbadpls]
- poles[j] = poles[j][plsgood]
- coeffs[j] = coeffs[j][plsgood, :]
- self.initializeFromLists(poles, coeffs, basis, HFEngine,
- matchingWeight, POD)
diff --git a/rrompy/reduction_methods/trained_model/trained_model_rational.py b/rrompy/reduction_methods/trained_model/trained_model_rational.py
index 8f5ec51..c7dcebc 100644
--- a/rrompy/reduction_methods/trained_model/trained_model_rational.py
+++ b/rrompy/reduction_methods/trained_model/trained_model_rational.py
@@ -1,163 +1,164 @@
# 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 . import TrainedModel
+from .trained_model import TrainedModel
from rrompy.utilities.base.types import (Np1D, List, paramVal, paramList,
sampList)
from rrompy.utilities.base import verbosityManager as vbMng, freepar as fp
from rrompy.utilities.exception_manager import RROMPyException
from rrompy.parameter import (checkParameter, checkParameterList,
emptyParameterList)
from rrompy.sampling import sampleList
__all__ = ['TrainedModelRational']
class TrainedModelRational(TrainedModel):
"""
ROM approximant evaluation for rational approximant.
Attributes:
Data: dictionary with all that can be pickled.
"""
def centerNormalize(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.mu0.
Returns:
Normalized parameter.
"""
mu = checkParameterList(mu, self.data.npar)[0]
if mu0 is None: mu0 = self.data.mu0
rad = ((mu ** self.data.rescalingExp - mu0 ** self.data.rescalingExp)
/ self.data.scaleFactor)
return rad
def getPVal(self, mu : paramList = []) -> sampList:
"""
Evaluate rational numerator at arbitrary parameter.
Args:
mu: Target parameter.
"""
mu = checkParameterList(mu, self.data.npar)[0]
vbMng(self, "INIT", "Evaluating numerator at mu = {}.".format(mu), 17)
muCenter = self.centerNormalize(mu)
p = sampleList(self.data.P(muCenter))
vbMng(self, "DEL", "Done evaluating numerator.", 17)
return p
def getQVal(self, mu:Np1D, der : List[int] = None,
scl : Np1D = None) -> Np1D:
"""
Evaluate rational denominator at arbitrary parameter.
Args:
mu: Target parameter.
der(optional): Derivatives to take before evaluation.
"""
mu = checkParameterList(mu, self.data.npar)[0]
vbMng(self, "INIT", "Evaluating denominator at mu = {}.".format(mu),
17)
muCenter = self.centerNormalize(mu)
q = self.data.Q(muCenter, der, scl)
vbMng(self, "DEL", "Done evaluating denominator.", 17)
return q
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 = self.getPVal(mu) / self.getQVal(mu)
vbMng(self, "DEL", "Done evaluating approximant.", 12)
self.lastSolvedApproxReduced = mu
return self.uApproxReduced
def getPoles(self, *args, **kwargs) -> Np1D:
"""
Obtain approximant poles.
Returns:
Numpy complex vector of poles.
"""
if len(args) + len(kwargs) > 1:
raise RROMPyException(("Wrong number of parameters passed. "
"Only 1 available."))
elif len(args) + len(kwargs) == 1:
if len(args) == 1:
mVals = args[0]
else:
mVals = kwargs["marginalVals"]
if not hasattr(mVals, "__len__"): mVals = [mVals]
mVals = list(mVals)
else:
mVals = [fp]
try:
rDim = mVals.index(fp)
if rDim < len(mVals) - 1 and fp in mVals[rDim + 1 :]:
raise
except:
raise RROMPyException(("Exactly 1 'freepar' entry in "
"marginalVals must be provided."))
mVals[rDim] = self.data.mu0(rDim)
mVals = self.centerNormalize(checkParameter(mVals, len(mVals)))
mVals = list(mVals.data.flatten())
mVals[rDim] = fp
return np.power(self.data.mu0(rDim) ** self.data.rescalingExp[rDim]
- + self.data.scaleFactor[rDim] * self.data.Q.roots(mVals),
+ + self.data.scaleFactor[rDim]
+ * np.sort(self.data.Q.roots(mVals)),
1. / self.data.rescalingExp[rDim])
def getResidues(self, *args, **kwargs) -> Np1D:
"""
Obtain approximant residues.
Returns:
Numpy matrix with residues as columns.
"""
pls = self.getPoles(*args, **kwargs)
if len(args) == 1:
mVals = args[0]
else:
mVals = kwargs["marginalVals"]
if not hasattr(mVals, "__len__"): mVals = [mVals]
mVals = list(mVals)
rDim = mVals.index(fp)
poles = emptyParameterList()
poles.reset((len(pls), self.data.npar), dtype = pls.dtype)
for k, pl in enumerate(pls):
poles[k] = mVals
poles.data[k, rDim] = pl
res = (self.data.projMat.dot(self.getPVal(poles).data)
/ self.getQVal(poles,
list(1 * (np.arange(self.data.npar) == rDim))))
return pls, res
diff --git a/rrompy/reduction_methods/trained_model/trained_model_rational_mls.py b/rrompy/reduction_methods/trained_model/trained_model_rational_mls.py
new file mode 100644
index 0000000..f012a55
--- /dev/null
+++ b/rrompy/reduction_methods/trained_model/trained_model_rational_mls.py
@@ -0,0 +1,174 @@
+# 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, degreeTotalToFull
+from rrompy.parameter import checkParameterList
+from rrompy.sampling import emptySampleList
+
+__all__ = ['TrainedModelRationalMLS']
+
+class TrainedModelRationalMLS(TrainedModelRational):
+ """
+ ROM approximant evaluation for rational moving least squares approximant.
+
+ Attributes:
+ Data: dictionary with all that can be pickled.
+ """
+
+ def assembleReducedModel(self, mu:paramVal):
+ if not hasattr(self, "lastSetupMu") or self.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,
+ nNearestNeighbor = self.data.nNearestNeighborDen)
+ 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)
+ _, s, eV = np.linalg.svd(Rstack, full_matrices = False)
+ 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)
+ ev, eV = np.linalg.eigh(gram)
+ 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,
+ nNearestNeighbor = self.data.nNearestNeighbor)
+ 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.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)
+ uAppR = self.getPVal(mu[i]) / self.getQVal(mu[i])
+ if i == 0:
+ #self.data.P.shape[-1], len(mu)
+ self.uApproxReduced.reset((len(uAppR), 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/reduction_methods/trained_model/trained_model_reduced_basis.py b/rrompy/reduction_methods/trained_model/trained_model_reduced_basis.py
index 6754e66..33e8364 100644
--- a/rrompy/reduction_methods/trained_model/trained_model_reduced_basis.py
+++ b/rrompy/reduction_methods/trained_model/trained_model_reduced_basis.py
@@ -1,108 +1,115 @@
# 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 import TrainedModel
-from rrompy.utilities.base.types import Np1D, ListAny, paramList, sampList
+from rrompy.utilities.base.types import (Np1D, ListAny, paramVal, paramList,
+ sampList)
from rrompy.utilities.base import verbosityManager as vbMng, freepar as fp
-from rrompy.utilities.poly_fitting.polynomial import (
- hashIdxToDerivative as hashI)
from rrompy.utilities.numerical import (eigvalsNonlinearDense,
marginalizePolyList)
-from rrompy.utilities.exception_manager import RROMPyException
+from rrompy.utilities.expression import expressionEvaluator
+from rrompy.utilities.exception_manager import RROMPyException, RROMPyWarning
from rrompy.parameter import checkParameter, checkParameterList
from rrompy.sampling import emptySampleList
__all__ = ['TrainedModelReducedBasis']
class TrainedModelReducedBasis(TrainedModel):
"""
ROM approximant evaluation for RB approximant.
Attributes:
Data: dictionary with all that can be pickled.
"""
+ def assembleReducedModel(self, mu:paramVal):
+ mu = checkParameter(mu, self.data.npar)
+ if not hasattr(self, "lastSetupMu") or self.lastSetupMu != mu:
+ vbMng(self, "INIT", "Assembling reduced model for mu = {}."\
+ .format(mu), 17)
+ muEff = mu ** self.data.rescalingExp
+ self.data.ARBmu, self.data.bRBmu = 0., 0.
+ for thA, ARB in zip(self.data.thAs, self.data.ARBs):
+ self.data.ARBmu = (expressionEvaluator(thA[0], muEff) * ARB
+ + self.data.ARBmu)
+ for thb, bRB in zip(self.data.thbs, self.data.bRBs):
+ self.data.bRBmu = (expressionEvaluator(thb[0], muEff) * bRB
+ + self.data.bRBmu)
+ vbMng(self, "DEL", "Done assembling reduced model.", 17)
+ self.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",
"Computing RB solution at mu = {}.".format(mu), 12)
- ARBs, bRBs = self.data.ARBs, self.data.bRBs
self.uApproxReduced = emptySampleList()
- self.uApproxReduced.reset((ARBs[0].shape[0], len(mu)),
- self.data.projMat.dtype)
- mu0Eff = (self.data.mu0 ** self.data.rescalingExp).data
for i in range(len(mu)):
- vbMng(self, "INIT", "Assembling reduced model for mu = {}."\
- .format(mu[i]), 17)
- ARBmu = 1. * ARBs[0]
- bRBmu = 1. * bRBs[0]
- for j in range(1, max(len(ARBs), len(bRBs))):
- derIdx = hashI(j, self.data.npar)
- theta = np.prod(((mu[i] ** self.data.rescalingExp - mu0Eff)
- / self.data.scaleFactor) ** derIdx)
- if j < len(ARBs):
- ARBmu += theta * ARBs[j]
- if j < len(bRBs):
- bRBmu += theta * bRBs[j]
- vbMng(self, "DEL", "Done assembling reduced model.", 17)
+ self.assembleReducedModel(mu[i])
vbMng(self, "INIT",
"Solving reduced model for mu = {}.".format(mu[i]), 15)
- self.uApproxReduced[i] = np.linalg.solve(ARBmu, bRBmu)
+ uAppR = np.linalg.solve(self.data.ARBmu, self.data.bRBmu)
+ if i == 0:
+ #self.data.ARBs[0].shape[-1], len(mu)
+ self.uApproxReduced.reset((len(uAppR), len(mu)),
+ dtype = uAppR.dtype)
+ self.uApproxReduced[i] = uAppR
vbMng(self, "DEL", "Done solving reduced model.", 15)
vbMng(self, "DEL", "Done computing RB solution.", 12)
self.lastSolvedApproxReduced = mu
return self.uApproxReduced
def getPoles(self, marginalVals : ListAny = [fp], jSupp : int = 1,
**kwargs) -> Np1D:
"""
Obtain approximant poles.
Returns:
Numpy complex vector of poles.
"""
+ if not self.data.affinePoly:
+ RROMPyWarning(("Unable to compute approximate poles due "
+ "to parametric dependence (detected non-"
+ "polynomial). Change HFEngine.affinePoly to True "
+ "if necessary."))
+ return
if not hasattr(marginalVals, "__len__"): marginalVals = [marginalVals]
mVals = list(marginalVals)
try:
rDim = mVals.index(fp)
if rDim < len(mVals) - 1 and fp in mVals[rDim + 1 :]:
raise
except:
raise RROMPyException(("Exactly 1 'freepar' entry in "
"marginalVals must be provided."))
ARBs = self.data.ARBs
if self.data.npar > 1:
mVals[rDim] = self.data.mu0(rDim)
- mVals = (checkParameter(mVals) ** self.data.rescalingExp
- - self.data.mu0 ** self.data.rescalingExp)
- mVals = mVals.data.flatten()
+ mVals = checkParameter(mVals).data.flatten()
mVals[rDim] = fp
ARBs = marginalizePolyList(ARBs, mVals, "auto")
ev = eigvalsNonlinearDense(ARBs, jSupp = jSupp, **kwargs)
- return np.power(self.data.mu0(rDim) ** self.data.rescalingExp[rDim]
- + ev * self.data.scaleFactor[rDim],
- 1. / self.data.rescalingExp[rDim])
+ return np.sort(np.power(ev, 1. / self.data.rescalingExp[rDim]))
diff --git a/rrompy/sampling/base/pod_engine.py b/rrompy/sampling/base/pod_engine.py
index 316a70e..b3298a4 100644
--- a/rrompy/sampling/base/pod_engine.py
+++ b/rrompy/sampling/base/pod_engine.py
@@ -1,133 +1,134 @@
# 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 Np1D, Np2D, Tuple, HFEng, sampList
+from rrompy.utilities.numerical import dot
from rrompy.sampling import sampleList
__all__ = ['PODEngine']
class PODEngine:
"""
POD engine for general matrix orthogonalization.
"""
def __init__(self, HFEngine:HFEng):
self.HFEngine = HFEngine
def name(self) -> str:
return self.__class__.__name__
def __str__(self) -> str:
return self.name()
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
def GS(self, a:Np1D, Q:sampList, n : int = -1) -> Tuple[Np1D, Np1D, bool]:
"""
Compute 1 Gram-Schmidt step with given projector.
Args:
a: vector to be projected;
Q: orthogonal projection matrix;
n: number of columns of Q to be considered;
Returns:
Resulting normalized vector, coefficients of a wrt the updated
basis, whether computation is ill-conditioned.
"""
if n == -1:
n = Q.shape[1]
r = np.zeros((n + 1,), dtype = Q.dtype)
if n > 0:
Q = Q[: n]
for j in range(2): # twice is enough!
nu = self.HFEngine.innerProduct(a, Q)
- a = a - Q.dot(nu)
+ a = a - dot(Q, nu)
r[:-1] = r[:-1] + nu.flatten()
r[-1] = self.HFEngine.norm(a)
ill_cond = False
if np.isclose(np.abs(r[-1]) / np.linalg.norm(r), 0.):
ill_cond = True
r[-1] = 1.
a = a / r[-1]
return a, r, ill_cond
def generalizedQR(self, A:sampList, Q0 : sampList = None,
only_R : bool = False,
genTrials : int = 10) -> Tuple[sampList, Np2D]:
"""
Compute generalized QR decomposition of a matrix through Householder
method.
Args:
A: matrix to be decomposed;
Q0(optional): initial orthogonal guess for Q; defaults to random;
only_R(optional): whether to skip reconstruction of Q; defaults to
False.
genTrials(optional): number of trials of generation of linearly
independent vector; defaults to 10.
Returns:
Resulting (orthogonal and )upper-triangular factor(s).
"""
Nh, N = A.shape
B = copy(A)
V = copy(A)
R = np.zeros((N, N), dtype = A.dtype)
if Q0 is None:
Q = sampleList(np.zeros(A.shape, dtype = A.dtype)
+ np.random.randn(*(A.shape)))
else:
Q = copy(Q0)
for k in range(N):
a = B[k]
R[k, k] = self.HFEngine.norm(a)
if Q0 is None:
for _ in range(genTrials):
Q[k], _, illC = self.GS(np.random.randn(Nh), Q, k)
if not illC: break
else:
illC = False
if illC:
Q[k] = np.zeros(Nh, dtype = Q.dtype)
alpha = 0.
else:
alpha = self.HFEngine.innerProduct(a, Q[k])
if np.isclose(np.abs(alpha), 0.): s = 1.
else: s = - alpha / np.abs(alpha)
Q[k] = s * Q[k]
V[k], _, _ = self.GS(R[k, k] * Q[k] - a, Q, k)
J = np.arange(k + 1, N)
vtB = self.HFEngine.innerProduct(B[J], V[k])
B.data[:, J] -= 2 * np.outer(V[k], vtB)
if illC:
R[k, J] = 0.
else:
R[k, J] = self.HFEngine.innerProduct(B[J], Q[k])
B.data[:, J] -= np.outer(Q[k], R[k, J])
if only_R:
return R
for k in range(N - 1, -1, -1):
J = list(range(k, N))
vtQ = self.HFEngine.innerProduct(Q[J], V[k])
Q.data[:, J] -= 2 * np.outer(V[k], vtQ)
return Q, R
-
+
diff --git a/rrompy/sampling/base/sampling_engine_base.py b/rrompy/sampling/base/sampling_engine_base.py
index 19aa2bc..c61b3fd 100644
--- a/rrompy/sampling/base/sampling_engine_base.py
+++ b/rrompy/sampling/base/sampling_engine_base.py
@@ -1,189 +1,187 @@
# 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.utilities.base.types import (Np1D, HFEng, List, strLst, paramVal,
paramList, sampList)
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.utilities.exception_manager import RROMPyWarning
from rrompy.parameter import (emptyParameterList, checkParameter,
checkParameterList)
from rrompy.sampling import emptySampleList
__all__ = ['SamplingEngineBase']
class SamplingEngineBase:
"""HERE"""
def __init__(self, HFEngine:HFEng, verbosity : int = 10,
- timestamp : bool = True, allowRepeatedSamples : bool = True):
+ timestamp : bool = True):
self.verbosity = verbosity
self.timestamp = timestamp
- self.allowRepeatedSamples = allowRepeatedSamples
vbMng(self, "INIT",
"Initializing sampling engine of type {}.".format(self.name()),
10)
self.HFEngine = HFEngine
vbMng(self, "DEL", "Done initializing sampling engine.", 10)
def name(self) -> str:
return self.__class__.__name__
def __str__(self) -> str:
return self.name()
def __repr__(self) -> str:
return self.__str__() + " at " + hex(id(self))
def resetHistory(self):
self.samples = emptySampleList()
self.nsamples = 0
self.mus = emptyParameterList()
self._derIdxs = []
def popSample(self):
if hasattr(self, "nsamples") and self.nsamples > 1:
if self.samples.shape[1] > self.nsamples:
RROMPyWarning(("More than 'nsamples' memory allocated for "
"samples. Popping empty sample column."))
self.nsamples += 1
self.nsamples -= 1
self.samples.pop()
self.mus.pop()
else:
self.resetHistory()
def preallocateSamples(self, u:sampList, mu:paramVal, n:int):
self.samples.reset((u.shape[0], n), u.dtype)
self.samples[0] = u
mu = checkParameter(mu, self.HFEngine.npar)
self.mus.reset((n, self.HFEngine.npar))
self.mus[0] = mu[0]
@property
def HFEngine(self):
"""Value of HFEngine. Its assignment resets history."""
return self._HFEngine
@HFEngine.setter
def HFEngine(self, HFEngine):
self._HFEngine = HFEngine
self.resetHistory()
- def solveLS(self, mu : paramList = [], RHS : sampList = None,
- homogeneized : bool = False) -> sampList:
+ def solveLS(self, mu : paramList = [], RHS : sampList = None) -> sampList:
"""
Solve linear system.
Args:
mu: Parameter value.
Returns:
Solution of system.
"""
mu = checkParameterList(mu, self.HFEngine.npar)[0]
vbMng(self, "INIT", "Solving HF model for mu = {}.".format(mu), 15)
- u = self.HFEngine.solve(mu, RHS, homogeneized)
+ u = self.HFEngine.solve(mu, RHS)
vbMng(self, "DEL", "Done solving HF model.", 15)
return u
def plotSamples(self, warping : List[callable] = None, name : str = "u",
save : str = None, what : strLst = 'all',
saveFormat : str = "eps", saveDPI : int = 100,
show : bool = True, plotArgs : dict = {}, **figspecs):
"""
Do some nice plots of the samples.
Args:
warping(optional): Domain warping functions.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
show(optional): Whether to show figure. Defaults to True.
plotArgs(optional): Optional arguments for fen/pyplot.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
for j in range(self.nsamples):
self.HFEngine.plot(self.samples[j], warping,
"{}_{}".format(name, j), save, what, saveFormat,
saveDPI, show, plotArgs, **figspecs)
def outParaviewSamples(self, name : str = "u", folders : bool = True,
filename : str = "out", times : Np1D = None,
what : strLst = 'all', forceNewFile : bool = True,
filePW = None):
"""
Output samples to ParaView file.
Args:
name(optional): Base name to be used for data output.
folders(optional): Whether to split output in folders.
filename(optional): Name of output file.
times(optional): Timestamps.
what(optional): Which plots to do. If list, can contain 'MESH',
'ABS', 'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard
'ALL'. Defaults to 'ALL'.
forceNewFile(optional): Whether to create new output file.
filePW(optional): Fenics File entity (for time series).
"""
if times is None: times = [0.] * self.nsamples
for j in range(self.nsamples):
self.HFEngine.outParaview(self.samples[j],
name = "{}_{}".format(name, j),
filename = "{}_{}".format(filename, j),
time = times[j], what = what,
forceNewFile = forceNewFile,
folder = folders, filePW = filePW)
def outParaviewTimeDomainSamples(self, omegas : Np1D = None,
timeFinal : Np1D = None,
periodResolution : int = 20,
name : str = "u", folders : bool = True,
filename : str = "out",
forceNewFile : bool = True):
"""
Output samples to ParaView file, converted to time domain.
Args:
omegas(optional): frequencies.
timeFinal(optional): final time of simulation.
periodResolution(optional): number of time steps per period.
name(optional): Base name to be used for data output.
folders(optional): Whether to split output in folders.
filename(optional): Name of output file.
forceNewFile(optional): Whether to create new output file.
"""
if omegas is None: omegas = np.real(self.mus)
if not isinstance(timeFinal, (list, tuple,)):
timeFinal = [timeFinal] * self.nsamples
for j in range(self.nsamples):
self.HFEngine.outParaviewTimeDomain(self.samples[j],
omega = omegas[j],
timeFinal = timeFinal[j],
periodResolution = periodResolution,
name = "{}_{}".format(name, j),
filename = "{}_{}".format(filename, j),
forceNewFile = forceNewFile,
folder = folders)
diff --git a/rrompy/sampling/base/sampling_engine_base_pivoted.py b/rrompy/sampling/base/sampling_engine_base_pivoted.py
index 1d6c889..1d0a6da 100644
--- a/rrompy/sampling/base/sampling_engine_base_pivoted.py
+++ b/rrompy/sampling/base/sampling_engine_base_pivoted.py
@@ -1,208 +1,206 @@
# 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.utilities.base.types import (Np1D, HFEng, List, ListAny, strLst,
paramVal, paramList, sampList)
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.utilities.exception_manager import RROMPyWarning
from rrompy.parameter import (emptyParameterList, checkParameter,
checkParameterList)
from rrompy.sampling import emptySampleList
from .sampling_engine_base import SamplingEngineBase
__all__ = ['SamplingEngineBasePivoted']
class SamplingEngineBasePivoted(SamplingEngineBase):
"""HERE"""
def __init__(self, HFEngine:HFEng, directionPivot:ListAny,
- verbosity : int = 10, timestamp : bool = True,
- allowRepeatedSamples : bool = True):
+ verbosity : int = 10, timestamp : bool = True):
super().__init__(HFEngine, verbosity, timestamp)
self.directionPivot = directionPivot
self.HFEngineMarginalized = None
self.resetHistory()
@property
def directionMarginal(self):
return tuple([x for x in range(self.HFEngine.npar) \
if x not in self.directionPivot])
@property
def nPivot(self):
return len(self.directionPivot)
@property
def nMarginal(self):
return len(self.directionMarginal)
@property
def nsamplesTot(self):
return np.sum(self.nsamples)
def resetHistory(self, j : int = 1):
self.samples = [emptySampleList() for _ in range(j)]
self.nsamples = [0] * j
self.mus = [emptyParameterList() for _ in range(j)]
self._derIdxs = [[] for _ in range(j)]
def popSample(self, j:int):
if hasattr(self, "nsamples") and self.nsamples[j] > 1:
if self.samples[j].shape[1] > self.nsamples[j]:
RROMPyWarning(("More than 'nsamples' memory allocated for "
"samples. Popping empty sample column."))
self.nsamples[j] += 1
self.nsamples[j] -= 1
self.samples[j].pop()
self.mus[j].pop()
else:
self.resetHistory()
def preallocateSamples(self, u:sampList, mu:paramVal, n:int, j:int):
self.samples[j].reset((u.shape[0], n), u.dtype)
self.samples[j][0] = u
mu = checkParameter(mu, self.nPivot)
self.mus[j].reset((n, self.nPivot))
self.mus[j][0] = mu[0]
def coalesceSamples(self):
self.samplesCoalesced = emptySampleList()
self.samplesCoalesced.reset((self.samples[0].shape[0],
np.sum([samp.shape[1] \
for samp in self.samples])),
self.samples[0].dtype)
run_idx = 0
for samp in self.samples:
slen = samp.shape[1]
self.samplesCoalesced.data[:, run_idx : run_idx + slen] = samp.data
run_idx += slen
- def solveLS(self, mu : paramList = [], RHS : sampList = None,
- homogeneized : bool = False) -> sampList:
+ def solveLS(self, mu : paramList = [], RHS : sampList = None) -> sampList:
"""
Solve linear system.
Args:
mu: Parameter value.
Returns:
Solution of system.
"""
mu = checkParameterList(mu, self.nPivot)[0]
vbMng(self, "INIT",
- ("Solving HF model for mu = {} for marginal "
+ ("Solving HF model for muPivot = {} and muMarginal = "
"{}.").format(mu, self.HFEngineMarginalized.muFixed), 15)
- u = self.HFEngineMarginalized.solve(mu, RHS, homogeneized)
+ u = self.HFEngineMarginalized.solve(mu, RHS)
vbMng(self, "DEL", "Done solving HF model.", 15)
return u
def plotSamples(self, warping : List[callable] = None, name : str = "u",
save : str = None, what : strLst = 'all',
saveFormat : str = "eps", saveDPI : int = 100,
show : bool = True, plotArgs : dict = {}, **figspecs):
"""
Do some nice plots of the samples.
Args:
warping(optional): Domain warping functions.
name(optional): Name to be shown as title of the plots. Defaults to
'u'.
save(optional): Where to save plot(s). Defaults to None, i.e. no
saving.
what(optional): Which plots to do. If list, can contain 'ABS',
'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
Defaults to 'ALL'.
saveFormat(optional): Format for saved plot(s). Defaults to "eps".
saveDPI(optional): DPI for saved plot(s). Defaults to 100.
show(optional): Whether to show figure. Defaults to True.
plotArgs(optional): Optional arguments for fen/pyplot.
figspecs(optional key args): Optional arguments for matplotlib
figure creation.
"""
for i in range(len(self.nsamples)):
for j in range(self.nsamples[i]):
self.HFEngine.plot(self.samples[i][j], warping,
"{}_{}_{}".format(name, i, j), save, what,
saveFormat, saveDPI, show, plotArgs,
**figspecs)
def outParaviewSamples(self, name : str = "u", folders : bool = True,
filename : str = "out", times : Np1D = None,
what : strLst = 'all', forceNewFile : bool = True,
filePW = None):
"""
Output samples to ParaView file.
Args:
name(optional): Base name to be used for data output.
folders(optional): Whether to split output in folders.
filename(optional): Name of output file.
times(optional): Timestamps.
what(optional): Which plots to do. If list, can contain 'MESH',
'ABS', 'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard
'ALL'. Defaults to 'ALL'.
forceNewFile(optional): Whether to create new output file.
filePW(optional): Fenics File entity (for time series).
"""
if times is None: times = [[0.] * self.nsamples[i] \
for i in range(len(self.nsamples))]
for i in range(len(self.nsamples)):
for j in range(self.nsamples[i]):
self.HFEngine.outParaview(self.samples[i][j],
name = "{}_{}_{}".format(name, i, j),
filename = "{}_{}_{}".format(filename,
i, j),
time = times[i][j], what = what,
forceNewFile = forceNewFile,
folder = folders, filePW = filePW)
def outParaviewTimeDomainSamples(self, omegas : Np1D = None,
timeFinal : Np1D = None,
periodResolution : int = 20,
name : str = "u", folders : bool = True,
filename : str = "out",
forceNewFile : bool = True):
"""
Output samples to ParaView file, converted to time domain.
Args:
omegas(optional): frequencies.
timeFinal(optional): final time of simulation.
periodResolution(optional): number of time steps per period.
name(optional): Base name to be used for data output.
folders(optional): Whether to split output in folders.
filename(optional): Name of output file.
forceNewFile(optional): Whether to create new output file.
"""
if omegas is None: omegas = [[np.real(self.mus[i])] \
for i in range(len(self.nsamples))]
if not isinstance(timeFinal, (list, tuple,)):
timeFinal = [[timeFinal] * self.nsamples[i] \
for i in range(len(self.nsamples))]
for i in range(len(self.nsamples)):
for j in range(self.nsamples[i]):
self.HFEngine.outParaviewTimeDomain(self.samples[i][j],
omega = omegas[i][j],
timeFinal = timeFinal[i][j],
periodResolution = periodResolution,
name = "{}_{}_{}".format(name, i, j),
filename = "{}_{}_{}".format(filename,
i, j),
forceNewFile = forceNewFile,
folder = folders)
diff --git a/rrompy/sampling/pivoted/sampling_engine_pivoted.py b/rrompy/sampling/pivoted/sampling_engine_pivoted.py
index 2119cb4..c10d0dc 100644
--- a/rrompy/sampling/pivoted/sampling_engine_pivoted.py
+++ b/rrompy/sampling/pivoted/sampling_engine_pivoted.py
@@ -1,128 +1,123 @@
# 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.sampling.base.sampling_engine_base_pivoted import (
SamplingEngineBasePivoted)
from rrompy.hfengines.base import MarginalProxyEngine
from rrompy.utilities.base.types import Np1D, paramVal, paramList, sampList
from rrompy.utilities.base import verbosityManager as vbMng, freepar as fp
from rrompy.utilities.exception_manager import RROMPyException
-from rrompy.utilities.poly_fitting.polynomial import nextDerivativeIndices
+from rrompy.utilities.numerical import nextDerivativeIndices, dot
from rrompy.parameter import checkParameter, checkParameterList
from rrompy.sampling import sampleList
__all__ = ['SamplingEnginePivoted']
class SamplingEnginePivoted(SamplingEngineBasePivoted):
"""HERE"""
def preprocesssamples(self, idxs:Np1D, j:int) -> sampList:
if self.samples[j] is None or len(self.samples[j]) == 0: return
return self.samples[j](idxs)
def postprocessu(self, u:sampList, j:int,
overwrite : bool = False) -> Np1D:
return copy(u)
def postprocessuBulk(self, u:sampList, j:int) -> sampList:
return copy(u)
def lastSampleManagement(self, j:int):
pass
- def _getSampleConcurrence(self, mu:paramVal, j:int, previous:Np1D,
- homogeneized : bool = False) -> sampList:
+ def _getSampleConcurrence(self, mu:paramVal, j:int,
+ previous:Np1D) -> sampList:
if len(previous) >= len(self._derIdxs[j]):
self._derIdxs[j] += nextDerivativeIndices(
self._derIdxs[j], self.nPivot,
len(previous) + 1 - len(self._derIdxs[j]))
derIdx = self._derIdxs[j][len(previous)]
mu = checkParameter(mu, self.nPivot)
samplesOld = self.preprocesssamples(previous, j)
- RHS = self.HFEngineMarginalized.b(mu, derIdx,
- homogeneized = homogeneized)
+ RHS = self.HFEngineMarginalized.b(mu, derIdx)
for j, derP in enumerate(self._derIdxs[j][: len(previous)]):
diffP = [x - y for (x, y) in zip(derIdx, derP)]
if np.all([x >= 0 for x in diffP]):
- RHS -= self.HFEngineMarginalized.A(mu, diffP).dot(
- samplesOld[j])
- return self.solveLS(mu, RHS = RHS, homogeneized = homogeneized)
+ RHS -= dot(self.HFEngineMarginalized.A(mu, diffP),
+ samplesOld[j])
+ return self.solveLS(mu, RHS = RHS)
def nextSample(self, mu:paramVal, j:int, overwrite : bool = False,
- homogeneized : bool = False,
lastSample : bool = True) -> Np1D:
mu = checkParameter(mu, self.nPivot)
ns = self.nsamples[j]
muidxs = self.mus[j].findall(mu[0])
if len(muidxs) > 0:
- u = self._getSampleConcurrence(mu, j, np.sort(muidxs),
- homogeneized)
+ u = self._getSampleConcurrence(mu, j, np.sort(muidxs))
else:
- u = self.solveLS(mu, homogeneized = homogeneized)
+ u = self.solveLS(mu)
u = self.postprocessu(u, j, overwrite = overwrite)
if overwrite:
self.samples[j][ns] = u
self.mus[j][ns] = mu[0]
else:
if ns == 0:
self.samples[j] = sampleList(u)
else:
self.samples[j].append(u)
self.mus[j].append(mu)
self.nsamples[j] += 1
if lastSample: self.lastSampleManagement(j)
return u
- def iterSample(self, mus:paramList, musM:paramList,
- homogeneized : bool = False) -> sampList:
+ def iterSample(self, mus:paramList, musM:paramList) -> sampList:
mus = checkParameterList(mus, self.nPivot)[0]
musM = checkParameterList(musM, self.nMarginal)[0]
vbMng(self, "INIT", "Starting sampling iterations.", 5)
n = len(mus)
m = len(musM)
if n <= 0:
raise RROMPyException("Number of samples must be positive.")
if m <= 0:
raise RROMPyException(("Number of marginal samples must be "
"positive."))
+ repeatedSamples = len(mus.unique()) != n
for j in range(m):
muMEff = [fp] * self.HFEngine.npar
for k, x in enumerate(self.directionMarginal):
muMEff[x] = musM(j, k)
self.HFEngineMarginalized = MarginalProxyEngine(self.HFEngine,
list(muMEff))
- if self.allowRepeatedSamples:
+ if repeatedSamples:
for k in range(n):
vbMng(self, "MAIN",
"Computing sample {} / {} for marginal {} / {}."\
.format(k + 1, n, j, m), 10)
self.nextSample(mus[k], j, overwrite = (k > 0),
- homogeneized = homogeneized,
lastSample = (n == k + 1))
if n > 1 and k == 0:
self.preallocateSamples(self.samples[j][0], mus[0],
n, j)
else:
- self.samples[j] = self.postprocessuBulk(self.solveLS(mus,
- homogeneized = homogeneized), j)
+ self.samples[j] = self.postprocessuBulk(self.solveLS(mus), j)
self.mus[j] = copy(mus)
self.nsamples[j] = n
vbMng(self, "DEL", "Finished sampling iterations.", 5)
return self.samples[j]
diff --git a/rrompy/sampling/pivoted/sampling_engine_pivoted_pod.py b/rrompy/sampling/pivoted/sampling_engine_pivoted_pod.py
index af32fb3..32c9a4c 100644
--- a/rrompy/sampling/pivoted/sampling_engine_pivoted_pod.py
+++ b/rrompy/sampling/pivoted/sampling_engine_pivoted_pod.py
@@ -1,114 +1,114 @@
# 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.sampling.base.pod_engine import PODEngine
from .sampling_engine_pivoted import SamplingEnginePivoted
from rrompy.utilities.base.types import Np1D, paramVal, sampList
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.sampling import sampleList, emptySampleList
__all__ = ['SamplingEnginePivotedPOD']
class SamplingEnginePivotedPOD(SamplingEnginePivoted):
"""HERE"""
def resetHistory(self, j : int = 1):
super().resetHistory(j)
self.samples_full = [None] * j
self.RPOD = [None] * j
def popSample(self, j:int):
if hasattr(self, "nsamples") and self.nsamples[j] > 1:
self.RPOD[j] = self.RPOD[j][: -1, : -1]
self.samples_full[j].pop()
super().popSample(j)
def coalesceSamples(self, tol : float = 1e-12):
super().coalesceSamples()
self.samplesCoalesced, RPODC = (
self.PODEngine.generalizedQR(self.samplesCoalesced))
self.RPODCoalesced = np.zeros((self.samplesCoalesced.shape[1],
self.samplesCoalesced.shape[1]),
dtype = self.RPOD[0].dtype)
self.samples_fullCoalesced = emptySampleList()
self.samples_fullCoalesced.reset((self.samples_full[0].shape[0],
self.samplesCoalesced.shape[1]),
self.samples_full[0].dtype)
ci = 0
for j, (Rloc, samp) in enumerate(zip(self.RPOD, self.samples_full)):
ri = 0
Rheg = Rloc.shape[1]
for k, Rloc2 in enumerate(self.RPOD[: j + 1]):
Rlen = Rloc2.shape[1]
self.RPODCoalesced[ri : ri + Rlen, ci : ci + Rheg] = (
RPODC[ri : ri + Rlen, ci : ci + Rheg].dot(Rloc))
ri += Rlen
self.samples_fullCoalesced.data[:, ci : ci + Rheg] = samp.data
ci += Rheg
RCdiag = np.abs(np.diag(self.RPODCoalesced))
RCdiag /= RCdiag[0]
ntrunc = np.nonzero(RCdiag < tol)[0]
if len(ntrunc) == 0: return
self.samplesCoalesced.data = self.samplesCoalesced.data[:, : ntrunc[0]]
self.RPODCoalesced = self.RPODCoalesced[: ntrunc[0], :]
@property
def HFEngine(self):
"""Value of HFEngine. Its assignment resets history."""
return self._HFEngine
@HFEngine.setter
def HFEngine(self, HFEngine):
self._HFEngine = HFEngine
self.resetHistory()
self.PODEngine = PODEngine(self._HFEngine)
def preprocesssamples(self, idxs:Np1D, j:int) -> sampList:
if self.samples_full[j] is None or len(self.samples_full[j]) == 0:
return
return self.samples_full[j](idxs)
def postprocessu(self, u:sampList, j:int,
overwrite : bool = False) -> Np1D:
ns = self.nsamples[j]
if overwrite:
self.samples_full[j][ns] = copy(u)
else:
if ns == 0:
self.samples_full[j] = sampleList(u)
else:
self.samples_full[j].append(u)
return u
def postprocessuBulk(self, u:sampList, j:int) -> sampList:
self.samples_full[j] = copy(u)
vbMng(self, "INIT",
- "Starting orthogonalization for marginal {}.".format(j), 40)
+ "Starting orthogonalization for marginal no {}.".format(j), 40)
u, self.RPOD[j] = self.PODEngine.generalizedQR(self.samples_full[j])
vbMng(self, "DEL", "Done orthogonalizing.", 40)
return u
def lastSampleManagement(self, j:int):
self.samples[j] = self.postprocessuBulk(self.samples_full[j], j)
def preallocateSamples(self, u:Np1D, mu:paramVal, n:int, j:int):
super().preallocateSamples(u, mu, n, j)
self.samples_full[j].reset((u.shape[0], n), u.dtype)
self.samples_full[j][0] = u
diff --git a/rrompy/sampling/sample_list.py b/rrompy/sampling/sample_list.py
index 79dc269..75ac132 100644
--- a/rrompy/sampling/sample_list.py
+++ b/rrompy/sampling/sample_list.py
@@ -1,222 +1,226 @@
# 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.utilities.exception_manager import RROMPyAssert
from rrompy.utilities.base.types import Np1D, List
+from rrompy.utilities.numerical import dot
__all__ = ['emptySampleList', 'sampleList']
def emptySampleList():
return sampleList(np.empty((0, 0)))
class sampleList:
"""HERE"""
def __init__(self, data:List[Np1D], lengthCheck : int = None,
deep : bool = True):
if isinstance(data, (self.__class__,)):
data = data.data
if isinstance(data, (np.ndarray,)):
self.data = copy(data) if deep else data
if self.data.ndim <= 1:
self.data.shape = (self.data.shape[0], 1)
else:
if not isinstance(data, (list,)):
data = [data]
self.data = np.empty((len(data[0]), len(data)),
dtype = data[0].dtype)
for j, par in enumerate(data):
self[j] = copy(data[j]) if deep else data[j]
if j == 0 and lengthCheck is None:
lengthCheck = self.shape[0]
RROMPyAssert(len(data[j]), lengthCheck, "Number of parameters")
def __len__(self):
return self.shape[1]
def __str__(self):
return str(self.data)
def __repr__(self):
return repr(self.data)
@property
def shape(self):
return self.data.shape
@property
def re(self):
return sampleList(np.real(self.data))
@property
def im(self):
return sampleList(np.imag(self.data))
@property
def abs(self):
return sampleList(np.abs(self.data))
@property
def angle(self):
return sampleList(np.angle(self.data))
def conj(self):
return sampleList(np.conj(self.data))
@property
def T(self):
return sampleList(self.data.T)
@property
def H(self):
return sampleList(self.data.T.conj())
@property
def dtype(self):
return self.data.dtype
@dtype.setter
def dtype(self, dtype):
self.data.dtype = dtype
def __getitem__(self, key):
return self.data[:, key]
def __call__(self, key):
return sampleList(self.data[:, key])
def __setitem__(self, key, value):
if isinstance(value, self.__class__):
value = value.data
if isinstance(key, (tuple, list,)):
RROMPyAssert(len(key), len(value), "Slice length")
for k, val in zip(key, value):
self[k] = val
else:
self.data[:, key] = value.flatten()
def __iter__(self):
return self.data.T.__iter__()
def __eq__(self, other):
if not hasattr(other, "shape") or self.shape != other.shape:
return False
if isinstance(other, self.__class__):
fac = other.data
else:
fac = other
return np.allclose(self.data, fac)
def __ne__(self, other):
return not self == other
def __copy__(self):
return sampleList(self.data)
def __deepcopy__(self, memo):
return sampleList(copy(self.data, memo))
def __add__(self, other):
if isinstance(other, self.__class__):
RROMPyAssert(self.shape, other.shape, "Sample shape")
fac = other.data
else:
fac = other
return sampleList(self.data + fac)
def __iadd__(self, other):
self.data = (self + other).data
return self
def __sub__(self, other):
if isinstance(other, self.__class__):
RROMPyAssert(self.shape, other.shape, "Sample shape")
fac = other.data
else:
fac = other
return sampleList(self.data - fac)
def __isub__(self, other):
self.data = (self - other).data
return self
def __mul__(self, other):
if isinstance(other, self.__class__):
RROMPyAssert(self.shape, other.shape, "Sample shape")
fac = other.data
else:
fac = other
return sampleList(self.data * fac)
def __imul__(self, other):
self.data = (self * other).data
return self
def __truediv__(self, other):
if isinstance(other, self.__class__):
RROMPyAssert(self.shape, other.shape, "Sample shape")
fac = other.data
else:
fac = other
return sampleList(self.data / fac)
def __idiv__(self, other):
self.data = (self / other).data
return self
def __pow__(self, other):
if isinstance(other, self.__class__):
RROMPyAssert(self.shape, other.shape, "Sample shape")
fac = other.data
else:
fac = other
return sampleList(np.power(self.data, fac))
def __ipow__(self, other):
self.data = (self ** other).data
return self
def __neg__(self):
return sampleList(- self.data)
def __pos__(self):
return sampleList(self.data)
- def reset(self, size, dtype = np.float):
+ def reset(self, size, dtype = np.complex):
self.data = np.empty(size, dtype = dtype)
self.data[:] = np.nan
def append(self, items):
if isinstance(items, self.__class__):
fac = items.data
else:
fac = np.array(items, ndmin = 2)
self.data = np.append(self.data, fac, axis = 1)
def pop(self, idx = -1):
self.data = np.delete(self.data, idx, axis = 1)
def dot(self, other, sampleListOut : bool = True):
if isinstance(other, self.__class__):
other = other.data
- prod = self.data.dot(other)
+ try:
+ prod = dot(self.data, other)
+ except:
+ prod = dot(other.T, self.data.T).T
if sampleListOut:
prod = sampleList(prod)
return prod
diff --git a/rrompy/sampling/standard/sampling_engine_standard.py b/rrompy/sampling/standard/sampling_engine_standard.py
index 50ab0f7..3cfc21b 100644
--- a/rrompy/sampling/standard/sampling_engine_standard.py
+++ b/rrompy/sampling/standard/sampling_engine_standard.py
@@ -1,112 +1,106 @@
# 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.sampling.base.sampling_engine_base import SamplingEngineBase
from rrompy.utilities.base.types import Np1D, paramVal, paramList, sampList
from rrompy.utilities.base import verbosityManager as vbMng
from rrompy.utilities.exception_manager import RROMPyException
-from rrompy.utilities.poly_fitting.polynomial import nextDerivativeIndices
+from rrompy.utilities.numerical import nextDerivativeIndices, dot
from rrompy.parameter import checkParameter, checkParameterList
from rrompy.sampling import sampleList
__all__ = ['SamplingEngineStandard']
class SamplingEngineStandard(SamplingEngineBase):
"""HERE"""
def preprocesssamples(self, idxs:Np1D) -> sampList:
if self.samples is None or len(self.samples) == 0: return
return self.samples(idxs)
def postprocessu(self, u:sampList, overwrite : bool = False) -> Np1D:
return copy(u)
def postprocessuBulk(self, u:sampList) -> sampList:
return copy(u)
def lastSampleManagement(self):
pass
- def _getSampleConcurrence(self, mu:paramVal, previous:Np1D,
- homogeneized : bool = False) -> sampList:
+ def _getSampleConcurrence(self, mu:paramVal, previous:Np1D) -> sampList:
if len(previous) >= len(self._derIdxs):
self._derIdxs += nextDerivativeIndices(self._derIdxs,
self.HFEngine.npar,
len(previous) + 1 - len(self._derIdxs))
derIdx = self._derIdxs[len(previous)]
mu = checkParameter(mu, self.HFEngine.npar)
samplesOld = self.preprocesssamples(previous)
- RHS = self.HFEngine.b(mu, derIdx, homogeneized = homogeneized)
+ RHS = self.HFEngine.b(mu, derIdx)
for j, derP in enumerate(self._derIdxs[: len(previous)]):
diffP = [x - y for (x, y) in zip(derIdx, derP)]
if np.all([x >= 0 for x in diffP]):
- RHS -= self.HFEngine.A(mu, diffP).dot(samplesOld[j])
- return self.solveLS(mu, RHS = RHS, homogeneized = homogeneized)
+ RHS -= dot(self.HFEngine.A(mu, diffP), samplesOld[j])
+ return self.solveLS(mu, RHS = RHS)
def nextSample(self, mu : paramVal = [], overwrite : bool = False,
- homogeneized : bool = False,
lastSample : bool = True) -> Np1D:
mu = checkParameter(mu, self.HFEngine.npar)
ns = self.nsamples
muidxs = self.mus.findall(mu[0])
if len(muidxs) > 0:
- u = self._getSampleConcurrence(mu, np.sort(muidxs), homogeneized)
+ u = self._getSampleConcurrence(mu, np.sort(muidxs))
else:
- u = self.solveLS(mu, homogeneized = homogeneized)
+ u = self.solveLS(mu)
u = self.postprocessu(u, overwrite = overwrite)
if overwrite:
self.samples[ns] = u
self.mus[ns] = mu[0]
else:
if ns == 0:
self.samples = sampleList(u)
else:
self.samples.append(u)
self.mus.append(mu)
self.nsamples += 1
if lastSample: self.lastSampleManagement()
return u
- def iterSample(self, mus:paramList,
- homogeneized : bool = False) -> sampList:
+ def iterSample(self, mus:paramList) -> sampList:
mus = checkParameterList(mus, self.HFEngine.npar)[0]
vbMng(self, "INIT", "Starting sampling iterations.", 5)
n = len(mus)
if n <= 0:
raise RROMPyException(("Number of samples must be positive."))
self.resetHistory()
-
- if self.allowRepeatedSamples:
+ if len(mus.unique()) != n:
for j in range(n):
vbMng(self, "MAIN",
"Computing sample {} / {}.".format(j + 1, n), 7)
self.nextSample(mus[j], overwrite = (j > 0),
- homogeneized = homogeneized,
lastSample = (n == j + 1))
if n > 1 and j == 0:
self.preallocateSamples(self.samples[0], mus[0], n)
else:
- self.samples = self.postprocessuBulk(self.solveLS(mus,
- homogeneized = homogeneized))
+ self.samples = self.postprocessuBulk(self.solveLS(mus))
self.mus = copy(mus)
self.nsamples = n
vbMng(self, "DEL", "Finished sampling iterations.", 5)
return self.samples
diff --git a/rrompy/solver/fenics/fenics_la.py b/rrompy/solver/fenics/fenics_la.py
index d2bace5..ba66db7 100644
--- a/rrompy/solver/fenics/fenics_la.py
+++ b/rrompy/solver/fenics/fenics_la.py
@@ -1,45 +1,51 @@
# 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 numpy import array, complex
from scipy.sparse import csr_matrix
import fenics as fen
from rrompy.utilities.base.types import Np2D, FenBC, FenExpr
__all__ = ['fenics2Sparse', 'fenics2Vector']
def fenics2Sparse(expr:FenExpr, formCompPars : dict = {}, DBC : FenBC = None,
BCType : int = -1, dtype = complex) -> Np2D:
assembled = fen.assemble(expr, form_compiler_parameters = formCompPars)
+ loglvl = fen.get_log_level()
+ fen.set_log_level(40)
if BCType == 0:
DBC.zero(assembled)
elif BCType >= 1:
DBC.apply(assembled)
+ fen.set_log_level(loglvl)
emat = fen.as_backend_type(assembled).mat()
er, ec, ev = emat.getValuesCSR()
return csr_matrix((ev, ec, er), shape = emat.size, dtype = dtype)
def fenics2Vector(expr:FenExpr, formCompPars : dict = {}, DBC : FenBC = None,
BCType : int = -1, dtype = complex) -> Np2D:
assembled = fen.assemble(expr, form_compiler_parameters = formCompPars)
+ loglvl = fen.get_log_level()
+ fen.set_log_level(40)
if BCType == 0:
DBC.zero(assembled)
elif BCType >= 1:
DBC.apply(assembled)
+ fen.set_log_level(loglvl)
return array(assembled[:], dtype = dtype)
diff --git a/rrompy/solver/fenics/fenics_norms.py b/rrompy/solver/fenics/fenics_norms.py
index 5c5d7c7..8f53414 100644
--- a/rrompy/solver/fenics/fenics_norms.py
+++ b/rrompy/solver/fenics/fenics_norms.py
@@ -1,89 +1,88 @@
# 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 fenics as fen
from rrompy.utilities.base.types import Np2D, FenFunc, DictAny, FenFuncSpace
from rrompy.solver.norm_utilities import (Np2DLikeEye, Np2DLikeInv,
Np2DLikeInvLowRank)
from .fenics_la import fenics2Sparse
__all__ = ['L2NormMatrix', 'L2InverseNormMatrix', 'H1NormMatrix',
'Hminus1NormMatrix', 'elasticNormMatrix', 'elasticDualNormMatrix']
def L2NormMatrix(V:FenFuncSpace, r_ : FenFunc = 1.) -> Np2D:
u = fen.TrialFunction(V)
v = fen.TestFunction(V)
return fenics2Sparse(r_ * fen.dot(u, v) * fen.dx)
def L2InverseNormMatrix(V:FenFuncSpace, r_ : FenFunc = 1.,
solverType : str = "SPSOLVE",
solverArgs : DictAny = {}, compressRank : int = None,
compressOversampling : int = 10,
compressSeed : int = 420) -> Np2D:
+ L2Mat = L2NormMatrix(V, r_)
if compressRank is None:
- return Np2DLikeInv(L2NormMatrix(V, r_), Np2DLikeEye(), solverType,
+ return Np2DLikeInv(L2Mat, Np2DLikeEye(L2Mat.shape[0]), solverType,
solverArgs)
- return Np2DLikeInvLowRank(L2NormMatrix(V, r_), Np2DLikeEye(), solverType,
+ return Np2DLikeInvLowRank(L2Mat, Np2DLikeEye(L2Mat.shape[0]), solverType,
solverArgs, compressRank, compressOversampling,
compressSeed)
def H1NormMatrix(V:FenFuncSpace, w : float = 0., r_ : FenFunc = 1.,
a_ : FenFunc = 1.) -> Np2D:
u = fen.TrialFunction(V)
v = fen.TestFunction(V)
return fenics2Sparse((w * r_ * fen.dot(u, v)
+ fen.dot(a_ * fen.grad(u), fen.grad(v))) * fen.dx)
def Hminus1NormMatrix(V:FenFuncSpace, w : float = 0., r_ : FenFunc = 1.,
a_ : FenFunc = 1., solverType : str = "SPSOLVE",
solverArgs : DictAny = {}, compressRank : int = None,
compressOversampling : int = 10,
compressSeed : int = 420, duality : bool = True) -> Np2D:
- identity = L2NormMatrix(V, r_) if duality else Np2DLikeEye()
+ H1Mat = H1NormMatrix(V, w, r_, a_)
+ identity = L2NormMatrix(V, r_) if duality else Np2DLikeEye(H1Mat.shape[0])
if compressRank is None:
- return Np2DLikeInv(H1NormMatrix(V, w, r_, a_), identity, solverType,
- solverArgs)
- return Np2DLikeInvLowRank(H1NormMatrix(V, w, r_, a_), identity, solverType,
- solverArgs, compressRank, compressOversampling,
- compressSeed)
+ return Np2DLikeInv(H1Mat, identity, solverType, solverArgs)
+ return Np2DLikeInvLowRank(H1Mat, identity, solverType, solverArgs,
+ compressRank, compressOversampling, compressSeed)
def elasticNormMatrix(V:FenFuncSpace, l_:FenFunc, m_:FenFunc,
w : float = 0., r_ : FenFunc = 1.) -> Np2D:
u = fen.TrialFunction(V)
v = fen.TestFunction(V)
epsilon = lambda f: 0.5 * (fen.grad(f) + fen.nabla_grad(f))
sigma = (l_ * fen.div(u) * fen.Identity(u.geometric_dimension())
+ 2. * m_ * epsilon(u))
return fenics2Sparse((w * r_ * fen.dot(u, v)
+ fen.inner(sigma, epsilon(v))) * fen.dx)
def elasticDualNormMatrix(V:FenFuncSpace, l_:FenFunc, m_:FenFunc,
w : float = 0., solverType : str = "SPSOLVE",
solverArgs : DictAny = {}, r_ : FenFunc = 1.,
compressRank : int = None,
compressOversampling : int = 10,
compressSeed : int = 420,
duality : bool = True) -> Np2D:
- identity = L2NormMatrix(V, r_) if duality else Np2DLikeEye()
+ elMat = elasticNormMatrix(V, l_, m_, w, r_)
+ identity = L2NormMatrix(V, r_) if duality else Np2DLikeEye(elMat.shape[0])
if compressRank is None:
- return Np2DLikeInv(elasticNormMatrix(V, l_, m_, w, r_), identity,
- solverType, solverArgs)
- return Np2DLikeInvLowRank(elasticNormMatrix(V, l_, m_, w, r_), identity,
- solverType, solverArgs, compressRank,
- compressOversampling, compressSeed)
+ return Np2DLikeInv(elMat, identity, solverType, solverArgs)
+ return Np2DLikeInvLowRank(elMat, identity, solverType, solverArgs,
+ compressRank, compressOversampling, compressSeed)
diff --git a/rrompy/solver/norm_utilities.py b/rrompy/solver/norm_utilities.py
index 96b151f..244ec67 100644
--- a/rrompy/solver/norm_utilities.py
+++ b/rrompy/solver/norm_utilities.py
@@ -1,89 +1,100 @@
# 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 abc import abstractmethod
import numpy as np
from copy import deepcopy as copy
from rrompy.utilities.base.types import Np1D, Np2D, DictAny
+from rrompy.utilities.numerical import dot as tdot, solve as tsolve
from rrompy.solver.linear_solver import setupSolver
from rrompy.utilities.exception_manager import RROMPyException
__all__ = ['Np2DLike', 'Np2DLikeEye', 'Np2DLikeInv', 'Np2DLikeInvLowRank',
'normEngine']
@abstractmethod
class Np2DLike:
def dot(self, u:Np2D) -> Np2D:
pass
class Np2DLikeEye(Np2DLike):
+ def __init__(self, n:int):
+ self.n = n
@property
def T(self):
return self
-
+ @property
+ def shape(self):
+ return (self.n, self.n)
def conj(self):
return self
-
def dot(self, u:Np2D) -> Np2D:
return u
class Np2DLikeInv(Np2DLike):
def __init__(self, K:Np2D, M:Np2D, solverType:str, solverArgs:DictAny):
self.K, self.M, self.MH = K, M, M.T.conj()
try:
self.solver, self.solverArgs = setupSolver(solverType, solverArgs)
except:
self.solver, self.solverArgs = solverType, solverArgs
def dot(self, u:Np2D) -> Np2D:
- return self.MH.dot(self.solver(self.K, self.M.dot(u),
- self.solverArgs)).reshape(u.shape)
+ return tdot(self.MH, tsolve(self.K, tdot(self.M, u), self.solver,
+ self.solverArgs)).reshape(u.shape)
+ @property
+ def shape(self):
+ return (self.MH.shape[0], self.M.shape[1])
class Np2DLikeInvLowRank(Np2DLike):
def __init__(self, K:Np2D, M:Np2D, solverType:str, solverArgs:DictAny,
rank:int, oversampling : int = 10, seed : int = 420):
- if rank > M.shape[1]:
+ sizeO = K.shape[1] if hasattr(K, "shape") else M.shape[1]
+ if rank > sizeO:
raise RROMPyException(("Cannot select compressed rank larger than "
"original size."))
if oversampling < 0:
raise RROMPyException("Oversampling parameter must be positive.")
HF = Np2DLikeInv(K, M, solverType, solverArgs)
np.random.seed(seed)
- xs = np.random.randn(M.shape[1], rank + oversampling)
+ xs = np.random.randn(sizeO, rank + oversampling)
samples = HF.dot(xs)
Q, _ = np.linalg.qr(samples, mode = "reduced")
R = HF.dot(Q).T.conj() # assuming HF (i.e. K) hermitian...
- U, s, Vh = np.linalg.svd(R)
+ U, s, Vh = np.linalg.svd(R, full_matrices = False)
self.L = Q.dot(U[:, : rank]) * s[: rank]
self.R = Vh[: rank, :]
def dot(self, u:Np2D) -> Np2D:
- return self.L.dot(self.R.dot(u)).reshape(u.shape)
+ return tdot(self.L, tdot(self.R, u)).reshape(u.shape)
+ @property
+ def shape(self):
+ return (self.L.shape[0], self.R.shape[1])
class normEngine:
def __init__(self, energyNormMatrix:Np2D):
self.energyNormMatrix = copy(energyNormMatrix)
def innerProduct(self, u:Np2D, v:Np2D, onlyDiag : bool = False) -> Np2D:
if not isinstance(u, (np.ndarray,)): u = u.data
if not isinstance(v, (np.ndarray,)): v = v.data
if onlyDiag:
- return np.sum(self.energyNormMatrix.dot(u) * v.conj(), axis = 0)
- return v.T.conj().dot(self.energyNormMatrix.dot(u))
+ return np.sum(tdot(self.energyNormMatrix, u) * v.conj(), axis = 0)
+ return tdot(tdot(self.energyNormMatrix, u).T, v.conj()).T
def norm(self, u:Np2D) -> Np1D:
return np.power(np.abs(self.innerProduct(u, u, onlyDiag = True)), .5)
diff --git a/rrompy/solver/scipy/scipy_tensorize.py b/rrompy/solver/scipy/scipy_tensorize.py
deleted file mode 100644
index 3eaa14d..0000000
--- a/rrompy/solver/scipy/scipy_tensorize.py
+++ /dev/null
@@ -1,51 +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
-import scipy.sparse as scsp
-from rrompy.utilities.base.types import Np1D, Np2D, List
-from rrompy.utilities.exception_manager import RROMPyException
-
-__all__ = ['tensorizeLS', 'detensorizeLS']
-
-def tensorizeLS(As : List[Np2D] = [], bs : List[Np1D] = [],
- AFormat : str = "csr"):
- if len(As) > 0:
- A = scsp.block_diag(As, format = AFormat)
- else:
- A = None
- if len(bs) > 0:
- b = np.concatenate(bs, axis = None)
- else:
- b = None
- return A, b
-
-def detensorizeLS(x:Np1D, n : int = 0, sizes : List[int] = []):
- if n > 0 and len(sizes) > 0 and n != len(sizes):
- raise RROMPyException("Specified n and sizes are inconsistent.")
- if n == 0 and len(sizes) == 0:
- raise RROMPyException("Must specify either n or sizes.")
- if len(sizes) == 0:
- sizes = [len(x) // n] * n
- if n * sizes[0] != len(x):
- raise RROMPyException(("Number of chunks must divide vector "
- "length."))
- n = len(sizes)
- sEnd = np.cumsum(sizes)
- sStart = sEnd - sizes[0]
- return [x[sStart[j] : sEnd[j]] for j in range(n)]
diff --git a/rrompy/solver/scipy/__init__.py b/rrompy/utilities/expression/__init__.py
similarity index 60%
copy from rrompy/solver/scipy/__init__.py
copy to rrompy/utilities/expression/__init__.py
index c126e95..b22ee8d 100644
--- a/rrompy/solver/scipy/__init__.py
+++ b/rrompy/utilities/expression/__init__.py
@@ -1,25 +1,34 @@
# 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 .scipy_tensorize import tensorizeLS, detensorizeLS
+from .keys import (expressionKeysUnary, expressionKeysUnaryParam,
+ expressionKeysBinary, expressionKeysBinaryParam)
+from .expression_evaluator import expressionEvaluator
+from .monomial_creator import createMonomial, createMonomialList
__all__ = [
- 'tensorizeLS',
- 'detensorizeLS'
+ 'expressionKeysUnary',
+ 'expressionKeysUnaryParam',
+ 'expressionKeysBinary',
+ 'expressionKeysBinaryParam',
+ 'expressionEvaluator',
+ 'createMonomial',
+ 'createMonomialList'
]
+
diff --git a/rrompy/utilities/expression/expression_evaluator.py b/rrompy/utilities/expression/expression_evaluator.py
new file mode 100644
index 0000000..d95d85e
--- /dev/null
+++ b/rrompy/utilities/expression/expression_evaluator.py
@@ -0,0 +1,123 @@
+# 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 numbers import Number
+import numpy as np
+from copy import deepcopy as copy
+from .keys import (expressionKeysUnary, expressionKeysUnaryParam,
+ expressionKeysBinary, expressionKeysBinaryParam)
+from rrompy.utilities.base.types import Tuple, TupleAny, paramList
+from rrompy.utilities.exception_manager import RROMPyException
+from rrompy.parameter import parameterList, checkParameterList
+
+__all__ = ["expressionEvaluator"]
+
+def manageNotExpression(expr):
+ if isinstance(expr, (str,)) and expr == "x": return None
+ elif isinstance(expr, (Number, parameterList,)): return expr
+ else:
+ try:
+ return np.array(expr)
+ except:
+ raise RROMPyException(("Expression '{}' not "
+ "recognized.").format(expr))
+
+def expressionEvaluator(expr:TupleAny, x:paramList,
+ force_shape : Tuple[int] = None):
+ if not isinstance(x, (parameterList,)): x = checkParameterList(x)[0]
+ exprSimp = [None] * len(expr)
+ for j, ex in enumerate(expr):
+ if isinstance(ex, (tuple,)):
+ exprSimp[j] = expressionEvaluator(ex, x)
+ else:
+ exprSimp[j] = ex
+ z, zc = None, None
+ pile, pilePars = [], []
+ j = -1
+ while j + 1 < len(exprSimp):
+ j += 1
+ ex = exprSimp[j]
+ if not isinstance(ex, (np.ndarray, parameterList, list, tuple,)):
+ if ex in expressionKeysUnary.keys():
+ pile = pile + [ex]
+ pilePars = pilePars + [None]
+ continue
+ if ex in expressionKeysUnaryParam.keys():
+ pile = pile + [ex]
+ j += 1
+ if j >= len(exprSimp) or not isinstance(exprSimp[j], (dict,)):
+ raise RROMPyException(("Parameters missing for unary "
+ "operand '{}'.").format(ex))
+ pilePars = pilePars + [exprSimp[j]]
+ continue
+ if ex in expressionKeysBinary.keys():
+ if len(pile) > 0 or z is None or zc is not None:
+ raise RROMPyException(("Binary operand '{}' must follow "
+ "numerical expression.").format(ex))
+ zc = copy(z)
+ pile = pile + [ex]
+ pilePars = pilePars + [None]
+ continue
+ if ex in expressionKeysBinaryParam.keys():
+ if len(pile) > 0 or z is None or zc is not None:
+ raise RROMPyException(("Binary operand '{}' must follow "
+ "numerical expression.").format(ex))
+ zc = copy(z)
+ pile = pile + [ex]
+ j += 1
+ if j >= len(exprSimp) or not isinstance(exprSimp[j], (dict,)):
+ raise RROMPyException(("Parameters missing for binary "
+ "operand '{}'.").format(ex))
+ pilePars = pilePars + [exprSimp[j]]
+ continue
+ z = manageNotExpression(ex)
+ if z is None: z = copy(x)
+ if len(pile) > 0:
+ for pl, plp in zip(pile[::-1], pilePars[::-1]):
+ if zc is None:
+ if plp is None:
+ z = expressionKeysUnary[pl](z)
+ else:
+ z = expressionKeysUnaryParam[pl](z, plp)
+ else:
+ if plp is None:
+ z = expressionKeysBinary[pl](zc, z)
+ else:
+ z = expressionKeysBinaryParam[pl](zc, z, plp)
+ zc, pile, pilePars = None, [], []
+ if len(pile) > 0:
+ raise RROMPyException(("Missing numerical expression feeding into "
+ "'{}'.").format(pile[-1]))
+ if force_shape is not None:
+ if hasattr(z, "__len__") and len(z) > 1:
+ if isinstance(z, (parameterList,)): z = z.data
+ if isinstance(z, (list, tuple,)): z = np.array(z)
+ if z.size == np.prod(force_shape):
+ z = np.reshape(z, force_shape)
+ else:
+ zdim = len(z.shape)
+ if z.shape != force_shape[: zdim]:
+ raise RROMPyException(("Error in reshaping result: shapes "
+ "{} and {} not compatible.").format(
+ z.shape, force_shape))
+ else:
+ z = np.tile(z, [1] * zdim + force_shape[zdim :])
+ else:
+ if hasattr(z, "__len__"): z = z[0]
+ z = z * np.ones(force_shape)
+ return z
diff --git a/rrompy/utilities/expression/keys.py b/rrompy/utilities/expression/keys.py
new file mode 100644
index 0000000..7b1bd54
--- /dev/null
+++ b/rrompy/utilities/expression/keys.py
@@ -0,0 +1,57 @@
+# 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
+
+expressionKeysUnary = {"sin" : lambda x: np.sin(x),
+ "cos" : lambda x: np.cos(x),
+ "tan" : lambda x: np.tan(x),
+ "arcsin" : lambda x: np.arcsin(x),
+ "arccos" : lambda x: np.arccos(x),
+ "arctan" : lambda x: np.arctan(x),
+ "floor" : lambda x: np.floor(x),
+ "ceil" : lambda x: np.ceil(x),
+ "round" : lambda x: np.round(x),
+ "exp" : lambda x: np.exp(x),
+ "expm1" : lambda x: np.expm1(x),
+ "log" : lambda x: np.log(x),
+ "reciprocal" : lambda x: np.reciprocal(x),
+ "negative" : lambda x: np.negative(x),
+ "abs" : lambda x: np.abs(x),
+ "angle" : lambda x: np.angle(x),
+ "real" : lambda x: np.real(x),
+ "imag" : lambda x: np.imag(x),
+ "conj" : lambda x: np.negative(x),
+ "data" : lambda x: x.data}
+
+expressionKeysBinary = {"+" : lambda x, y: x + y,
+ "-" : lambda x, y: x - y,
+ "*" : lambda x, y: x * y,
+ "/" : lambda x, y: x / y,
+ "//" : lambda x, y: x // y,
+ "**" : lambda x, y: x ** y,
+ "[]" : lambda x, y: x[y],
+ "()" : lambda x, y: x(y)}
+
+expressionKeysUnaryParam = {
+ "sum" : lambda x, pars: np.sum(x, **pars),
+ "mean" : lambda x, pars: np.mean(x, **pars),
+ "prod" : lambda x, pars: np.prod(x, **pars)}
+
+expressionKeysBinaryParam = {}
+
diff --git a/rrompy/utilities/expression/monomial_creator.py b/rrompy/utilities/expression/monomial_creator.py
new file mode 100644
index 0000000..dcbffe1
--- /dev/null
+++ b/rrompy/utilities/expression/monomial_creator.py
@@ -0,0 +1,57 @@
+# 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.utilities.numerical import (multibinom, nextDerivativeIndices,
+ hashIdxToDerivative as hashI,
+ hashDerivativeToIdx as hashD)
+from rrompy.utilities.base.types import List, TupleAny
+
+__all__ = ["createMonomial", "createMonomialList"]
+
+def createMonomial(deg:List[int],
+ return_derivatives : bool = False) -> List[List[TupleAny]]:
+ if not hasattr(deg, "__len__"): deg = [deg]
+ dim = len(deg)
+ degj = hashD(deg)
+ expr = []
+ for k in range(degj * return_derivatives + 1):
+ degder = hashI(k, dim)
+ derdiff = [x - y for (x, y) in zip(deg, degder)]
+ if all([d >= 0 for d in derdiff]):
+ mult = multibinom(deg, degder)
+ if np.sum(derdiff) == 0:
+ exprLoc = (mult,)
+ else:
+ exprLoc = ("prod", {"axis" : 1}, ("data", "x", "**", derdiff))
+ if not np.isclose(mult, 1):
+ exprLoc = exprLoc + ("*", mult,)
+ expr += [exprLoc]
+ else:
+ expr += [(0.,)]
+ if return_derivatives: expr += [None]
+ return expr
+
+def createMonomialList(n:int, dim:int,
+ return_derivatives : bool = False) -> List[List[TupleAny]]:
+ derIdxs = nextDerivativeIndices([], dim, n)
+ idxList = []
+ for j, der in enumerate(derIdxs):
+ idxList += [createMonomial(der, return_derivatives)]
+ return idxList
+
diff --git a/rrompy/utilities/numerical/__init__.py b/rrompy/utilities/numerical/__init__.py
index 6af5afa..10f6b57 100644
--- a/rrompy/utilities/numerical/__init__.py
+++ b/rrompy/utilities/numerical/__init__.py
@@ -1,49 +1,67 @@
# 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 .custom_pinv import customPInv
+from .degree import (fullDegreeN, totalDegreeN, fullDegreeSet, totalDegreeSet,
+ degreeTotalToFull, fullDegreeMaxMask, totalDegreeMaxMask)
from .factorials import multibinom, multifactorial
from .halton import haltonGenerate
+from .hash_derivative import (nextDerivativeIndices, hashDerivativeToIdx,
+ hashIdxToDerivative)
from .kroneckerer import kroneckerer
from .low_discrepancy import lowDiscrepancy
from .marginalize_poly_list import marginalizePolyList
from .nonlinear_eigenproblem import (linearizeDense, eigNonlinearDense,
eigvalsNonlinearDense)
from .number_theory import squareResonances
from .point_matching import pointMatching
from .sobol import sobolGenerate
+from .tensor_la import dot, solve
freepar = None
__all__ = [
+ 'freepar',
'customPInv',
+ 'fullDegreeN',
+ 'totalDegreeN',
+ 'fullDegreeSet',
+ 'totalDegreeSet',
+ 'degreeTotalToFull',
+ 'fullDegreeMaxMask',
+ 'totalDegreeMaxMask',
'multibinom',
'multifactorial',
'haltonGenerate',
+ 'nextDerivativeIndices',
+ 'hashDerivativeToIdx',
+ 'hashIdxToDerivative',
'kroneckerer',
'lowDiscrepancy',
'marginalizePolyList',
'linearizeDense',
'eigNonlinearDense',
'eigvalsNonlinearDense',
'squareResonances',
'pointMatching',
- 'sobolGenerate'
+ 'sobolGenerate',
+ 'dot',
+ 'solve'
]
diff --git a/rrompy/utilities/numerical/degree.py b/rrompy/utilities/numerical/degree.py
new file mode 100644
index 0000000..5ffe723
--- /dev/null
+++ b/rrompy/utilities/numerical/degree.py
@@ -0,0 +1,59 @@
+# 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 scipy.special import binom
+from rrompy.utilities.base.types import Np2D, Tuple, List
+from .kroneckerer import kroneckerer
+
+__all__ = ['fullDegreeN', 'totalDegreeN', 'fullDegreeSet', 'totalDegreeSet',
+ 'degreeTotalToFull', 'fullDegreeMaxMask', 'totalDegreeMaxMask']
+
+def fullDegreeN(deg:int, npar:int) -> int:
+ return (1 + deg) ** npar
+
+def totalDegreeN(deg:int, npar:int) -> int:
+ return int(binom(deg + npar, npar))
+
+def fullDegreeSet(deg:int, npar:int) -> List[List[int]]:
+ idxs = np.empty((fullDegreeN(deg, npar), npar), dtype = int)
+ for j in range(npar):
+ idxs[:, j] = kroneckerer(np.arange(deg + 1), fullDegreeN(deg, j),
+ fullDegreeN(deg, npar - j - 1))
+ return idxs
+
+def totalDegreeSet(deg:int, npar:int,
+ return_mask : bool = False) -> List[List[int]]:
+ remN = fullDegreeSet(deg, npar)
+ mask = np.sum(remN, axis = 1) <= deg
+ if return_mask: return remN[mask], mask
+ return remN[mask]
+
+def degreeTotalToFull(shapeFull:Tuple[int], dim:int, coeffs:Np2D) -> Np2D:
+ from .hash_derivative import hashIdxToDerivative as hashI
+ full = np.zeros(shapeFull, dtype = coeffs.dtype)
+ for j in range(len(coeffs)):
+ full[tuple(hashI(j, dim))] = coeffs[j]
+ return full
+
+def fullDegreeMaxMask(deg:int, npar:int) -> List[int]:
+ return np.where(np.any(fullDegreeSet(deg, npar) == deg, axis = 1))[0]
+
+def totalDegreeMaxMask(deg:int, npar:int) -> List[int]:
+ if deg == 0: return np.zeros(1, dtype = int)
+ return np.arange(totalDegreeN(deg - 1, npar), totalDegreeN(deg, npar))
diff --git a/rrompy/utilities/poly_fitting/polynomial/derivative.py b/rrompy/utilities/numerical/hash_derivative.py
similarity index 78%
rename from rrompy/utilities/poly_fitting/polynomial/derivative.py
rename to rrompy/utilities/numerical/hash_derivative.py
index ba9fab4..ecce005 100644
--- a/rrompy/utilities/poly_fitting/polynomial/derivative.py
+++ b/rrompy/utilities/numerical/hash_derivative.py
@@ -1,72 +1,94 @@
# 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 scipy.special import binom
from rrompy.utilities.base.types import List
from rrompy.utilities.exception_manager import RROMPyException
+from .degree import totalDegreeN
-__all__ = ['nextDerivativeIndices']
+__all__ = ['nextDerivativeIndices', 'hashDerivativeToIdx',
+ 'hashIdxToDerivative']
def nextDerivativeIndices(derIdxs:List[List[int]], dim:int,
count : int = 1) -> List[List[int]]:
out = []
if count <= 0: return out
derIdxs = copy(derIdxs)
sumDer, sumInverse, sumCount = np.unique(
[np.sum(derIdx) for derIdx in derIdxs],
return_inverse = True, return_counts = True)
if len(derIdxs) == 0 or 0 not in sumDer:
out += [[0] * dim]
count -= 1
if count <= 0: return out
derIdxs += [[0] * dim]
shellIncomplete = 1
_, sumInverse = np.unique([np.sum(derIdx) for derIdx in derIdxs],
return_inverse = True)
else:
sumCount = np.cumsum(sumCount)
shellIncomplete = 1
for shellIncomplete in range(1, len(sumDer) + 1):
- theoreticalCount = binom(shellIncomplete + dim, dim)
+ theoreticalCount = totalDegreeN(shellIncomplete, dim)
if (shellIncomplete not in sumDer
or theoreticalCount > sumCount[shellIncomplete]):
break
if theoreticalCount < sumCount[shellIncomplete]:
raise RROMPyException("Starting index list is redundant.")
shell_previous = [derIdxs[x] for x in
np.nonzero(sumInverse == shellIncomplete - 1)[0]]
while count > 0:
shell_current = [derIdxs[x] for x in
np.nonzero(sumInverse == shellIncomplete)[0]]
for prev in shell_previous:
prevC = copy(prev)
for d in range(dim):
prevC[d] += 1
if prevC not in shell_current:
out += [copy(prevC)]
shell_current += [copy(prevC)]
derIdxs += [copy(prevC)]
count -= 1
if count <= 0: return out
prevC[d] -= 1
shell_previous = copy(shell_current)
_, sumInverse = np.unique([np.sum(derIdx) for derIdx in derIdxs],
return_inverse = True)
shellIncomplete += 1
+
+def hashDerivativeToIdx(derIdx:List[int]) -> int:
+ dim = len(derIdx)
+ if dim == 0: return 0
+ derMag = sum(derIdx)
+ base = totalDegreeN(derMag - 1, dim)
+ if derMag == derIdx[0]: return base
+ return base + hashDerivativeToIdx(derIdx[1:])
+
+def hashIdxToDerivative(n:int, dim:int) -> List[int]:
+ if n == 0: return [0] * dim
+ shell = 0
+ shellOld = -1
+ shellNew = 1
+ while shellNew <= n:
+ shell += 1
+ shellOld = shellNew
+ shellNew = totalDegreeN(shell, dim)
+ rest = hashIdxToDerivative(n - shellOld, dim - 1)
+ return [shell - sum(rest)] + rest
+
diff --git a/rrompy/utilities/numerical/marginalize_poly_list.py b/rrompy/utilities/numerical/marginalize_poly_list.py
index 9780834..d36262c 100644
--- a/rrompy/utilities/numerical/marginalize_poly_list.py
+++ b/rrompy/utilities/numerical/marginalize_poly_list.py
@@ -1,79 +1,79 @@
# 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 scipy.sparse import csr
from rrompy.utilities.base.types import Np1D, Np2D, ListAny
from rrompy.utilities.base import freepar as fp
-from rrompy.utilities.poly_fitting.polynomial import (
- hashDerivativeToIdx as hashD, hashIdxToDerivative as hashI)
+from .hash_derivative import (hashDerivativeToIdx as hashD,
+ hashIdxToDerivative as hashI)
from rrompy.parameter import checkParameter
__all__ = ['marginalizePolyList']
def marginalizePolyList(objs:ListAny, marginalVals : Np1D = [fp],
zeroObj : Np2D = 0.,
recompress : bool = True) -> ListAny:
res = []
freeLocations = []
fixedLocations = []
muFixed = []
if not hasattr(marginalVals, "__len__"): marginalVals = [marginalVals]
for i, m in enumerate(marginalVals):
if m == fp:
freeLocations += [i]
else:
fixedLocations += [i]
muFixed += [m]
muFixed = checkParameter(muFixed, len(fixedLocations))
if zeroObj == "auto":
if isinstance(objs[0], np.ndarray):
zeroObj = np.zeros_like(objs[0])
elif isinstance(objs[0], csr.csr_matrix):
d = objs[0].shape[0]
zeroObj = csr.csr_matrix(([], [], np.zeros(d + 1)),
shape = objs[0].shape,
dtype = objs[0].dtype)
else:
zeroObj = 0.
for j, obj in enumerate(objs):
derjBase = hashI(j, len(marginalVals))
jNew = hashD([derjBase[i] for i in freeLocations])
derjFixed = [derjBase[i] for i in fixedLocations]
obj = np.prod((muFixed ** derjFixed).data) * obj
if jNew >= len(res):
for _ in range(len(res), jNew):
res += [zeroObj]
res += [obj]
else:
res[jNew] = res[jNew] + obj
if recompress:
for re in res[::-1]:
try:
if isinstance(re, np.ndarray):
iszero = np.allclose(re, zeroObj,
atol = 2 * np.finfo(re.dtype).eps)
elif isinstance(re, csr.csr_matrix):
iszero = re.nnz == 0
else:
break
if not iszero: break
except: break
res.pop()
return res
-
\ No newline at end of file
+
diff --git a/rrompy/utilities/numerical/point_matching.py b/rrompy/utilities/numerical/point_matching.py
index 9029e02..599e938 100644
--- a/rrompy/utilities/numerical/point_matching.py
+++ b/rrompy/utilities/numerical/point_matching.py
@@ -1,165 +1,26 @@
# 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 itertools import permutations
+from scipy.optimize import linear_sum_assignment as LSA
from rrompy.utilities.base.types import Np1D, Np2D
-from rrompy.utilities.base import verbosityManager as vbMng
-from rrompy.utilities.exception_manager import RROMPyException
__all__ = ['pointMatching']
-def matchExplicit(distanceMatrix:Np2D, idx1:Np1D, idx2:Np1D,
- verbObj = None) -> Np1D:
- if verbObj is not None:
- vbMng(verbObj, "INIT", ("Starting exact point matching of {} "
- "points.").format(len(distanceMatrix)), 25)
- L1 = len(idx1)
- matches, optV = None, None
- idxLead = 0
- for idx2p in permutations(idx2, L1):
- if verbObj is not None and idxLead != idx2p[0]:
- idxLead += 1
- explRatio = 100 * idxLead / len(idx2)
- vbMng(verbObj, "MAIN",
- "Explored {}% of permutations.".format(int(explRatio)), 65)
- val = np.sum(distanceMatrix[idx1, idx2p])
- if optV is None or val < optV:
- optV, matches = val, idx2p
- if verbObj is not None:
- vbMng(verbObj, "DEL", "Done point matching.", 25)
- return np.array(matches)
+def pointMatching(distanceMatrix:Np2D) -> Np1D:
+ return LSA(distanceMatrix)[1]
-def findClusterBipartiteRecursive(i, edges, clusters, explored, right):
- if explored[right][i] == 0: return clusters, explored
- explored[right][i] = 0
- if edges[right][i] not in clusters[1 - right]:
- clusters[1 - right] += [edges[right][i]]
- clusters, explored = findClusterBipartiteRecursive(edges[right][i], edges,
- clusters, explored,
- 1 - right)
- for k, i2 in enumerate(edges[1 - right]):
- if i2 == i and k not in clusters[1 - right]:
- clusters[1 - right] += [k]
- clusters, explored = findClusterBipartiteRecursive(k, edges,
- clusters, explored,
- 1 - right)
- return clusters, explored
-
-def pointMatchingHeuristic(distanceMatrix:Np2D, idx1:Np1D, idx2:Np1D,
- max_iter : int = 10, verbObj = None,
- expl_threshold : int = 8) -> Np1D:
- if verbObj is not None:
- vbMng(verbObj, "INIT", ("Starting heuristic point matching of {} "
- "points.").format(len(idx1)), 25)
- distanceMatrixEff = distanceMatrix[idx1, :]
- distanceMatrixEff = distanceMatrixEff[:, idx2]
- N = len(distanceMatrixEff)
- matches = - np.ones(N, dtype = int)
- fBest = np.argmin(distanceMatrixEff, axis = 1)
- bBest = np.argmin(distanceMatrixEff, axis = 0)
- clusters1, clusters2 = [], []
- fIdxs = [np.ones(N, dtype = bool), np.ones(N, dtype = bool)]
- if verbObj is not None: vbMng(verbObj, "INIT", "Starting clustering.", 65)
- for i in range(N):
- if fIdxs[0][i]:
- cloc, fIdxs = findClusterBipartiteRecursive(i, [fBest, bBest],
- [[], []], fIdxs, 0)
- clusters1 += [cloc[0]]
- clusters2 += [cloc[1]]
- if verbObj is not None: vbMng(verbObj, "DEL", "Done clustering.", 65)
- if verbObj is not None:
- vbMng(verbObj, "INIT", "Starting optimization of clustered points.",
- 65)
- for c1, c2 in zip(clusters1, clusters2):
- if len(c1) > len(c2):
- if len(c1) > expl_threshold:
- optP = np.random.permutation(c1)[: len(c2)]
- max_iter += int(np.ceil(np.log2(len(c1))))
- else:
- optP = matchExplicit(distanceMatrixEff.T, c2, c1)
- for i, k in enumerate(optP):
- matches[k] = c2[i]
- else:
- if len(c2) > expl_threshold:
- optP = np.random.permutation(c2)[: len(c1)]
- max_iter += int(np.ceil(np.log2(len(c2))))
- else:
- optP = matchExplicit(distanceMatrixEff, c1, c2)
- for i, k in enumerate(c1):
- matches[k] = optP[i]
- front1 = np.where(matches == -1)[0]
- if len(front1) == 0:
- if verbObj is not None: vbMng(verbObj, "DEL", "Done optimizing.", 65)
- if verbObj is not None:
- vbMng(verbObj, "DEL", "Done point matching.", 25)
- return idx2[matches]
- if len(front1) == N:
- raise RROMPyException(("Heuristic point matching algorithm not "
- "converging. Must increase threshold."))
- optP = np.array([i for i in range(N) if i not in matches], dtype = int)
- if verbObj is not None: vbMng(verbObj, "DEL", "Done optimizing.", 65)
- for _ in range(max_iter):
- bulk1 = [i for i in range(N) if i not in front1]
- if verbObj is not None:
- vbMng(verbObj, "INIT", ("Starting optimization of {} unclustered "
- "points.").format(len(front1)), 65)
- optP = pointMatching(distanceMatrixEff, idx1 = front1, idx2 = optP)
- for i, k in enumerate(front1): matches[k] = optP[i]
- if verbObj is not None: vbMng(verbObj, "DEL", "Done optimizing.", 65)
- if verbObj is not None:
- vbMng(verbObj, "INIT",
- ("Starting optimization of {}x{} frontier "
- "points.").format(len(front1), len(bulk1)), 65)
- keepfront1, addfront1, addoptP = [], [], []
- for i, il1 in enumerate(front1):
- il2 = optP[i]
- change = False
- for ib1 in bulk1:
- ib2 = matches[ib1]
- val = (
- distanceMatrixEff[il1, ib2] + distanceMatrixEff[ib1, il2]
- - distanceMatrixEff[il1, il2] - distanceMatrixEff[ib1, ib2])
- if val < 0:
- addfront1 += [ib1]
- addoptP += [il2]
- matches[ib1] = il2
- matches[il1] = ib2
- il2 = ib2
- optP[i] = ib2
- change = True
- if change: keepfront1 += [i]
- front1, optP = front1[keepfront1], optP[keepfront1]
- for (addb, addo) in zip(addfront1[::-1], addoptP[::-1]):
- if addb not in front1:
- front1, optP = np.append(front1, addb), np.append(optP, addo)
- if verbObj is not None: vbMng(verbObj, "DEL", "Done optimizing.", 65)
- if len(front1) == 0: break
- if verbObj is not None: vbMng(verbObj, "DEL", "Done point matching.", 25)
- return idx2[matches]
-
-def pointMatching(distanceMatrix:Np2D, expl_threshold : int = 8,
- max_iter : int = 10, verbObj = None, idx1 : Np1D = None,
- idx2 : Np1D = None) -> Np1D:
- N = len(distanceMatrix)
- if idx1 is None: idx1 = np.arange(N)
- if idx2 is None: idx2 = np.arange(N)
- if len(idx1) > expl_threshold:
- return pointMatchingHeuristic(distanceMatrix, idx1, idx2, max_iter,
- verbObj, expl_threshold)
- return matchExplicit(distanceMatrix, idx1, idx2, verbObj)
diff --git a/rrompy/utilities/poly_fitting/radial_basis/kernel.py b/rrompy/utilities/numerical/tensor_la.py
similarity index 54%
copy from rrompy/utilities/poly_fitting/radial_basis/kernel.py
copy to rrompy/utilities/numerical/tensor_la.py
index d0e1db2..9900771 100644
--- a/rrompy/utilities/poly_fitting/radial_basis/kernel.py
+++ b/rrompy/utilities/numerical/tensor_la.py
@@ -1,35 +1,39 @@
# 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.utilities.base.types import Np1D
-from rrompy.utilities.exception_manager import RROMPyAssert
-__all__ = ['radialGaussian', 'thinPlateSpline', 'multiQuadric']
+__all__ = ['dot', 'solve']
-def radialGaussian(r2:Np1D, der : int = 0) -> Np1D:
- RROMPyAssert(der, 0, "Radial basis derivative")
- return np.exp(- .5 * r2)
+def dot(u, v):
+ if u.shape[-1] == v.shape[0]:
+ if isinstance(u, np.ndarray):
+ return np.tensordot(u, v, 1)
+ else:
+ return u.dot(v)
+ M = u.shape[-1]
+ N = v.shape[0] // M
+ rshape = u.shape[: -2] + (N * u.shape[-2],) + v.shape[1 :]
+ return u.dot(v.reshape(M, -1)).reshape(rshape)
-def thinPlateSpline(r2:Np1D, der : int = 0) -> Np1D:
- RROMPyAssert(der, 0, "Radial basis derivative")
- return .5 * r2 * np.log(np.finfo(float).eps + r2)
-
-def multiQuadric(r2:Np1D, der : int = 0) -> Np1D:
- RROMPyAssert(der, 0, "Radial basis derivative")
- return np.power(r2 + 1., -.5)
+def solve(A, b, solver, kwargs):
+ if A.shape[-1] == b.shape[0]: return solver(A, b, kwargs)
+ M = A.shape[-1]
+ N = b.shape[0] // M
+ rshape = A.shape[: -2] + (N * A.shape[-2],) + b.shape[1 :]
+ return solver(A, b.reshape(M, -1), kwargs).reshape(rshape)
diff --git a/rrompy/utilities/poly_fitting/heaviside/__init__.py b/rrompy/utilities/poly_fitting/heaviside/__init__.py
index 4074d47..0025e9f 100644
--- a/rrompy/utilities/poly_fitting/heaviside/__init__.py
+++ b/rrompy/utilities/poly_fitting/heaviside/__init__.py
@@ -1,41 +1,40 @@
# 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 .base import polybases, polyfitname, polydomcoeff
from .val import polyval
-from .vander import polyvander
-from .homogeneization import homogeneizedpolyvander
+from .vander import polyvander, polyvanderTotal
from .heaviside_to_from_rational import heaviside2rational, rational2heaviside
from .heaviside_to_from_affine import heaviside2affine, affine2heaviside
from .heaviside_interpolator import HeavisideInterpolator
__all__ = [
'polybases',
'polyfitname',
'polydomcoeff',
'polyval',
'polyvander',
'heaviside2rational',
'rational2heaviside',
'heaviside2affine',
'affine2heaviside',
- 'homogeneizedpolyvander',
+ 'polyvanderTotal',
'HeavisideInterpolator'
]
diff --git a/rrompy/utilities/poly_fitting/heaviside/heaviside_interpolator.py b/rrompy/utilities/poly_fitting/heaviside/heaviside_interpolator.py
index f0aca96..818219e 100644
--- a/rrompy/utilities/poly_fitting/heaviside/heaviside_interpolator.py
+++ b/rrompy/utilities/poly_fitting/heaviside/heaviside_interpolator.py
@@ -1,77 +1,82 @@
# 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, Np1D, paramList,
interpEng)
from rrompy.utilities.base import freepar as fp
from rrompy.utilities.poly_fitting.polynomial.polynomial_interpolator import (
PolynomialInterpolator)
from rrompy.utilities.poly_fitting.polynomial.roots import polyroots
-from rrompy.utilities.poly_fitting.heaviside.val import polyval
-from rrompy.utilities.poly_fitting.heaviside.heaviside_to_from_rational import\
- heaviside2rational, rational2heaviside
+from .val import polyval
+from .heaviside_to_from_affine import affine2heaviside
+from .heaviside_to_from_rational import heaviside2rational, rational2heaviside
from rrompy.utilities.exception_manager import RROMPyAssert
__all__ = ['HeavisideInterpolator']
class HeavisideInterpolator(PolynomialInterpolator):
"""HERE"""
def __init__(self, other = None):
if other is None: return
self.poles = other.poles
super().__init__(other)
def __call__(self, mu:paramList, der : List[int] = None,
scl : Np1D = None):
return polyval(mu, self.coeffs, self.poles, self.polybasis)
def __copy__(self):
return HeavisideInterpolator(self)
def __deepcopy__(self, memo):
other = HeavisideInterpolator()
other.poles, other.coeffs, other.npar, other.polybasis = copy(
(self.poles, self.coeffs, self.npar, self.polybasis), memo)
return other
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(nleft[0], 0, "Padding in free direction")
super().pad(nleft, nright)
+ def setupFromAffine(self, As:ListAny, bs:ListAny,
+ jSupp : int = 1):
+ self.coeffs, self.poles, self.polybasis = affine2heaviside(As, bs,
+ jSupp)
+
def setupFromRational(self, num:interpEng, den:interpEng,
murange : Np1D = np.array([-1., 1.]),
scl : Np1D = None, scalingExp : List[float] = None):
self.coeffs, self.poles, self.polybasis = rational2heaviside(num, den,
murange, scl,
scalingExp)
def roots(self, marginalVals : ListAny = [fp], murange : Np1D = None,
scalingExp : List[float] = None):
RROMPyAssert(self.shape, (1,), "Shape of output")
RROMPyAssert(marginalVals, [fp], "Marginal values")
basisN = self.polybasis.split("_")[0]
coeffsN = heaviside2rational(self.coeffs, self.poles, murange, basisN,
scalingExp = scalingExp)[0]
return polyroots(coeffsN, basisN)
diff --git a/rrompy/utilities/poly_fitting/heaviside/heaviside_to_from_affine.py b/rrompy/utilities/poly_fitting/heaviside/heaviside_to_from_affine.py
index 11cbc3b..931b7d7 100644
--- a/rrompy/utilities/poly_fitting/heaviside/heaviside_to_from_affine.py
+++ b/rrompy/utilities/poly_fitting/heaviside/heaviside_to_from_affine.py
@@ -1,94 +1,95 @@
# 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 scipy.special import binom
import scipy.sparse as sp
from rrompy.utilities.base.types import (Np1D, Np2D, List, ListAny, Tuple,
paramVal)
-from rrompy.utilities.numerical import eigNonlinearDense
+from rrompy.utilities.numerical import eigNonlinearDense, dot, solve
from rrompy.utilities.exception_manager import RROMPyException
from rrompy.parameter import checkParameter
__all__ = ['heaviside2affine', 'affine2heaviside']
def heaviside2affine(c:Np2D, poles:Np1D, mu : paramVal = [],
basis : str = "MONOMIAL_HEAVISIDE",
sparse : bool = False) \
-> Tuple[Np2D, List[Np2D], List[Np1D]]:
mu = checkParameter(mu, 1)(0, 0)
n, d = len(poles), len(c) - len(poles)
basisN = basis.split("_")[0]
if basisN not in ["MONOMIAL", "CHEBYSHEV", "LEGENDRE"]:
raise RROMPyException("Polynomial basis not recognized.")
if sparse:
A0 = sp.spdiags([np.concatenate((- mu - poles, np.ones(d)))],
[0], n + d, n + d)
A1 = sp.spdiags([np.concatenate((np.ones(n), np.zeros(d)))],
[0], n + d, n + d)
else:
A0 = np.diag(np.concatenate((mu - poles, np.ones(d))))
A1 = np.diag(np.concatenate((np.ones(n), np.zeros(d))))
As = [A0, A1]
bs = np.zeros((d, n + d), dtype = poles.dtype)
bs[0, :] = 1.
if d > 0:
bs[0, n + 1 :] = 0.
if d > 1:
bs[1, n + 1] = 1.
for j in range(2, d):
if basisN == "MONOMIAL":
bs[j, n + j] = 1.
else:
alpha = - 1. if basisN == "CHEBYSHEV" else 1. / j - 1.
bs[:, n + j] = alpha * bs[:, n + j - 2]
bs[1 :, n + j] += (1. - alpha) * bs[: -1, n + j - 1]
bs = list(bs)
return c.reshape(c.shape[0], -1).T, As, bs
def affine2heaviside(As:ListAny, bs:ListAny,
jSupp : int = 1) -> Tuple[Np2D, Np1D, str]:
if jSupp != 1 and not (isinstance(jSupp, (int,))
and jSupp.upper() == "COMPANION"):
raise RROMPyException(("Affine to heaviside conversion does not allow "
"nonlinear eigenproblem support outside first "
"block row."))
N = len(As)
M = len(bs)
n = As[0].shape[0]
if N == 1:
poles = np.empty(0, dtype = np.complex)
Q = np.eye(n)
else:
basis = "MONOMIAL_HEAVISIDE"
poles, P, Q = eigNonlinearDense(As, jSupp = jSupp,
return_inverse = True)
P = P[- n :, :]
Q = Q[:, : n]
- bEffs = np.array([Q.dot(np.linalg.solve(As[-1], b)) for b in bs])
+ bEffs = np.array([dot(Q, solve(As[-1], b, np.linalg.solve,
+ {})) for b in bs])
if N == 1:
c = bEffs
else:
- c = np.zeros((len(poles) + M - 1, As[0].shape[1]), dtype = As[0].dtype)
+ c = np.zeros((len(poles) + M - 1, As[0].shape[1]), dtype = np.complex)
for l, pl in enumerate(poles):
for i in range(M):
c[l, :] = pl ** i * bEffs[i, l] * P[:, l]
for l in range(M - 1):
for i in range(l + 1, M):
- c[len(poles) + l, :] = P.dot(poles ** (i- 1 - l) * bEffs[i, :])
+ c[len(poles) + l, :] = dot(P, poles ** (i- 1 - l) * bEffs[i, :])
return c, poles, basis
diff --git a/rrompy/utilities/poly_fitting/heaviside/homogeneization.py b/rrompy/utilities/poly_fitting/heaviside/homogeneization.py
deleted file mode 100644
index d72c308..0000000
--- a/rrompy/utilities/poly_fitting/heaviside/homogeneization.py
+++ /dev/null
@@ -1,51 +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 rrompy.utilities.base.types import Np1D, Np2D, Tuple, List, paramList
-from rrompy.utilities.poly_fitting.polynomial.homogeneization import (
- homogeneizedpolyvander as hpvP)
-from rrompy.utilities.exception_manager import RROMPyException
-from .vander import heavisidevander
-
-__all__ = ['homogeneizedpolyvander']
-
-def homogeneizedpolyvander(x:paramList, poles:Np1D, deg : int = None,
- basis : str = "MONOMIAL_HEAVISIDE",
- derIdxs : List[List[List[int]]] = None,
- reorder : List[int] = None, scl : Np1D = None)\
- -> Tuple[Np2D, List[List[int]], List[int]]:
- """
- Compute radial-basis-inclusive homogeneized Hermite-Vandermonde matrix with
- specified derivative directions.
- """
- if derIdxs is not None and np.sum(np.sum(derIdxs)) > 0:
- raise RROMPyException(("Cannot take derivatives of radial basis "
- "function."))
- basisp = basis.split("_")[0]
- VanR = heavisidevander(x, poles, reorder = reorder)
- if deg is None or deg < 0:
- VanP = np.empty((len(x), 0))
- derIdxs, ordIdxs = np.zeros(0, dtype = int), np.zeros(0, dtype = int)
- else:
- VanP, derIdxs, ordIdxs = hpvP(x, deg, basisp, derIdxs = derIdxs,
- reorder = reorder, scl = scl)
- ordIdxsEff = np.concatenate((np.arange(len(VanR)), ordIdxs + len(VanR)))
- return (np.block([[VanR, VanP],
- [VanP.T.conj(), np.zeros(tuple([VanP.shape[1]] * 2))]]),
- derIdxs, ordIdxsEff)
diff --git a/rrompy/utilities/poly_fitting/heaviside/val.py b/rrompy/utilities/poly_fitting/heaviside/val.py
index 2a8fa45..af590f6 100644
--- a/rrompy/utilities/poly_fitting/heaviside/val.py
+++ b/rrompy/utilities/poly_fitting/heaviside/val.py
@@ -1,46 +1,46 @@
# 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 Np1D, Np2D, paramList
from rrompy.parameter import checkParameterList
-from rrompy.utilities.poly_fitting.polynomial import polyval as pvP
+from rrompy.utilities.poly_fitting.polynomial.val import polyval as pvP
__all__ = ['polyval']
def polyval(x:paramList, c:Np2D, poles:Np1D,
basis : str = "MONOMIAL_HEAVISIDE") -> Np2D:
x = checkParameterList(x, 1)[0]
poles = poles.flatten()
if len(c) > len(poles):
basisp = basis.split("_")[0]
c0 = pvP(x, c[len(poles) :], basisp)
else:
c0 = np.zeros(c.shape[1:] + (len(x),), dtype = c.dtype)
csh = copy(c0.shape)
if len(csh) == 1: c0 = c0.reshape(1, -1)
for j in range(len(x)):
muDiff = 1. / (x[j] - poles)
val = muDiff.dot(c[: len(poles)])
try:
c0[..., j] += val
except:
c0[..., j] += val.flatten()
if len(csh) == 1: c0 = c0.flatten()
return c0
diff --git a/rrompy/utilities/poly_fitting/heaviside/vander.py b/rrompy/utilities/poly_fitting/heaviside/vander.py
index 1b752de..ce816d3 100644
--- a/rrompy/utilities/poly_fitting/heaviside/vander.py
+++ b/rrompy/utilities/poly_fitting/heaviside/vander.py
@@ -1,62 +1,89 @@
# 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.utilities.poly_fitting.polynomial.vander import polyvander as pvP
-from rrompy.utilities.base.types import Np1D, Np2D, List, paramList
+from rrompy.utilities.poly_fitting.polynomial.vander import (polyvander as pvP,
+ polyvanderTotal as pvTP)
+from rrompy.utilities.base.types import Np1D, Np2D, Tuple, List, paramList
from rrompy.parameter import checkParameterList
from rrompy.utilities.exception_manager import RROMPyException
-__all__ = ['heavisidevander', 'polyvander']
+__all__ = ['heavisidevander', 'polyvander', 'polyvanderTotal']
def heavisidevander(x:paramList, poles:Np1D,
reorder : List[int] = None) -> Np2D:
"""Compute Heaviside-Vandermonde matrix."""
x = checkParameterList(x, 1)[0]
x_un, idx_un = x.unique(return_inverse = True)
nx = len(x)
if len(x_un) < nx:
raise RROMPyException("Sample points must be distinct.")
del x_un
x = x.data.flatten()
if reorder is not None: x = x[reorder]
poles = poles.flatten()
- Van = np.empty((len(x), len(poles)), dtype = poles.dtype)
+ Van = np.empty((len(x), len(poles)), dtype = np.complex)
for j in range(len(x)):
Van[j, :] = 1. / (x[j] - poles)
return Van
def polyvander(x:paramList, poles:Np1D, degs : List[int] = None,
basis : str = "MONOMIAL_HEAVISIDE",
derIdxs : List[List[List[int]]] = None,
reorder : List[int] = None, scl : Np1D = None) -> Np2D:
"""
- Compute Heaviside-inclusive Hermite-Vandermonde matrix with specified
- derivative directions.
+ Compute full Hermite-Vandermonde matrix with specified derivative
+ directions.
"""
if derIdxs is not None and np.sum(np.sum(derIdxs)) > 0:
raise RROMPyException(("Cannot take derivatives of heaviside "
"function."))
basisp = basis.split("_")[0]
VanH = heavisidevander(x, poles, reorder = reorder)
if degs is None or np.sum(degs) < 0:
VanP = np.empty((len(x), 0))
else:
VanP = pvP(x, degs, basisp, derIdxs = derIdxs, reorder = reorder,
scl = scl)
return np.block([[VanH, VanP]])
+
+def polyvanderTotal(x:paramList, poles:Np1D, deg : int = None,
+ basis : str = "MONOMIAL_HEAVISIDE",
+ derIdxs : List[List[List[int]]] = None,
+ reorder : List[int] = None, scl : Np1D = None)\
+ -> Tuple[Np2D, List[List[int]], List[int]]:
+ """
+ Compute full total degree Hermite-Vandermonde matrix with specified
+ derivative directions.
+ """
+ if derIdxs is not None and np.sum(np.sum(derIdxs)) > 0:
+ raise RROMPyException(("Cannot take derivatives of radial basis "
+ "function."))
+ basisp = basis.split("_")[0]
+ VanR = heavisidevander(x, poles, reorder = reorder)
+ if deg is None or deg < 0:
+ VanP = np.empty((len(x), 0))
+ derIdxs, ordIdxs = np.zeros(0, dtype = int), np.zeros(0, dtype = int)
+ else:
+ VanP, derIdxs, ordIdxs = pvTP(x, deg, basisp, derIdxs = derIdxs,
+ reorder = reorder, scl = scl)
+ ordIdxsEff = np.concatenate((np.arange(len(VanR)), ordIdxs + len(VanR)))
+ return (np.block([[VanR, VanP],
+ [VanP.T.conj(), np.zeros(tuple([VanP.shape[1]] * 2))]]),
+ derIdxs, ordIdxsEff)
+
diff --git a/rrompy/utilities/poly_fitting/radial_basis/__init__.py b/rrompy/utilities/poly_fitting/moving_least_squares/__init__.py
similarity index 67%
copy from rrompy/utilities/poly_fitting/radial_basis/__init__.py
copy to rrompy/utilities/poly_fitting/moving_least_squares/__init__.py
index 108132b..d41094e 100644
--- a/rrompy/utilities/poly_fitting/radial_basis/__init__.py
+++ b/rrompy/utilities/poly_fitting/moving_least_squares/__init__.py
@@ -1,41 +1,40 @@
# 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
-from .base import rbbases, polybases, polyfitname, polydomcoeff
-from .val import polyval
-from .vander import rbvander, polyvander
-from .homogeneization import homogeneizedpolyvander
-from .radial_basis_interpolator import RadialBasisInterpolator
+from .kernel import (radialGaussian, thinPlateSpline, multiQuadric,
+ nearestNeighbor)
+from .base import mlsbases, polybases, polyfitname, polydomcoeff
+from .vander import mlsweights, polyvander, polyvanderTotal
+from .moving_least_squares_interpolator import MovingLeastSquaresInterpolator
__all__ = [
'radialGaussian',
'thinPlateSpline',
'multiQuadric',
- 'rbbases',
+ 'nearestNeighbor',
+ 'mlsbases',
'polybases',
'polyfitname',
'polydomcoeff',
- 'polyval',
- 'rbvander',
+ 'mlsweights',
'polyvander',
- 'homogeneizedpolyvander',
- 'RadialBasisInterpolator'
+ 'polyvanderTotal',
+ 'MovingLeastSquaresInterpolator'
]
diff --git a/rrompy/reduction_methods/pole_matching/__init__.py b/rrompy/utilities/poly_fitting/moving_least_squares/base.py
similarity index 66%
rename from rrompy/reduction_methods/pole_matching/__init__.py
rename to rrompy/utilities/poly_fitting/moving_least_squares/base.py
index 0370cf1..155b780 100644
--- a/rrompy/reduction_methods/pole_matching/__init__.py
+++ b/rrompy/utilities/poly_fitting/moving_least_squares/base.py
@@ -1,29 +1,27 @@
# 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 .generic_pole_matching_approximant import GenericPoleMatchingApproximant
-from .rational_interpolant_pole_matching import RationalInterpolantPoleMatching
-from .reduced_basis_pole_matching import ReducedBasisPoleMatching
+from rrompy.utilities.poly_fitting.radial_basis.base import (
+ rbbases, polybases as rbpb, polyfitname, polydomcoeff)
-__all__ = [
- 'GenericPoleMatchingApproximant',
- 'RationalInterpolantPoleMatching',
- 'ReducedBasisPoleMatching'
- ]
+__all__ = ['mlsbases', 'polybases', 'polyfitname', 'polydomcoeff']
+mlsbases = [rbb + "_MLS" for rbb in rbbases]
+
+polybases = [rbp + "_MLS" for rbp in rbpb]
diff --git a/rrompy/solver/scipy/__init__.py b/rrompy/utilities/poly_fitting/moving_least_squares/kernel.py
similarity index 73%
rename from rrompy/solver/scipy/__init__.py
rename to rrompy/utilities/poly_fitting/moving_least_squares/kernel.py
index c126e95..626f30b 100644
--- a/rrompy/solver/scipy/__init__.py
+++ b/rrompy/utilities/poly_fitting/moving_least_squares/kernel.py
@@ -1,25 +1,24 @@
# 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 .scipy_tensorize import tensorizeLS, detensorizeLS
+from rrompy.utilities.poly_fitting.radial_basis.kernel import (radialGaussian,
+ thinPlateSpline, multiQuadric, nearestNeighbor)
-__all__ = [
- 'tensorizeLS',
- 'detensorizeLS'
- ]
+__all__ = ['radialGaussian', 'thinPlateSpline', 'multiQuadric',
+ 'nearestNeighbor']
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
new file mode 100644
index 0000000..bab415d
--- /dev/null
+++ b/rrompy/utilities/poly_fitting/moving_least_squares/moving_least_squares_interpolator.py
@@ -0,0 +1,144 @@
+# 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):
+ """HERE"""
+
+ 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,
+ nNearestNeighbor = self.evalParams["nNearestNeighbor"])
+ 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 = self.suppValues.dot(A)
+
+ 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"]]
+ if "nNearestNeighbor" not in vanderCoeffs.keys():
+ vanderCoeffs["nNearestNeighbor"] = -1
+ 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
new file mode 100644
index 0000000..04094e1
--- /dev/null
+++ b/rrompy/utilities/poly_fitting/moving_least_squares/vander.py
@@ -0,0 +1,97 @@
+# 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,
+ nearestNeighbor)
+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,
+ nNearestNeighbor : int = -1) -> 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,
+ "NEARESTNEIGHBOR" : nearestNeighbor}[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)
+ if basis.upper() == "NEARESTNEIGHBOR":
+ if nNearestNeighbor > 0 and nNearestNeighbor < len(xSupp):
+ cutoffValue = np.partition(r2, nNearestNeighbor - 1)[0,
+ nNearestNeighbor - 1]
+ r2 /= cutoffValue
+ else:
+ r2[0, :] = 1. * (nNearestNeighbor == 0)
+ 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,
+ nNearestNeighbor : int = -1) -> Tuple[Np2D, Np2D]:
+ """
+ Compute full Hermite-Vandermonde matrix with specified derivative
+ directions.
+ """
+ basisp, basisr, _ = basis.split("_")
+ Weights = mlsweights(x, xSupp, basisr, reorder, directionalWeights,
+ nNearestNeighbor)
+ 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,
+ nNearestNeighbor : int = -1)\
+ -> Tuple[Np2D, Np2D, List[List[int]], List[int]]:
+ """
+ Compute full total degree Hermite-Vandermonde matrix with specified
+ derivative directions.
+ """
+ basisp, basisr, _ = basis.split("_")
+ Weights = mlsweights(x, xSupp, basisr, reorder, directionalWeights,
+ nNearestNeighbor)
+ VanP, derIdxs, ordIdxs = pvTP(x, deg, basisp, derIdxs = derIdxs,
+ reorder = reorder, scl = scl)
+ RHP = VanP.T.conj() * Weights
+ return RHP.dot(VanP), RHP, derIdxs, ordIdxs
diff --git a/rrompy/utilities/poly_fitting/polynomial/__init__.py b/rrompy/utilities/poly_fitting/polynomial/__init__.py
index 747c8b5..69a9d43 100644
--- a/rrompy/utilities/poly_fitting/polynomial/__init__.py
+++ b/rrompy/utilities/poly_fitting/polynomial/__init__.py
@@ -1,49 +1,40 @@
# 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 .base import (polybases, polyfitname, polydomcoeff)
from .der import polyder
from .val import polyval
from .marginalize import polymarginalize
-from .vander import polyvander
+from .vander import polyvander, polyvanderTotal
from .roots import polyroots
-from .derivative import nextDerivativeIndices
-from .hash_derivative import hashDerivativeToIdx, hashIdxToDerivative
-from .homogeneization import (homogeneizationMask, homogeneizedpolyvander,
- homogeneizedToFull)
from .polynomial_interpolator import PolynomialInterpolator
__all__ = [
'polybases',
'polyfitname',
'polydomcoeff',
'polyder',
'polyval',
'polymarginalize',
'polyvander',
+ 'polyvanderTotal',
'polyroots',
- 'nextDerivativeIndices',
- 'hashDerivativeToIdx',
- 'hashIdxToDerivative',
- 'homogeneizationMask',
- 'homogeneizedpolyvander',
- 'homogeneizedToFull',
'PolynomialInterpolator'
]
diff --git a/rrompy/utilities/poly_fitting/polynomial/hash_derivative.py b/rrompy/utilities/poly_fitting/polynomial/hash_derivative.py
deleted file mode 100644
index 17c1c8e..0000000
--- a/rrompy/utilities/poly_fitting/polynomial/hash_derivative.py
+++ /dev/null
@@ -1,45 +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 scipy.special import binom
-from rrompy.utilities.base.types import List
-
-__all__ = ['hashDerivativeToIdx', 'hashIdxToDerivative']
-
-def shellCount(shell:int, dim:int) -> int:
- return int(binom(shell + dim, dim))
-
-def hashDerivativeToIdx(derIdx:List[int]) -> int:
- dim = len(derIdx)
- if dim == 0: return 0
- derMag = sum(derIdx)
- base = shellCount(derMag - 1, dim)
- if derMag == derIdx[0]: return base
- return base + hashDerivativeToIdx(derIdx[1:])
-
-def hashIdxToDerivative(n:int, dim:int) -> List[int]:
- if n == 0: return [0] * dim
- shell = 0
- shellOld = -1
- shellNew = 1
- while shellNew <= n:
- shell += 1
- shellOld = shellNew
- shellNew = shellCount(shell, dim)
- rest = hashIdxToDerivative(n - shellOld, dim - 1)
- return [shell - sum(rest)] + rest
diff --git a/rrompy/utilities/poly_fitting/polynomial/homogeneization.py b/rrompy/utilities/poly_fitting/polynomial/homogeneization.py
deleted file mode 100644
index 97fa102..0000000
--- a/rrompy/utilities/poly_fitting/polynomial/homogeneization.py
+++ /dev/null
@@ -1,62 +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 rrompy.utilities.base.types import Np1D, Np2D, Tuple, List, paramList
-from rrompy.utilities.poly_fitting.polynomial import (polyvander,
- hashIdxToDerivative as hashI)
-from rrompy.parameter import checkParameterList
-
-__all__ = ['homogeneizationMask', 'homogeneizedpolyvander',
- 'homogeneizedToFull']
-
-def homogeneizationMask(degs:List[int]) -> Tuple[List[int], List[bool]]:
- dim = len(degs)
- N = np.prod([d + 1 for d in degs])
- maskN = np.arange(N, dtype = int)
- remN = np.zeros((N, dim), dtype = int)
- for j in range(dim - 1, -1, -1):
- remN[:, j] = maskN % (degs[j] + 1)
- maskN //= degs[j] + 1
- mask = np.sum(remN, axis = 1) <= min(degs)
- return remN[mask], mask
-
-def homogeneizedpolyvander(x:paramList, deg:int, basis:str,
- derIdxs : List[List[List[int]]] = None,
- reorder : List[int] = None, scl : Np1D = None)\
- -> Tuple[Np2D, List[List[int]], List[int]]:
- x = checkParameterList(x)[0]
- degs = [deg] * x.shape[1]
- VanBase = polyvander(x, degs, basis, derIdxs, reorder, scl)
- derIdxs, mask = homogeneizationMask(degs)
-
- ordIdxs = np.empty(len(derIdxs), dtype = int)
- derTotal = np.array([np.sum(y) for y in derIdxs])
- idxPrev = 0
- rangeAux = np.arange(len(derIdxs))
- for j in range(deg + 1):
- idxLocal = rangeAux[derTotal == j][::-1]
- idxPrev += len(idxLocal)
- ordIdxs[idxPrev - len(idxLocal) : idxPrev] = idxLocal
- return VanBase[:, mask], derIdxs, ordIdxs
-
-def homogeneizedToFull(shapeFull:Tuple[int], dim:int, coeffs:Np2D) -> Np2D:
- full = np.zeros(shapeFull, dtype = coeffs.dtype)
- for j in range(len(coeffs)):
- full[tuple(hashI(j, dim))] = coeffs[j]
- return full
diff --git a/rrompy/utilities/poly_fitting/polynomial/polynomial_interpolator.py b/rrompy/utilities/poly_fitting/polynomial/polynomial_interpolator.py
index 7c95b03..3b46e64 100644
--- a/rrompy/utilities/poly_fitting/polynomial/polynomial_interpolator.py
+++ b/rrompy/utilities/poly_fitting/polynomial/polynomial_interpolator.py
@@ -1,140 +1,131 @@
# 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.base import freepar as fp
from rrompy.utilities.poly_fitting.interpolator import GenericInterpolator
from rrompy.utilities.poly_fitting.custom_fit import customFit
-from rrompy.utilities.poly_fitting.polynomial.base import (polyfitname,
- polydomcoeff)
-from rrompy.utilities.poly_fitting.polynomial.val import polyval
-from rrompy.utilities.poly_fitting.polynomial.roots import polyroots
-from rrompy.utilities.poly_fitting.polynomial.homogeneization import (
- homogeneizedpolyvander as hpv,
- homogeneizedToFull)
-from rrompy.utilities.poly_fitting.polynomial.vander import polyvander as pv
+from .base import polyfitname
+from .val import polyval
+from .roots import polyroots
+from .vander import polyvander as pv, polyvanderTotal as pvT
+from rrompy.utilities.numerical import degreeTotalToFull, dot
from rrompy.utilities.exception_manager import RROMPyAssert, RROMPyException
from rrompy.parameter import checkParameterList
__all__ = ['PolynomialInterpolator']
class PolynomialInterpolator(GenericInterpolator):
"""HERE"""
def __init__(self, other = None):
if other is None: return
self.coeffs = other.coeffs
self.npar = other.npar
self.polybasis = other.polybasis
@property
def shape(self):
if self.coeffs.ndim > self.npar:
sh = self.coeffs.shape[self.npar :]
else: sh = tuple([1])
return sh
@property
def deg(self):
return [x - 1 for x in self.coeffs.shape[: self.npar]]
def __getitem__(self, key):
return self.coeffs[key]
def __call__(self, mu:paramList, der : List[int] = None,
scl : Np1D = None):
return polyval(mu, self.coeffs, self.polybasis, der, scl)
def __copy__(self):
return PolynomialInterpolator(self)
def __deepcopy__(self, memo):
other = PolynomialInterpolator()
other.coeffs, other.npar, other.polybasis = copy(
(self.coeffs, self.npar, self.polybasis), memo)
return other
- @property
- def domCoeff(self):
- RROMPyAssert(self.npar, 1, "Number of parameters")
- return polydomcoeff(self.deg, self.polybasis) * self[-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)] * self.npar
padwidth = padwidth + [(l, r) for l, r in zip(nleft, nright)]
self.coeffs = np.pad(self.coeffs, padwidth, "constant",
constant_values = (0., 0.))
def postmultiplyTensorize(self, A:Np2D):
RROMPyAssert(A.shape[0], self.shape[-1], "Shape of output")
- self.coeffs = np.tensordot(self.coeffs, A, axes = (-1, 0))
+ self.coeffs = dot(self.coeffs, A)
def setupByInterpolation(self, support:paramList, values:ListAny,
deg:int, polybasis : str = "MONOMIAL",
- verbose : bool = True, homogeneized : bool = True,
+ verbose : bool = True, totalDegree : bool = True,
vanderCoeffs : DictAny = {},
fitCoeffs : DictAny = {}):
support = checkParameterList(support)[0]
self.npar = support.shape[1]
self.polybasis = polybasis
- if homogeneized:
- vander, _, reorder = hpv(support, deg, basis = polybasis,
+ if totalDegree:
+ vander, _, reorder = pvT(support, deg, basis = polybasis,
**vanderCoeffs)
vander = vander[:, reorder]
else:
if not hasattr(deg, "__len__"): deg = [deg] * self.npar
vander = pv(support, deg, basis = polybasis, **vanderCoeffs)
outDim = values.shape[1:]
values = values.reshape(values.shape[0], -1)
fitOut = customFit(vander, values, full = True, **fitCoeffs)
P = fitOut[0]
if verbose:
msg = ("Fitting {} samples with degree {} through {}... "
"Conditioning of LS system: {:.4e}.").format(
len(vander), deg,
polyfitname(self.polybasis),
fitOut[1][2][0] / fitOut[1][2][-1])
else: msg = None
- if homogeneized:
- self.coeffs = homogeneizedToFull(
- tuple([deg + 1] * self.npar) + outDim,
- self.npar, P)
+ if totalDegree:
+ self.coeffs = degreeTotalToFull(tuple([deg + 1] * self.npar)
+ + outDim, self.npar, P)
else:
self.coeffs = P.reshape(tuple([d + 1 for d in deg]) + outDim)
return fitOut[1][1] == vander.shape[1], msg
def roots(self, marginalVals : ListAny = [fp]):
RROMPyAssert(self.shape, (1,), "Shape of output")
RROMPyAssert(len(marginalVals), self.npar, "Number of parameters")
try:
rDim = marginalVals.index(fp)
if rDim < len(marginalVals) - 1 and fp in marginalVals[rDim + 1 :]:
raise
except:
raise RROMPyException(("Exactly 1 'freepar' entry in "
"marginalVals must be provided."))
return polyroots(self.coeffs, self.polybasis, marginalVals)
diff --git a/rrompy/utilities/poly_fitting/polynomial/val.py b/rrompy/utilities/poly_fitting/polynomial/val.py
index c54463d..0727be3 100644
--- a/rrompy/utilities/poly_fitting/polynomial/val.py
+++ b/rrompy/utilities/poly_fitting/polynomial/val.py
@@ -1,43 +1,43 @@
# 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.utilities.poly_fitting.polynomial import polyder
+from .der import polyder
from rrompy.utilities.base.types import Np1D, Np2D, List, paramList
from rrompy.parameter import checkParameterList
from rrompy.utilities.exception_manager import RROMPyException
__all__ = ['polyval']
def polyval(x:paramList, c:Np2D, basis:str, m : List[int] = None,
scl : Np1D = None) -> Np2D:
c = polyder(c, basis, m = m, scl = scl)
x = checkParameterList(x)[0]
if x.shape[1] > c.ndim:
raise RROMPyException("Incompatible parameter number.")
try:
polyvalbase = {"CHEBYSHEV" : np.polynomial.chebyshev.chebval,
"LEGENDRE" : np.polynomial.legendre.legval,
"MONOMIAL" : np.polynomial.polynomial.polyval
}[basis.upper()]
except:
raise RROMPyException("Polynomial basis not recognized.")
c = polyvalbase(x(0), c, tensor = True)
for d in range(1, x.shape[1]):
c = polyvalbase(x(d), c, tensor = False)
return c
diff --git a/rrompy/utilities/poly_fitting/polynomial/vander.py b/rrompy/utilities/poly_fitting/polynomial/vander.py
index 097b738..4f20015 100644
--- a/rrompy/utilities/poly_fitting/polynomial/vander.py
+++ b/rrompy/utilities/poly_fitting/polynomial/vander.py
@@ -1,114 +1,138 @@
# 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.utilities.poly_fitting.polynomial import polyder
-from rrompy.utilities.base.types import Np1D, Np2D, List, paramList
+from .der import polyder
+from rrompy.utilities.base.types import Np1D, Np2D, Tuple, List, paramList
+from rrompy.utilities.numerical import totalDegreeSet
from rrompy.parameter import checkParameterList
from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
-__all__ = ['polyvander']
+__all__ = ['polyvander', 'polyvanderTotal']
def firstDerTransition(dim:int, TDirac:List[Np2D], basis:str,
scl : Np1D = None) -> Np2D:
C_m = np.zeros((dim, len(TDirac), len(TDirac)), dtype = float)
for j, Tj in enumerate(TDirac):
m, om = [0] * dim, [(0, 0)] * dim
for idx in range(dim):
m[idx], om[idx] = 1, (0, 1)
J_der = polyder(Tj, basis, m, scl)
C_m[idx, :, j] = np.ravel(np.pad(J_der, mode = "constant",
pad_width = om))
m[idx], om[idx] = 0, (0, 0)
return C_m
def countDerDirections(n:int, base:int, digits:int, idx:int):
if digits == 0: return []
dig = n % base
return [(idx, dig)] * (dig > 0) + countDerDirections(
(n - dig) // base, base, digits - 1, idx + 1)
def polyvander(x:paramList, degs:List[int], basis:str,
derIdxs : List[List[List[int]]] = None,
reorder : List[int] = None, scl : Np1D = None) -> Np2D:
"""
- Compute Hermite-Vandermonde matrix with specified derivative directions.
+ Compute full Hermite-Vandermonde matrix with specified derivative
+ directions.
E.g. assume that we want to obtain the Vandermonde matrix for
(value, derx, derx2) at x = [0, 0],
(value, dery) at x = [1, 0],
(dery, derxy) at x = [0, 0],
of degree 3 in x and 1 in y, using Chebyshev polynomials.
This can be done by
polyvander([[0, 0], [1, 0]], # unique sample points
[3, 1], # polynomial degree
"chebyshev", # polynomial family
[
[[0, 0], [1, 0], [2, 0], [0, 1], [1, 1]],
# derivative directions at first point
[[0, 0], [0, 1]] # derivative directions at second point
],
[0, 1, 2, 5, 6, 3, 4] # reorder indices
)
"""
if not isinstance(degs, (list,tuple,np.ndarray,)): degs = [degs]
dim = len(degs)
x = checkParameterList(x, dim)[0]
x_un, idx_un = x.unique(return_inverse = True)
if len(x_un) < len(x):
raise RROMPyException("Sample points must be distinct.")
del x_un
try:
vanderbase = {"CHEBYSHEV" : np.polynomial.chebyshev.chebvander,
"LEGENDRE" : np.polynomial.legendre.legvander,
"MONOMIAL" : np.polynomial.polynomial.polyvander
}[basis.upper()]
except:
raise RROMPyException("Polynomial basis not recognized.")
VanBase = vanderbase(x(0), degs[0])
for j in range(1, dim):
VNext = vanderbase(x(j), degs[j])
for jj in range(j): VNext = np.expand_dims(VNext, 1)
VanBase = VanBase[..., None] * VNext
VanBase = VanBase.reshape((len(x), -1))
if derIdxs is None or VanBase.shape[-1] <= 1:
Van = VanBase
else:
derFlat, idxRep = [], []
for j, derIdx in enumerate(derIdxs):
derFlat += derIdx[:]
idxRep += [j] * len(derIdx[:])
for j in range(len(derFlat)):
if not hasattr(derFlat[j], "__len__"):
derFlat[j] = [derFlat[j]]
RROMPyAssert(len(derFlat[j]), dim, "Number of dimensions")
TDirac = [y.reshape([d + 1 for d in degs])
for y in np.eye(VanBase.shape[-1], dtype = int)]
Cs_loc = firstDerTransition(dim, TDirac, basis, scl)
Van = np.empty((len(derFlat), VanBase.shape[-1]),
dtype = VanBase.dtype)
for j in range(len(derFlat)):
Van[j, :] = VanBase[idxRep[j], :]
for k in range(dim):
for der in range(derFlat[j][k]):
Van[j, :] = Van[j, :].dot(Cs_loc[k]) / (der + 1)
if reorder is not None: Van = Van[reorder, :]
return Van
+
+def polyvanderTotal(x:paramList, deg:int, basis:str,
+ derIdxs : List[List[List[int]]] = None,
+ reorder : List[int] = None, scl : Np1D = None)\
+ -> Tuple[Np2D, List[List[int]], List[int]]:
+ """
+ Compute full total degree Hermite-Vandermonde matrix with specified
+ derivative directions.
+ """
+ x = checkParameterList(x)[0]
+ degs = [deg] * x.shape[1]
+ VanBase = polyvander(x, degs, basis, derIdxs, reorder, scl)
+ derIdxs, mask = totalDegreeSet(deg, x.shape[1], return_mask = True)
+ ordIdxs = np.empty(len(derIdxs), dtype = int)
+ derTotal = np.array([np.sum(y) for y in derIdxs])
+ idxPrev = 0
+ rangeAux = np.arange(len(derIdxs))
+ for j in range(deg + 1):
+ idxLocal = rangeAux[derTotal == j][::-1]
+ idxPrev += len(idxLocal)
+ ordIdxs[idxPrev - len(idxLocal) : idxPrev] = idxLocal
+ return VanBase[:, mask], derIdxs, ordIdxs
diff --git a/rrompy/utilities/poly_fitting/radial_basis/__init__.py b/rrompy/utilities/poly_fitting/radial_basis/__init__.py
index 108132b..c660671 100644
--- a/rrompy/utilities/poly_fitting/radial_basis/__init__.py
+++ b/rrompy/utilities/poly_fitting/radial_basis/__init__.py
@@ -1,41 +1,42 @@
# 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
+from .kernel import (radialGaussian, thinPlateSpline, multiQuadric,
+ nearestNeighbor)
from .base import rbbases, polybases, polyfitname, polydomcoeff
from .val import polyval
-from .vander import rbvander, polyvander
-from .homogeneization import homogeneizedpolyvander
+from .vander import rbvander, polyvander, polyvanderTotal
from .radial_basis_interpolator import RadialBasisInterpolator
__all__ = [
'radialGaussian',
'thinPlateSpline',
'multiQuadric',
+ 'nearestNeighbor',
'rbbases',
'polybases',
'polyfitname',
'polydomcoeff',
'polyval',
'rbvander',
'polyvander',
- 'homogeneizedpolyvander',
+ 'polyvanderTotal',
'RadialBasisInterpolator'
]
diff --git a/rrompy/utilities/poly_fitting/radial_basis/base.py b/rrompy/utilities/poly_fitting/radial_basis/base.py
index a31ebfb..29c4ba6 100644
--- a/rrompy/utilities/poly_fitting/radial_basis/base.py
+++ b/rrompy/utilities/poly_fitting/radial_basis/base.py
@@ -1,44 +1,44 @@
# 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 itertools import product
-from rrompy.utilities.base.types import Np1D, Np2D, paramList
from rrompy.utilities.exception_manager import RROMPyException
from rrompy.utilities.poly_fitting.polynomial.base import (polybases as pbP,
polyfitname as pfnP,
polydomcoeff as polydomcoeffB)
__all__ = ['rbbases', 'polybases', 'polyfitname', 'polydomcoeff']
-rbbases = ["GAUSSIAN", "THINPLATE", "MULTIQUADRIC"]
+rbbases = ["GAUSSIAN", "THINPLATE", "MULTIQUADRIC", "NEARESTNEIGHBOR"]
polybases = [x + "_" + y for x, y in product(pbP, rbbases)]
def polyfitname(basis:str) -> str:
fitrnames = {"GAUSSIAN" : "gaussian", "THINPLATE" : "thinplate",
- "MULTIQUADRIC" : "multiquadric"}
+ "MULTIQUADRIC" : "multiquadric",
+ "NEARESTNEIGHBOR" : "nearestneighbor"}
basisp, basisr = basis.split("_")
try:
return pfnP(basisp) + "_" + fitrnames[basisr]
except:
raise RROMPyException("Polynomial-radial basis combination not "
"recognized.")
def polydomcoeff(n:int, basis:str) -> float:
return polydomcoeffB(n, basis.split("_")[0])
diff --git a/rrompy/utilities/poly_fitting/radial_basis/homogeneization.py b/rrompy/utilities/poly_fitting/radial_basis/homogeneization.py
deleted file mode 100644
index c3769d2..0000000
--- a/rrompy/utilities/poly_fitting/radial_basis/homogeneization.py
+++ /dev/null
@@ -1,49 +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 rrompy.utilities.base.types import Np1D, Np2D, Tuple, List, paramList
-from rrompy.utilities.poly_fitting.polynomial.homogeneization import (
- homogeneizedpolyvander as hpvP)
-from rrompy.utilities.exception_manager import RROMPyException
-from .vander import rbvander
-
-__all__ = ['homogeneizedpolyvander']
-
-def homogeneizedpolyvander(x:paramList, deg:int, basis:str,
- derIdxs : List[List[List[int]]] = None,
- reorder : List[int] = None,
- directionalWeights : Np1D = None,
- scl : Np1D = None)\
- -> Tuple[Np2D, List[List[int]], List[int]]:
- """
- Compute radial-basis-inclusive homogeneized Hermite-Vandermonde matrix with
- specified derivative directions.
- """
- if derIdxs is not None and np.sum(np.sum(derIdxs)) > 0:
- raise RROMPyException(("Cannot take derivatives of radial basis "
- "function."))
- basisp, basisr = basis.split("_")
- VanR = rbvander(x, basisr, reorder = reorder,
- directionalWeights = directionalWeights)
- VanP, derIdxs, ordIdxs = hpvP(x, deg, basisp, derIdxs = derIdxs,
- reorder = reorder, scl = scl)
- ordIdxsEff = np.concatenate((np.arange(len(VanR)), ordIdxs + len(VanR)))
- return (np.block([[VanR, VanP],
- [VanP.T.conj(), np.zeros(tuple([VanP.shape[1]] * 2))]]),
- derIdxs, ordIdxsEff)
diff --git a/rrompy/utilities/poly_fitting/radial_basis/kernel.py b/rrompy/utilities/poly_fitting/radial_basis/kernel.py
index d0e1db2..d51bddb 100644
--- a/rrompy/utilities/poly_fitting/radial_basis/kernel.py
+++ b/rrompy/utilities/poly_fitting/radial_basis/kernel.py
@@ -1,35 +1,40 @@
# 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.utilities.base.types import Np1D
from rrompy.utilities.exception_manager import RROMPyAssert
-__all__ = ['radialGaussian', 'thinPlateSpline', 'multiQuadric']
+__all__ = ['radialGaussian', 'thinPlateSpline', 'multiQuadric',
+ 'nearestNeighbor']
def radialGaussian(r2:Np1D, der : int = 0) -> Np1D:
RROMPyAssert(der, 0, "Radial basis derivative")
return np.exp(- .5 * r2)
def thinPlateSpline(r2:Np1D, der : int = 0) -> Np1D:
RROMPyAssert(der, 0, "Radial basis derivative")
return .5 * r2 * np.log(np.finfo(float).eps + r2)
def multiQuadric(r2:Np1D, der : int = 0) -> Np1D:
RROMPyAssert(der, 0, "Radial basis derivative")
return np.power(r2 + 1., -.5)
+
+def nearestNeighbor(r2:Np1D, der : int = 0) -> Np1D:
+ RROMPyAssert(der, 0, "Radial basis derivative")
+ return 1. * (r2 <= 1.)
diff --git a/rrompy/utilities/poly_fitting/radial_basis/radial_basis_interpolator.py b/rrompy/utilities/poly_fitting/radial_basis/radial_basis_interpolator.py
index 7d8593f..e1e0023 100644
--- a/rrompy/utilities/poly_fitting/radial_basis/radial_basis_interpolator.py
+++ b/rrompy/utilities/poly_fitting/radial_basis/radial_basis_interpolator.py
@@ -1,141 +1,147 @@
# 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.poly_fitting.interpolator import GenericInterpolator
from rrompy.utilities.poly_fitting.custom_fit import customFit
-from rrompy.utilities.poly_fitting.radial_basis.base import polyfitname
-from rrompy.utilities.poly_fitting.radial_basis.val import polyval
-from rrompy.utilities.poly_fitting.radial_basis.homogeneization import (
- homogeneizedpolyvander as hpv)
-from rrompy.utilities.poly_fitting.radial_basis.vander import polyvander as pv
-from rrompy.utilities.poly_fitting.polynomial.homogeneization import (
- homogeneizedToFull)
+from .base import polyfitname
+from .val import polyval
+from .vander import polyvander as pv, polyvanderTotal as pvT
+from rrompy.utilities.numerical import degreeTotalToFull, dot
from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
from rrompy.parameter import checkParameterList
__all__ = ['RadialBasisInterpolator']
class RadialBasisInterpolator(GenericInterpolator):
"""HERE"""
def __init__(self, other = None):
if other is None: return
self.support = other.support
self.coeffsGlobal = other.coeffsGlobal
self.coeffsLocal = other.coeffsLocal
self.directionalWeights = other.directionalWeights
self.npar = other.npar
self.polybasis = other.polybasis
+ self.nNearestNeighbor = other.nNearestNeighbor
@property
def shape(self):
sh = self.coeffsLocal.shape[1 :] if self.coeffsLocal.ndim > 1 else 1
return sh
@property
def deg(self):
return [x - 1 for x in self.coeffsGlobal.shape[: self.npar]]
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 radial basis "
"function."))
return polyval(mu, self.coeffsGlobal, self.coeffsLocal, self.support,
- self.directionalWeights, self.polybasis)
+ self.directionalWeights, self.polybasis,
+ self.nNearestNeighbor)
def __copy__(self):
return RadialBasisInterpolator(self)
def __deepcopy__(self, memo):
other = RadialBasisInterpolator()
(other.support, other.coeffsGlobal, other.coeffsLocal,
- other.directionalWeights, other.npar, other.polybasis) = copy(
- (self.support, self.coeffsGlobal, self.coeffsLocal,
- self.directionalWeights, self.npar, self.polybasis), memo)
+ other.directionalWeights, other.npar, other.polybasis,
+ other.nNearestNeighbor) = copy(
+ (self.support, self.coeffsGlobal, self.coeffsLocal,
+ self.directionalWeights, self.npar, self.polybasis,
+ self.nNearestNeighbor), memo)
return other
def postmultiplyTensorize(self, A:Np2D):
RROMPyAssert(A.shape[0], self.shape[-1], "Shape of output")
- self.coeffsLocal = np.tensordot(self.coeffsLocal, A, axes = (-1, 0))
- self.coeffsGlobal = np.tensordot(self.coeffsGlobal, A, axes = (-1, 0))
+ self.coeffsLocal = dot(self.coeffsLocal, A)
+ self.coeffsGlobal = dot(self.coeffsGlobal, A)
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.coeffsLocal = np.pad(self.coeffsLocal, padwidth, "constant",
constant_values = (0., 0.))
padwidth = [(0, 0)] * (self.npar - 1) + padwidth
self.coeffsGlobal = np.pad(self.coeffsGlobal, padwidth, "constant",
constant_values = (0., 0.))
def setupByInterpolation(self, support:paramList, values:ListAny,
deg:int, polybasis : str = "MONOMIAL_GAUSSIAN",
directionalWeights : Np1D = None,
- verbose : bool = True, homogeneized : bool = True,
+ verbose : bool = True, totalDegree : bool = True,
vanderCoeffs : DictAny = {},
fitCoeffs : DictAny = {}):
support = checkParameterList(support)[0]
self.support = copy(support)
if "reorder" in vanderCoeffs.keys():
self.support = self.support[vanderCoeffs["reorder"]]
+ if "nNearestNeighbor" in vanderCoeffs.keys():
+ self.nNearestNeighbor = vanderCoeffs["nNearestNeighbor"]
+ else:
+ self.nNearestNeighbor = -1
self.npar = support.shape[1]
if directionalWeights is None:
directionalWeights = np.ones(self.npar)
self.directionalWeights = directionalWeights
self.polybasis = polybasis
- if homogeneized:
- vander, _, reorder = hpv(support, deg, basis = polybasis,
+ if totalDegree:
+ vander, _, reorder = pvT(support, deg, basis = polybasis,
directionalWeights = self.directionalWeights,
**vanderCoeffs)
vander = vander[reorder]
vander = vander[:, reorder]
else:
if not hasattr(deg, "__len__"): deg = [deg] * self.npar
- vander = pv(support, deg, basis = polybasis, **vanderCoeffs)
+ vander = pv(support, deg, basis = polybasis,
+ directionalWeights = self.directionalWeights,
+ **vanderCoeffs)
outDim = values.shape[1:]
values = values.reshape(values.shape[0], -1)
values = np.pad(values, ((0, len(vander) - len(values)), (0, 0)),
"constant")
fitOut = customFit(vander, values, full = True, **fitCoeffs)
P = fitOut[0][len(support) :]
if verbose:
msg = ("Fitting {}+{} samples with degree {} through {}... "
"Conditioning of LS system: {:.4e}.").format(
len(support), len(vander) - len(support),
deg, polyfitname(self.polybasis),
fitOut[1][2][0] / fitOut[1][2][-1])
else: msg = None
self.coeffsLocal = fitOut[0][: len(support)]
- if homogeneized:
- self.coeffsGlobal = homogeneizedToFull(
- tuple([deg + 1] * self.npar) + outDim,
- self.npar, P)
+ if totalDegree:
+ self.coeffsGlobal = degreeTotalToFull(tuple([deg + 1] * self.npar)
+ + outDim, self.npar, P)
else:
self.coeffsGlobal = P.reshape(tuple([d + 1 for d in deg]) + outDim)
return fitOut[1][1] == vander.shape[1], msg
diff --git a/rrompy/utilities/poly_fitting/radial_basis/val.py b/rrompy/utilities/poly_fitting/radial_basis/val.py
index d0a334f..170e821 100644
--- a/rrompy/utilities/poly_fitting/radial_basis/val.py
+++ b/rrompy/utilities/poly_fitting/radial_basis/val.py
@@ -1,52 +1,62 @@
# 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 .kernel import (radialGaussian, thinPlateSpline, multiQuadric,
+ nearestNeighbor)
+from rrompy.utilities.poly_fitting.polynomial.val import polyval as pvP
from rrompy.utilities.base.types import Np1D, Np2D, paramList
from rrompy.parameter import checkParameterList
from rrompy.utilities.exception_manager import RROMPyException
-from rrompy.utilities.poly_fitting.polynomial import polyval as pvP
-from .kernel import radialGaussian, thinPlateSpline, multiQuadric
__all__ = ['polyval']
def polyval(x:paramList, cG:Np2D, cL:Np2D, supportPoints:paramList,
- directionalWeights:Np1D, basis:str) -> Np2D:
+ directionalWeights:Np1D, basis:str,
+ nNearestNeighbor : int = -1) -> Np2D:
x = checkParameterList(x)[0]
basisp, basisr = basis.split("_")
c = pvP(x, cG, basisp)
try:
radialvalbase = {"GAUSSIAN" : radialGaussian,
"THINPLATE" : thinPlateSpline,
- "MULTIQUADRIC" : multiQuadric
- }[basisr.upper()]
+ "MULTIQUADRIC" : multiQuadric,
+ "NEARESTNEIGHBOR" : nearestNeighbor}[basisr.upper()]
except:
raise RROMPyException("Radial basis not recognized.")
+ isnearestneighbor = basisr.upper() == "NEARESTNEIGHBOR"
csh = copy(c.shape)
if len(csh) == 1: c = c.reshape(1, -1)
for j in range(len(x)):
muDiff = (supportPoints.data - x[j]) * directionalWeights
r2j = np.sum(np.abs(muDiff) ** 2., axis = 1).reshape(1, -1)
+ if isnearestneighbor:
+ if nNearestNeighbor > 0 and nNearestNeighbor < len(supportPoints):
+ cutoffValue = np.partition(r2j, nNearestNeighbor - 1)[0,
+ nNearestNeighbor - 1]
+ r2j /= cutoffValue
+ else:
+ r2j[0, :] = 1. * (nNearestNeighbor == 0)
val = radialvalbase(r2j).dot(cL)
try:
c[..., j] += val
except:
c[..., j] += val.flatten()
if len(csh) == 1: c = c.flatten()
return c
diff --git a/rrompy/utilities/poly_fitting/radial_basis/vander.py b/rrompy/utilities/poly_fitting/radial_basis/vander.py
index d1cf051..9738162 100644
--- a/rrompy/utilities/poly_fitting/radial_basis/vander.py
+++ b/rrompy/utilities/poly_fitting/radial_basis/vander.py
@@ -1,79 +1,111 @@
# 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.utilities.poly_fitting.polynomial.vander import polyvander as pvP
-from rrompy.utilities.base.types import Np1D, Np2D, List, paramList
+from .kernel import (radialGaussian, thinPlateSpline, multiQuadric,
+ nearestNeighbor)
+from rrompy.utilities.poly_fitting.polynomial.vander import (polyvander as pvP,
+ polyvanderTotal as pvTP)
+from rrompy.utilities.base.types import Np1D, Np2D, Tuple, List, paramList
from rrompy.parameter import checkParameterList
from rrompy.utilities.exception_manager import RROMPyException, RROMPyAssert
-from .kernel import radialGaussian, thinPlateSpline, multiQuadric
-__all__ = ['rbvander', 'polyvander']
+__all__ = ['rbvander', 'polyvander', 'polyvanderTotal']
def rbvander(x:paramList, basis:str, reorder : List[int] = None,
- directionalWeights : Np1D = None) -> Np2D:
+ directionalWeights : Np1D = None,
+ nNearestNeighbor : int = -1) -> Np2D:
"""Compute radial-basis-Vandermonde matrix."""
x = checkParameterList(x)[0]
x_un = x.unique()
nx = len(x)
if len(x_un) < nx:
raise RROMPyException("Sample points must be distinct.")
del x_un
x = x.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
- }[basis.upper()]
+ "MULTIQUADRIC" : multiQuadric,
+ "NEARESTNEIGHBOR" : nearestNeighbor}[basis.upper()]
except:
raise RROMPyException("Radial basis not recognized.")
- r2 = np.zeros((nx * (nx - 1) // 2 + 1), dtype = float)
- idxInv = np.zeros(nx ** 2, dtype = int)
- if reorder is not None: x = x[reorder]
+ isnearestneighbor = basis.upper() == "NEARESTNEIGHBOR"
+ Van = np.zeros((nx, nx))
for j in range(nx):
- idx = j * (nx - 1) - j * (j + 1) // 2
- II = np.arange(j + 1, nx)
- r2[idx + II] = np.sum(np.abs((x[II] - x[j])
- * directionalWeights) ** 2., axis = 1)
- idxInv[j * nx + II] = idx + II
- idxInv[II * nx + j] = idx + II
- Van = radialkernel(r2)[idxInv].reshape((nx, nx))
+ muDiff = (x.data - x[j]) * directionalWeights
+ r2j = np.sum(np.abs(muDiff) ** 2., axis = 1).reshape(1, -1)
+ if isnearestneighbor:
+ if nNearestNeighbor > 0 and nNearestNeighbor < len(x):
+ cutoffValue = np.partition(r2j, nNearestNeighbor - 1)[0,
+ nNearestNeighbor - 1]
+ r2j /= cutoffValue
+ else:
+ r2j[0, :] = 1. * (nNearestNeighbor == 0)
+ Van[j] = radialkernel(r2j)
return Van
def polyvander(x:paramList, degs:List[int], basis:str,
derIdxs : List[List[List[int]]] = None,
reorder : List[int] = None, directionalWeights : Np1D = None,
- scl : Np1D = None) -> Np2D:
+ scl : Np1D = None, nNearestNeighbor : int = -1) -> Np2D:
"""
- Compute radial-basis-inclusive Hermite-Vandermonde matrix with specified
- derivative directions.
+ Compute full Hermite-Vandermonde matrix with specified derivative
+ directions.
"""
if derIdxs is not None and np.sum(np.sum(derIdxs)) > 0:
raise RROMPyException(("Cannot take derivatives of radial basis "
"function."))
basisp, basisr = basis.split("_")
VanR = rbvander(x, basisr, reorder = reorder,
- directionalWeights = directionalWeights)
+ directionalWeights = directionalWeights,
+ nNearestNeighbor = nNearestNeighbor)
VanP = pvP(x, degs, basisp, derIdxs = derIdxs, reorder = reorder,
scl = scl)
return np.block([[VanR, VanP],
[VanP.T.conj(), np.zeros(tuple([VanP.shape[1]] * 2))]])
+
+def polyvanderTotal(x:paramList, deg:int, basis:str,
+ derIdxs : List[List[List[int]]] = None,
+ reorder : List[int] = None,
+ directionalWeights : Np1D = None, scl : Np1D = None,
+ nNearestNeighbor : int = -1)\
+ -> Tuple[Np2D, List[List[int]], List[int]]:
+ """
+ Compute full total degree Hermite-Vandermonde matrix with specified
+ derivative directions.
+ """
+ if derIdxs is not None and np.sum(np.sum(derIdxs)) > 0:
+ raise RROMPyException(("Cannot take derivatives of radial basis "
+ "function."))
+ basisp, basisr = basis.split("_")
+ VanR = rbvander(x, basisr, reorder = reorder,
+ directionalWeights = directionalWeights,
+ nNearestNeighbor = nNearestNeighbor)
+ VanP, derIdxs, ordIdxs = pvTP(x, deg, basisp, derIdxs = derIdxs,
+ reorder = reorder, scl = scl)
+ ordIdxsEff = np.concatenate((np.arange(len(VanR)), ordIdxs + len(VanR)))
+ return (np.block([[VanR, VanP],
+ [VanP.T.conj(), np.zeros(tuple([VanP.shape[1]] * 2))]]),
+ derIdxs, ordIdxsEff)
diff --git a/setup.py b/setup.py
index 8db4eb6..931fdd3 100644
--- a/setup.py
+++ b/setup.py
@@ -1,52 +1,52 @@
# 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 os
from setuptools import find_packages, setup
rrompy_directory = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
#rrompy_directory = os.path.join(rrompy_directory, 'rrompy')
setup(name="RROMPy",
description="Rational reduced order modelling in Python",
long_description="Rational reduced order modelling in Python",
author="Davide Pradovera",
author_email="davide.pradovera@epfl.ch",
- version="1.7.1",
+ version="1.8",
license="GNU Library or Lesser General Public License (LGPL)",
classifiers=[
"Development Status :: 1 - Planning"
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Topic :: Scientific/Engineering :: Mathematics",
"Topic :: Software Development :: Libraries :: Python Modules",
],
packages=find_packages(rrompy_directory),
setup_requires=[
"pytest-runner"
],
tests_require=[
"pytest"
],
zip_safe=False
)
diff --git a/tests/hfengines/fracture.py b/tests/hfengines/fracture.py
index a7624a2..576f130 100644
--- a/tests/hfengines/fracture.py
+++ b/tests/hfengines/fracture.py
@@ -1,59 +1,58 @@
# 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 pytest
import numpy as np
import ufl
import fenics as fen
from rrompy.hfengines.linear_problem.bidimensional import \
MembraneFractureEngine as MFE
from rrompy.hfengines.linear_problem import MembraneFractureEngineNoDomain \
as MFEND
from rrompy.solver.fenics import affine_warping
@pytest.mark.xfail(reason = "no graphical interface")
def test_fracture():
mu0 = [45. ** .5, .6]
solver2 = MFE(mu0 = mu0, H = 1., L = .75, delta = .05, n = 20,
verbosity = 0)
uh2 = solver2.solve(mu0)[0]
solver1 = MFEND(mu0 = mu0, H = 1., L = .75, delta = .05, n = 20,
verbosity = 0)
uh1 = solver1.solve(mu0[0])[0]
L = mu0[1]
y = fen.SpatialCoordinate(solver1.V.mesh())[1]
warp1, warpI1 = affine_warping(solver1.V.mesh(),
np.array([[1, 0], [0, 2. * L]]))
warp2, warpI2 = affine_warping(solver1.V.mesh(),
np.array([[1, 0], [0, 2. - 2. * L]]))
warp = ufl.conditional(ufl.ge(y, 0.), warp1, warp2)
warpI = ufl.conditional(ufl.ge(y, 0.), warpI1, warpI2)
solver1.plotmesh([warp, warpI], show = False, figsize = (7, 7))
solver1.plot(uh1, [warp, warpI], what = 'REAL', show = False)
from matplotlib import pyplot as plt
plt.close('all')
assert np.isclose(
- solver1.norm(solver1.residual(uh1, mu0[0]), dual = True)[0],
- solver2.norm(solver2.residual(uh2, mu0), dual = True)[0],
+ solver1.norm(solver1.residual(mu0[0], uh1), dual = True)[0],
+ solver2.norm(solver2.residual(mu0, uh2), dual = True)[0],
atol = 1e-5)
assert np.isclose(solver1.norm(uh1 - uh2), 0., atol = 1e-6)
-
diff --git a/tests/hfengines/helmholtz_elasticity.py b/tests/hfengines/helmholtz_elasticity.py
index 6d3279c..1ced33e 100644
--- a/tests/hfengines/helmholtz_elasticity.py
+++ b/tests/hfengines/helmholtz_elasticity.py
@@ -1,69 +1,58 @@
# 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.hfengines.vector_linear_problem import (
LinearElasticityHelmholtzProblemEngine,
- LinearElasticityHelmholtzProblemEngineDamped,
- LinearElasticityHelmholtzArchwayFrequency)
+ LinearElasticityHelmholtzProblemEngineDamped)
from rod_3d import rod3Dsolver
-def test_helmholtz_elastic_arch():
- solver = LinearElasticityHelmholtzArchwayFrequency(kappa = 10, n = 30,
- rho_ = 1e4, T = 1e5, lambda_ = 4e6, mu_ = 7e5,
- R = 2e1, r = 1.5e1, verbosity = 0)
- mu = 10
- uh = solver.solve(mu)[0]
- assert np.isclose(solver.norm(uh), 3188.9960782143194, rtol = 1e-5)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
- 3.6771479e-12, rtol = 1e-1)
-
def test_helmholtz_elastic_rod():
solverBase = rod3Dsolver()
solver = LinearElasticityHelmholtzProblemEngine()
solver.V = solverBase.V
solver.lambda_ = solverBase.lambda_
solver.mu_ = solverBase.mu_
solver.forcingTerm = solverBase.forcingTerm
solver.DirichletBoundary = solverBase.DirichletBoundary
solver.NeumannBoundary = solverBase.NeumannBoundary
mu = 10
uh = solver.solve(mu)[0]
assert np.isclose(solver.norm(uh), 0.17836028624665373, rtol = 1e-5)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
8.070977e-07, rtol = 1e-1)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
- solver.norm(solver.residual(uh, mu, duality = False)[0],
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
+ solver.norm(solver.residual(mu, uh, duality = False)[0],
dual = True, duality = False), rtol = 1e-1)
def test_helmholtz_elastic_rod_damped():
solverBase = rod3Dsolver()
solver = LinearElasticityHelmholtzProblemEngineDamped()
solver.V = solverBase.V
solver.lambda_ = solverBase.lambda_
solver.mu_ = solverBase.mu_
solver.forcingTerm = solverBase.forcingTerm
solver.DirichletBoundary = solverBase.DirichletBoundary
solver.NeumannBoundary = solverBase.NeumannBoundary
solver.eta = 10
mu = 10
uh = solver.solve(mu)[0]
assert np.isclose(solver.norm(uh), 0.17646530119044376, rtol = 1e-2)
- assert np.isclose(solver.norm(solver.residual(uh, 10)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(10, uh)[0], dual = True),
6.7057338e-07, rtol = 1e-1)
diff --git a/tests/hfengines/helmholtz_external.py b/tests/hfengines/helmholtz_external.py
index 3e74d16..c126c9f 100644
--- a/tests/hfengines/helmholtz_external.py
+++ b/tests/hfengines/helmholtz_external.py
@@ -1,69 +1,71 @@
# 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 pytest
import numpy as np
from rrompy.hfengines.linear_problem import (
HelmholtzCavityScatteringProblemEngine, HelmholtzBoxScatteringProblemEngine)
def test_helmholtz_square_scattering():
solver = HelmholtzCavityScatteringProblemEngine(kappa = 4, gamma = 2.,
n = 20, verbosity = 0)
mu = 5
uh = solver.solve(mu)[0]
assert np.isclose(solver.norm(uh), 19.9362, rtol = 1e-2)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
4.25056407e-13, rtol = 1e-1)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
- solver.norm(solver.residual(uh, mu, duality = False)[0],
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
+ solver.norm(solver.residual(mu, uh, duality = False)[0],
dual = True, duality = False), rtol = 1e-1)
def test_helmholtz_scattering_copy(capsys):
solver1 = HelmholtzCavityScatteringProblemEngine(kappa = 4, gamma = 2.,
n = 20, verbosity = 0)
mu = 5
uh1 = solver1.solve(mu)[0]
solver2 = HelmholtzCavityScatteringProblemEngine(kappa = 4, gamma = 2.,
n = 20, verbosity = 100)
assert solver1.As[0] is not None and solver1.bs[0] is not None
assert solver2.As[0] is None and solver2.bs[0] is None
solver2.setAs(solver1.As)
+ solver2.setthAs(solver1.thAs)
solver2.setbs(solver1.bs)
+ solver2.setthbs(solver1.thbs)
uh2 = solver2.solve(mu)[0]
assert np.allclose(uh1, uh2, rtol = 1e-8)
out, err = capsys.readouterr()
assert ("Assembling operator term" not in out
and "Assembling forcing term" not in out)
assert len(err) == 0
@pytest.mark.xfail(reason = "no graphical interface")
def test_helmholtz_box_scattering():
solver = HelmholtzBoxScatteringProblemEngine(R = 2, kappa = 10.,
theta = np.pi * 30 / 180, n = 20, verbosity = 0)
mu = 15
uh = solver.solve(mu)[0]
solver.plotmesh(show = False, figsize = (7, 7))
assert np.isclose(solver.norm(uh), 62.113, rtol = 1e-2)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
9.62989935e-13, rtol = 1e-1)
from matplotlib import pyplot as plt
plt.close('all')
diff --git a/tests/hfengines/helmholtz_internal.py b/tests/hfengines/helmholtz_internal.py
index d6fde8c..7414310 100644
--- a/tests/hfengines/helmholtz_internal.py
+++ b/tests/hfengines/helmholtz_internal.py
@@ -1,97 +1,97 @@
# 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 os, shutil
import numpy as np
from rrompy.hfengines.linear_problem import (
HelmholtzSquareBubbleDomainProblemEngine, HelmholtzSquareBubbleProblemEngine,
HelmholtzSquareTransmissionProblemEngine)
def test_helmholtz_square_io():
solver = HelmholtzSquareBubbleProblemEngine(kappa = 4, theta = 1., n = 20,
verbosity = 0)
mu = 5
uh = solver.solve(mu)[0]
assert np.isclose(solver.norm(uh), 145.0115, rtol = 1e-3)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
1.19934e-11, rtol = 1e-1)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
- solver.norm(solver.residual(uh, mu, duality = False)[0],
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
+ solver.norm(solver.residual(mu, uh, duality = False)[0],
dual = True, duality = False), rtol = 1e-1)
if not os.path.isdir("./.pytest_cache"): os.mkdir("./.pytest_cache")
filesOut = [x for x in os.listdir("./.pytest_cache") if
(x[-4:] == ".pvd" and x[:9] == "outSquare")]
filesOutData = [x for x in os.listdir("./.pytest_cache") if
(x[-4:] == ".vtu" and x[:9] == "outSquare")]
for fileOut in filesOut:
os.remove("./.pytest_cache/" + fileOut)
for fileOut in filesOutData:
os.remove("./.pytest_cache/" + fileOut)
solver.outParaview(uh, what = ["MESH", "ABS"],
filename = ".pytest_cache/outSquare",
forceNewFile = False)
filesOut = [x for x in os.listdir("./.pytest_cache") if
(x[-4:] == ".pvd" and x[:9] == "outSquare")]
filesOutData = [x for x in os.listdir("./.pytest_cache") if
(x[-4:] == ".vtu" and x[:9] == "outSquare")]
assert len(filesOut) == 1
assert len(filesOutData) == 1
os.remove("./.pytest_cache/" + filesOut[0])
os.remove("./.pytest_cache/" + filesOutData[0])
def test_helmholtz_transmission_io():
solver = HelmholtzSquareTransmissionProblemEngine(nT = 1, nB = 2,
theta = np.pi * 40 / 180, kappa = 4., n = 20, verbosity = 0)
mu = 5.
uh = solver.solve(mu)[0]
assert np.isclose(solver.norm(uh), 138.6609, rtol = 1e-2)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
3.7288565e-12, rtol = 1e-1)
if not os.path.isdir("./.pytest_cache"): os.mkdir("./.pytest_cache")
solver.outParaviewTimeDomain(uh, omega = mu,
filename = ".pytest_cache/outTrans",
forceNewFile = False, folder = True)
filesOut = [x for x in os.listdir("./.pytest_cache/outTrans") if
(x[-4:] == ".pvd" and x[:8] == "outTrans")]
filesOutData = [x for x in os.listdir("./.pytest_cache/outTrans") if
(x[-4:] == ".vtu" and x[:8] == "outTrans")]
assert len(filesOut) == 1
assert len(filesOutData) == 20
shutil.rmtree("./.pytest_cache/outTrans")
def test_helmholtz_domain_io():
solver = HelmholtzSquareBubbleDomainProblemEngine(kappa = 4, theta = 1.,
n = 10, mu0 = 1.5, verbosity = 0)
mu = 1.5
uh = solver.solve(mu)[0]
if not os.path.isdir("./.pytest_cache"): os.mkdir("./.pytest_cache")
solver.plot(uh, save = "./.pytest_cache/outDomain", show = False)
filesOut = [x for x in os.listdir("./.pytest_cache") if
(x[-4:] == ".eps" and x[:9] == "outDomain")]
assert len(filesOut) == 1
os.remove("./.pytest_cache/" + filesOut[0])
assert np.isclose(solver.norm(uh), 10.07843, rtol = 1e-2)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
6.14454989e-13, rtol = 1e-1)
diff --git a/tests/hfengines/laplace.py b/tests/hfengines/laplace.py
index 409ea74..0a3bed5 100644
--- a/tests/hfengines/laplace.py
+++ b/tests/hfengines/laplace.py
@@ -1,42 +1,42 @@
# 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.hfengines.linear_problem import LaplaceDiskGaussian
from rrompy.hfengines.linear_problem.bidimensional import LaplaceDiskGaussian2
def test_laplace_disk():
solver = LaplaceDiskGaussian(n = 20, verbosity = 0)
mu = 1.5
solver.setSolver("BICG", {"tol" : 1e-15})
uh = solver.solve(mu)[0]
assert np.isclose(solver.norm(uh), 1.053403077447029, rtol = 1e-2)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
4.66728e-10, atol = 1e-7)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
- solver.norm(solver.residual(uh, mu, duality = False)[0],
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
+ solver.norm(solver.residual(mu, uh, duality = False)[0],
dual = True, duality = False), rtol = 1e-1)
def test_laplace_disk_2():
solver = LaplaceDiskGaussian2(n = 20, verbosity = 0)
mu = [[0., 1.5]]
mu = [0., 1.5]
uh = solver.solve(mu)[0]
assert np.isclose(solver.norm(uh), 1.0534030774205372, rtol = 1e-2)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
2.40043363e-08, atol = 1e-7)
diff --git a/tests/hfengines/linear_elasticity.py b/tests/hfengines/linear_elasticity.py
index 309716a..c4b294d 100644
--- a/tests/hfengines/linear_elasticity.py
+++ b/tests/hfengines/linear_elasticity.py
@@ -1,41 +1,41 @@
# 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.hfengines.vector_linear_problem import (
LinearElasticityBeamPoissonRatio)
from rod_3d import rod3Dsolver
def test_elastic_beam():
solver = LinearElasticityBeamPoissonRatio(n = 10, rho_ = 1e3, g = 3,
E = 1e6, nu0 = .45, length = 5, verbosity = 0)
mu = .45
uh = solver.solve(mu)[0]
- assert np.isclose(solver.norm(uh), 5.866888537228743e-08, rtol = 1e-1)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(uh), 9.33957e-08, rtol = 1e-1)
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
8.4545952e-13, rtol = 1e-1)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
- solver.norm(solver.residual(uh, mu, duality = False)[0],
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
+ solver.norm(solver.residual(mu, uh, duality = False)[0],
dual = True, duality = False), rtol = 1e-1)
def test_elastic_rod():
solver = rod3Dsolver()
uh = solver.solve()[0]
assert np.isclose(solver.norm(uh), 0.15563476339534466, rtol = 1e-5)
- assert np.isclose(solver.norm(solver.residual(uh)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual([], uh)[0], dual = True),
1.2210129e-07, rtol = 1e-1)
diff --git a/tests/hfengines/matrix.py b/tests/hfengines/matrix.py
index d0959e5..572b7d0 100644
--- a/tests/hfengines/matrix.py
+++ b/tests/hfengines/matrix.py
@@ -1,65 +1,58 @@
# 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
import scipy.sparse as sp
-from rrompy.hfengines.base import MatrixEngineBase as MEB
+from rrompy.hfengines.base import MatrixEngineBase
def test_deterministic():
+ solver = MatrixEngineBase(verbosity = 0)
N = 100
- verb = 0
-
- solver = MEB(verbosity = verb)
+ solver._affinePoly = True
solver.npar = 1
- solver.nAs = 2
- mu = 10. + .5j
-
+ solver.nAs, solver.nbs = 2, 1
solver.As = [sp.spdiags([np.arange(1, 1 + N)], [0], N, N),
- - sp.eye(N)]
- solver.nbs = 1
+ - sp.eye(N)]
solver.bs = [np.exp(1.j * np.linspace(0, -np.pi, N))]
+ solver.thAs = solver.getMonomialWeights(solver.nAs)
+ solver.thbs = solver.getMonomialWeights(solver.nbs)
+ mu = 10. + .5j
uh = solver.solve(mu)[0]
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
1.088e-15, rtol = 1e-1)
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
- solver.norm(solver.residual(uh, mu, duality = False)[0],
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
+ solver.norm(solver.residual(mu, uh, duality = False)[0],
dual = True, duality = False), rtol = 1e-1)
def test_random():
+ solver = MatrixEngineBase(verbosity = 0)
N = 100
- verb = 0
-
- solver = MEB(verbosity = verb)
+ solver.setSolver("SOLVE")
solver.npar = 1
- solver.nAs = 2
- mu = 1. + .5j
-
+ solver.nAs, solver.nbs = 2, 1
np.random.seed(420)
-
- solver.setSolver("SOLVE")
fftB = np.fft.fft(np.eye(N)) * N**-.5
solver.As = [fftB.dot(np.multiply(np.arange(1, 1 + N), fftB.conj()).T),
- np.eye(N)]
-
- solver.nbs = 1
solver.bs = [np.random.randn(N) + 1.j * np.random.randn(N)]
-
+ solver.thAs = solver.getMonomialWeights(solver.nAs)
+ solver.thbs = solver.getMonomialWeights(solver.nbs)
+ mu = 1. + .5j
uh = solver.solve(mu)[0]
-
- assert np.isclose(solver.norm(solver.residual(uh, mu)[0], dual = True),
+ assert np.isclose(solver.norm(solver.residual(mu, uh)[0], dual = True),
7.18658e-14, rtol = 1e-1)
diff --git a/tests/reduction_methods_1D/matrix_fft.py b/tests/reduction_methods_1D/matrix_fft.py
index d5ea4c0..e72b612 100644
--- a/tests/reduction_methods_1D/matrix_fft.py
+++ b/tests/reduction_methods_1D/matrix_fft.py
@@ -1,35 +1,38 @@
# 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.hfengines.base import MatrixEngineBase as MEB
+from rrompy.hfengines.base import MatrixEngineBase
+
+class matrixFFT(MatrixEngineBase):
+ def __init__(self):
+ super().__init__(verbosity = 0)
+ self._affinePoly = True
+ N = 100
+ np.random.seed(420)
+ self.setSolver("SOLVE")
+ self.npar = 1
+ self.nAs, self.nbs = 2, 1
+ self.mu0 = 0.
+ fftB = np.fft.fft(np.eye(N)) * N**-.5
+ self.As = [fftB.dot(np.multiply(np.arange(1, 1 + N), fftB.conj()).T),
+ - np.eye(N)]
+ self.bs = [np.random.randn(N) + 1.j * np.random.randn(N)]
+ self.thAs = self.getMonomialWeights(self.nAs)
+ self.thbs = self.getMonomialWeights(self.nbs)
-def matrixFFT():
- N = 100
- solver = MEB(verbosity = 0)
- np.random.seed(420)
- solver.setSolver("SOLVE")
- fftB = np.fft.fft(np.eye(N)) * N**-.5
- solver.npar = 1
- solver.mu0 = 0.
- solver.nAs = 2
- solver.As = [fftB.dot(np.multiply(np.arange(1, 1 + N), fftB.conj()).T),
- - np.eye(N)]
- solver.nbs = 1
- solver.bs = [np.random.randn(N) + 1.j * np.random.randn(N)]
- return solver
diff --git a/tests/reduction_methods_1D/rational_interpolant_1d.py b/tests/reduction_methods_1D/rational_interpolant_1d.py
index b8bd6ac..940d715 100644
--- a/tests/reduction_methods_1D/rational_interpolant_1d.py
+++ b/tests/reduction_methods_1D/rational_interpolant_1d.py
@@ -1,68 +1,68 @@
# 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 matrix_fft import matrixFFT
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
ManualSampler as MS)
from rrompy.parameter import checkParameterList
def test_monomials(capsys):
mu = 1.5
solver = matrixFFT()
params = {"POD": False, "M": 9, "N": 9, "S": 10, "robustTol": 1e-6,
"interpRcond": 1e-3, "polybasis": "MONOMIAL",
"sampler": QS([1.5, 6.5], "UNIFORM")}
approx = RI(solver, 4., params, verbosity = 0)
approx.setupApprox()
out, err = capsys.readouterr()
- assert "poorly conditioned. Reducing E " in out
+ assert "poorly conditioned. Reducing N " in out
assert len(err) == 0
- assert np.isclose(approx.normErr(mu)[0], 2.9051e-4, atol = 1e-4)
+ assert np.isclose(approx.normErr(mu)[0], 1.4746e-05, atol = 1e-4)
def test_well_cond():
mu = 1.5
solver = matrixFFT()
params = {"POD": True, "M": 9, "N": 9, "S": 10, "robustTol": 1e-14,
"interpRcond": 1e-10, "polybasis": "CHEBYSHEV",
"sampler": QS([1., 7.], "CHEBYSHEV")}
approx = RI(solver, 4., params, verbosity = 0)
approx.setupApprox()
poles = approx.getPoles()
for lambda_ in np.arange(1, 8):
assert np.isclose(np.min(np.abs(poles - lambda_)), 0., atol = 1e-4)
for mu in approx.mus:
assert np.isclose(approx.normErr(mu)[0], 0., atol = 1e-8)
def test_hermite():
mu = 1.5
solver = matrixFFT()
sampler0 = QS([1., 7.], "CHEBYSHEV")
points, _ = checkParameterList(np.tile(sampler0.generatePoints(4)(0), 3))
params = {"POD": True, "M": 11, "N": 11, "S": 12, "polybasis": "CHEBYSHEV",
"sampler": MS([1., 7.], points = points)}
approx = RI(solver, 4., params, verbosity = 0)
approx.setupApprox()
poles = approx.getPoles()
for lambda_ in np.arange(1, 8):
assert np.isclose(np.min(np.abs(poles - lambda_)), 0., atol = 1e-4)
for mu in approx.mus:
assert np.isclose(approx.normErr(mu)[0], 0., atol = 1e-8)
diff --git a/tests/reduction_methods_1D/rational_interpolant_greedy_1d.py b/tests/reduction_methods_1D/rational_interpolant_greedy_1d.py
index d57d9e2..31338b2 100644
--- a/tests/reduction_methods_1D/rational_interpolant_greedy_1d.py
+++ b/tests/reduction_methods_1D/rational_interpolant_greedy_1d.py
@@ -1,93 +1,94 @@
# 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 matrix_fft import matrixFFT
from rrompy.reduction_methods.greedy import RationalInterpolantGreedy as RIG
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
def test_lax_tolerance(capsys):
mu = 2.25
solver = matrixFFT()
params = {"POD": True, "sampler": QS([1.5, 6.5], "UNIFORM"), "S": 4,
"polybasis": "CHEBYSHEV", "greedyTol": 1e-2,
- "errorEstimatorKind": "bare",
+ "errorEstimatorKind": "DIAGONAL",
"trainSetGenerator": QS([1.5, 6.5], "CHEBYSHEV")}
approx = RIG(solver, 4., params, verbosity = 100)
approx.greedy()
out, err = capsys.readouterr()
assert "Done computing snapshots (final snapshot count: 10)." in out
assert len(err) == 0
assert np.isclose(approx.normErr(mu)[0], 2.169678e-4, rtol = 1e-1)
def test_samples_at_poles():
solver = matrixFFT()
params = {"POD": True, "sampler": QS([1.5, 6.5], "UNIFORM"), "S": 4,
"nTestPoints": 100, "polybasis": "CHEBYSHEV", "greedyTol": 1e-5,
- "errorEstimatorKind": "exact",
+ "errorEstimatorKind": "AFFINE",
"trainSetGenerator": QS([1.5, 6.5], "CHEBYSHEV")}
approx = RIG(solver, 4., params, verbosity = 0)
approx.greedy()
for mu in approx.mus:
assert np.isclose(approx.normErr(mu)[0] / (1e-15+approx.normHF(mu)[0]),
0., atol = 1e-4)
poles = approx.getPoles()
for lambda_ in range(2, 7):
assert np.isclose(np.min(np.abs(poles - lambda_)), 0., atol = 1e-3)
assert np.isclose(np.min(np.abs(np.array(approx.mus(0)) - lambda_)),
0., atol = 1e-1)
def test_maxIter():
solver = matrixFFT()
params = {"POD": True, "sampler": QS([1.5, 6.5], "UNIFORM"),
"S": 5, "nTestPoints": 500, "polybasis": "CHEBYSHEV",
- "greedyTol": 1e-6, "maxIter": 10, "errorEstimatorKind": "basic",
+ "greedyTol": 1e-6, "maxIter": 10,
+ "errorEstimatorKind": "INTERPOLATORY",
"trainSetGenerator": QS([1.5, 6.5], "CHEBYSHEV")}
approx = RIG(solver, 4., params, verbosity = 0)
approx.input = lambda: "N"
approx.greedy()
assert len(approx.mus) == 10
_, _, maxEst = approx.getMaxErrorEstimator(approx.muTest)
assert maxEst > 1e-6
def test_load_copy(capsys):
mu = 3.
solver = matrixFFT()
params = {"POD": True, "sampler": QS([1.5, 6.5], "UNIFORM"), "S": 4,
"nTestPoints": 100, "polybasis": "CHEBYSHEV",
- "greedyTol": 1e-5, "errorEstimatorKind": "exact",
+ "greedyTol": 1e-5, "errorEstimatorKind": "AFFINE",
"trainSetGenerator": QS([1.5, 6.5], "CHEBYSHEV")}
approx1 = RIG(solver, 4., params, verbosity = 100)
approx1.greedy()
err1 = approx1.normErr(mu)[0]
out, err = capsys.readouterr()
assert "Solving HF model for mu =" in out
assert len(err) == 0
approx2 = RIG(solver, 4., params, verbosity = 100)
approx2.setTrainedModel(approx1)
approx2.setHF(mu, approx1.uHF)
err2 = approx2.normErr(mu)[0]
out, err = capsys.readouterr()
assert "Solving HF model for mu =" not in out
assert len(err) == 0
assert np.isclose(err1, err2, rtol = 1e-10)
diff --git a/tests/reduction_methods_1D/reduced_basis_1d.py b/tests/reduction_methods_1D/reduced_basis_1d.py
index 3cd2a78..715db16 100644
--- a/tests/reduction_methods_1D/reduced_basis_1d.py
+++ b/tests/reduction_methods_1D/reduced_basis_1d.py
@@ -1,57 +1,57 @@
# 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 matrix_fft import matrixFFT
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
ManualSampler as MS)
from rrompy.parameter import checkParameterList
def test_LS():
solver = matrixFFT()
params = {"POD": True, "R": 5, "S": 10,
"sampler": QS([1., 7.], "CHEBYSHEV")}
approx = RB(solver, 4., params, verbosity = 0)
approx.setupApprox()
for mu in approx.mus:
assert not np.isclose(approx.normErr(mu)[0], 0., atol = 1e-7)
approx.POD = False
approx.setupApprox()
for mu in approx.mus[approx.R :]:
assert not np.isclose(approx.normErr(mu)[0], 0., atol = 1e-3)
-
+
def test_interp():
solver = matrixFFT()
params = {"POD": False, "S": 10, "sampler": QS([1., 7.], "CHEBYSHEV")}
approx = RB(solver, 4., params, verbosity = 0)
approx.setupApprox()
for mu in approx.mus:
assert np.isclose(approx.normErr(mu)[0], 0., atol = 1e-7)
def test_hermite():
mu = 1.5
solver = matrixFFT()
sampler0 = QS([1., 7.], "CHEBYSHEV")
points, _ = checkParameterList(np.tile(sampler0.generatePoints(4)(0), 3))
params = {"POD": True, "S": 12, "sampler": MS([1., 7.], points = points)}
approx = RB(solver, 4., params, verbosity = 0)
approx.setupApprox()
for mu in approx.mus:
assert np.isclose(approx.normErr(mu)[0], 0., atol = 1e-8)
diff --git a/tests/reduction_methods_1D/reduced_basis_greedy_1d.py b/tests/reduction_methods_1D/reduced_basis_greedy_1d.py
index 0086ab0..e56f2bb 100644
--- a/tests/reduction_methods_1D/reduced_basis_greedy_1d.py
+++ b/tests/reduction_methods_1D/reduced_basis_greedy_1d.py
@@ -1,59 +1,58 @@
# 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 matrix_fft import matrixFFT
from rrompy.reduction_methods.greedy import ReducedBasisGreedy as RBG
from rrompy.parameter.parameter_sampling import QuadratureSampler as QS
def test_lax_tolerance(capsys):
mu = 2.25
solver = matrixFFT()
params = {"POD": True, "sampler": QS([1.5, 6.5], "UNIFORM"),
"S": 4, "greedyTol": 1e-2,
"trainSetGenerator": QS([1.5, 6.5], "CHEBYSHEV")}
approx = RBG(solver, 4., params, verbosity = 10)
approx.greedy()
out, err = capsys.readouterr()
assert "Done computing snapshots (final snapshot count: 10)." in out
assert len(err) == 0
assert len(approx.mus) == 10
_, _, maxEst = approx.getMaxErrorEstimator(approx.muTest)
assert maxEst < 1e-2
assert np.isclose(approx.normErr(mu)[0], 1.5056e-05, rtol = 1e-1)
def test_samples_at_poles():
solver = matrixFFT()
params = {"POD": True, "sampler": QS([1.5, 6.5], "UNIFORM"),
"S": 4, "nTestPoints": 100, "greedyTol": 1e-5,
"trainSetGenerator": QS([1.5, 6.5], "CHEBYSHEV")}
approx = RBG(solver, 4., params, verbosity = 0)
approx.greedy()
for mu in approx.mus:
assert np.isclose(approx.normErr(mu)[0] / (1e-15+approx.normHF(mu)[0]),
0., atol = 1e-4)
poles = approx.getPoles()
for lambda_ in range(2, 7):
assert np.isclose(np.min(np.abs(poles - lambda_)), 0., atol = 1e-3)
assert np.isclose(np.min(np.abs(np.array(approx.mus(0)) - lambda_)),
0., atol = 1e-1)
-
diff --git a/tests/reduction_methods_multiD/matrix_random.py b/tests/reduction_methods_multiD/matrix_random.py
index c82fad7..79a5d83 100644
--- a/tests/reduction_methods_multiD/matrix_random.py
+++ b/tests/reduction_methods_multiD/matrix_random.py
@@ -1,38 +1,41 @@
# 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.hfengines.base import MatrixEngineBase as MEB
+from rrompy.hfengines.base import MatrixEngineBase
+
+class matrixRandom(MatrixEngineBase):
+ def __init__(self):
+ super().__init__(verbosity = 0)
+ self._affinePoly = True
+ N = 100
+ np.random.seed(420)
+ self.setSolver("SOLVE")
+ self.npar = 2
+ self.nAs, self.nbs = 3, 1
+ self.mu0 = [0., 0.]
+ d1 = np.random.randn(N)
+ Q1, _ = np.linalg.qr(np.random.randn(N, N))
+ d2 = np.random.randn(N)
+ Q2, _ = np.linalg.qr(np.random.randn(N, N))
+ self.As = [np.eye(N), Q1.dot(np.multiply(d1, Q1.conj()).T),
+ Q2.dot(np.multiply(d2, Q2.conj()).T)]
+ self.bs = [np.random.randn(N) + 1.j * np.random.randn(N)]
+ self.thAs = self.getMonomialWeights(self.nAs)
+ self.thbs = self.getMonomialWeights(self.nbs)
-def matrixRandom():
- N = 100
- solver = MEB(verbosity = 0)
- np.random.seed(420)
- solver.setSolver("SOLVE")
- solver.npar = 2
- solver.mu0 = [0., 0.]
- solver.nAs = 3
- d1 = np.random.randn(N)
- Q1, _ = np.linalg.qr(np.random.randn(N, N))
- d2 = np.random.randn(N)
- Q2, _ = np.linalg.qr(np.random.randn(N, N))
- solver.As = [np.eye(N), Q1.dot(np.multiply(d1, Q1.conj()).T),
- Q2.dot(np.multiply(d2, Q2.conj()).T)]
- solver.nbs = 1
- solver.bs = [np.random.randn(N) + 1.j * np.random.randn(N)]
- return solver
diff --git a/tests/reduction_methods_multiD/rational_interpolant_2d.py b/tests/reduction_methods_multiD/rational_interpolant_2d.py
index 0788552..9bd84a3 100644
--- a/tests/reduction_methods_multiD/rational_interpolant_2d.py
+++ b/tests/reduction_methods_multiD/rational_interpolant_2d.py
@@ -1,79 +1,79 @@
# 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 matrix_random import matrixRandom
from rrompy.reduction_methods.standard import RationalInterpolant as RI
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
ManualSampler as MS)
def test_monomials(capsys):
mu = [5.05, 7.1]
mu0 = [5., 7.]
solver = matrixRandom()
uh = solver.solve(mu)[0]
- params = {"POD": False, "M": 4, "N": 4, "S": [4, 4], "robustTol": 1e-6,
+ params = {"POD": False, "M": 4, "N": 4, "S": 16, "robustTol": 1e-6,
"interpRcond": 1e-3, "polybasis": "MONOMIAL",
"sampler": QS([[4.9, 6.85], [5.1, 7.15]], "UNIFORM")}
approx = RI(solver, mu0, params, verbosity = 0)
approx.setupApprox()
uhP1 = approx.getApprox(mu)[0]
errP = approx.getErr(mu)[0]
errNP = approx.normErr(mu)[0]
myerrP = uhP1 - uh
assert np.allclose(np.abs(errP - myerrP), 0., rtol = 1e-3)
assert np.isclose(solver.norm(errP), errNP, rtol = 1e-3)
resP = approx.getRes(mu)[0]
resNP = approx.normRes(mu)
assert np.isclose(solver.norm(resP), resNP, rtol = 1e-3)
assert np.allclose(np.abs(resP - (solver.b(mu) - solver.A(mu).dot(uhP1))),
0., rtol = 1e-3)
- assert np.isclose(errNP / solver.norm(uh), 5.2667e-05, rtol = 1e-1)
+ assert np.isclose(errNP / solver.norm(uh), 5.2667e-05, rtol = 1)
out, err = capsys.readouterr()
print(out)
- assert ("poorly conditioned. Reducing E" in out)
+ assert ("poorly conditioned. Reducing N " in out)
assert len(err) == 0
def test_well_cond():
mu = [5.05, 7.1]
mu0 = [5., 7.]
solver = matrixRandom()
- params = {"POD": True, "M": 3, "N": 3, "S": [4, 4],
+ params = {"POD": True, "M": 3, "N": 3, "S": 16,
"interpRcond": 1e-10, "polybasis": "CHEBYSHEV",
"sampler": QS([[4.9, 6.85], [5.1, 7.15]], "UNIFORM")}
approx = RI(solver, mu0, params, verbosity = 0)
approx.setupApprox()
print(approx.normErr(mu)[0] / approx.normHF(mu)[0])
assert np.isclose(approx.normErr(mu)[0] / approx.normHF(mu)[0],
5.98695e-05, rtol = 1e-1)
def test_hermite():
mu = [5.05, 7.1]
mu0 = [5., 7.]
solver = matrixRandom()
sampler0 = QS([[4.9, 6.85], [5.1, 7.15]], "UNIFORM")
- params = {"POD": True, "M": 3, "N": 3, "S": [25], "polybasis": "CHEBYSHEV",
+ params = {"POD": True, "M": 3, "N": 3, "S": 25, "polybasis": "CHEBYSHEV",
"sampler": MS([[4.9, 6.85], [5.1, 7.15]],
- points = sampler0.generatePoints([3, 3]))}
+ points = sampler0.generatePoints(9))}
approx = RI(solver, mu0, params, verbosity = 0)
approx.setupApprox()
assert np.isclose(approx.normErr(mu)[0] / approx.normHF(mu)[0],
- 0.000236598, rtol = 1e-1)
+ 0.000224, rtol = 5e-1)
diff --git a/tests/reduction_methods_multiD/reduced_basis_2d.py b/tests/reduction_methods_multiD/reduced_basis_2d.py
index 5a66aa1..e04b2d8 100644
--- a/tests/reduction_methods_multiD/reduced_basis_2d.py
+++ b/tests/reduction_methods_multiD/reduced_basis_2d.py
@@ -1,62 +1,62 @@
# 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 matrix_random import matrixRandom
from rrompy.reduction_methods.standard import ReducedBasis as RB
from rrompy.parameter.parameter_sampling import (QuadratureSampler as QS,
ManualSampler as MS)
from rrompy.parameter import checkParameterList
def test_LS():
mu0 = [2, 3]
solver = matrixRandom()
- params = {"POD": True, "R": 5, "S": [3, 3],
+ params = {"POD": True, "R": 5, "S": 9,
"sampler": QS([[0., 4.], [1., 5.]], "CHEBYSHEV")}
approx = RB(solver, mu0, params, verbosity = 0)
approx.setupApprox()
for mu in approx.mus:
assert not np.isclose(approx.normErr(mu)[0], 0., atol = 1e-7)
approx.POD = False
approx.setupApprox()
for mu in approx.mus[approx.R :]:
assert not np.isclose(approx.normErr(mu)[0], 0., atol = 1e-3)
def test_interp():
mu0 = [2, 3]
solver = matrixRandom()
- params = {"POD": False, "S": [3, 3],
+ params = {"POD": False, "S": 9,
"sampler": QS([[0., 4.], [1., 5.]], "CHEBYSHEV")}
approx = RB(solver, mu0, params, verbosity = 0)
approx.setupApprox()
for mu in approx.mus:
assert np.isclose(approx.normErr(mu)[0], 0., atol = 1e-7)
def test_hermite():
mu0 = [2, 3]
solver = matrixRandom()
sampler0 = QS([[0., 4.], [1., 5.]], "CHEBYSHEV")
points, _ = checkParameterList(np.tile(
- sampler0.generatePoints([2, 2]).data, [3, 1]))
- params = {"POD": True, "S": [12],
+ sampler0.generatePoints(4).data, [3, 1]))
+ params = {"POD": True, "S": 12,
"sampler": MS([[0., 4.], [1., 5.]], points = points)}
approx = RB(solver, mu0, params, verbosity = 0)
approx.setupApprox()
for mu in approx.mus:
assert np.isclose(approx.normErr(mu)[0], 0., atol = 1e-8)
diff --git a/tests/utilities/parameter_sampling.py b/tests/utilities/parameter_sampling.py
index b1ea088..cdc3009 100644
--- a/tests/utilities/parameter_sampling.py
+++ b/tests/utilities/parameter_sampling.py
@@ -1,59 +1,59 @@
# 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.parameter.parameter_sampling import (ManualSampler,
QuadratureSampler, RandomSampler, FFTSampler)
from rrompy.parameter import checkParameter
def test_manual():
sampler = ManualSampler(lims = [0., 3.], points = np.linspace(0, 3, 101),
scalingExp = 2.)
assert sampler.name() == "ManualSampler"
x = sampler.generatePoints(10)
assert np.allclose(x(0), np.linspace(0, 3, 101)[:10], rtol = 1e-5)
def test_quadrature():
sampler = QuadratureSampler(lims = [0., 3.], kind = "CHEBYSHEV")
- x = sampler.generatePoints(9)
- assert np.isclose(x(0)[2], 1.5, rtol = 1e-5)
+ x = sampler.generatePoints(9, reorder = False)
+ assert np.isclose(x(0)[4], 1.5, rtol = 1e-5)
def test_random():
sampler = RandomSampler(lims = [0., 3.], kind = "SOBOL", seed = 13432)
x = sampler.generatePoints(100)
assert np.isclose(x(0)[47], 0.55609130859375, rtol = 1e-5)
def test_fft():
sampler = FFTSampler(lims = [-1., 1.])
x = sampler.generatePoints(100)
assert np.allclose(np.power(x(0), 100), 1., rtol = 1e-5)
def test_2D():
sampler = QuadratureSampler(lims = [(0., 0.), (3., 1.)],
kind = "GAUSSLEGENDRE")
- x = sampler.generatePoints((9, 5))
- assert sum(np.isclose(x(0), 1.5)) == 5
+ x = sampler.generatePoints(81)
+ assert sum(np.isclose(x(0), 1.5)) == 9
assert sum(np.isclose(x(1), .5)) == 9
def test_4D():
- sampler = RandomSampler(lims = [tuple([0.] * 4), tuple([1.] * 4)],
+ sampler = RandomSampler(lims = [(0.,) * 4, (1.,) * 4],
kind = "UNIFORM", seed = 1234)
x = sampler.generatePoints(10)
assert x.shape[1] == 4
assert checkParameter([x[0]]) == checkParameter([(0.191519450378892,
0.622108771039832, 0.437727739007115, 0.785358583713769)])
diff --git a/tests/utilities/poly_fitting.py b/tests/utilities/poly_fitting.py
index 936b051..909452e 100644
--- a/tests/utilities/poly_fitting.py
+++ b/tests/utilities/poly_fitting.py
@@ -1,116 +1,116 @@
# 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.utilities.poly_fitting import customFit
from rrompy.utilities.poly_fitting.polynomial import (polybases, polyfitname,
polydomcoeff, polyval,
- polyroots, polyvander,
- nextDerivativeIndices)
+ polyroots, polyvander)
+from rrompy.utilities.numerical import nextDerivativeIndices
from rrompy.parameter import checkParameterList
def test_chebyshev():
assert "CHEBYSHEV" in polybases
fitname = polyfitname("CHEBYSHEV")
domcoeff = polydomcoeff(5, "CHEBYSHEV")
assert fitname == "chebfit"
assert np.isclose(domcoeff, 16, rtol = 1e-5)
assert np.allclose(polyroots((-1, 1, -1, 1), "CHEBYSHEV"),
np.array([-.5, 0., 1.]), rtol = 1e-5)
Phi = polyvander(np.arange(5), 4, "CHEBYSHEV")
y = 2. * np.arange(5)
cFit = customFit(Phi, y)
assert np.allclose(cFit, [0, 2, 0, 0, 0], rtol = 1e-5)
assert np.allclose(polyval(np.arange(5), cFit, "CHEBYSHEV"), y,
rtol = 1e-5)
assert np.allclose(polyval(np.arange(5), cFit, "CHEBYSHEV", m = 1),
2. * np.ones(5), rtol = 1e-5)
def test_legendre():
assert "LEGENDRE" in polybases
fitname = polyfitname("LEGENDRE")
domcoeff = polydomcoeff([0, 5], "LEGENDRE")
assert fitname == "legfit"
assert np.allclose(domcoeff, [1., 63. / 8], rtol = 1e-5)
assert np.allclose(polyroots((1, 2, 3, 4), "LEGENDRE"),
np.array([-0.85099543, -0.11407192, 0.51506735]),
rtol = 1e-5)
Phi = polyvander(np.arange(5), 4, "LEGENDRE")
y = 2. * np.arange(5)
cFit = customFit(Phi, y)
assert np.allclose(cFit, [0, 2, 0, 0, 0], rtol = 1e-5)
assert np.allclose(polyval(np.arange(5), cFit, "LEGENDRE"), y, rtol = 1e-5)
assert np.allclose(polyval(np.arange(5), cFit, "LEGENDRE", m = 1),
2. * np.ones(5), rtol = 1e-5)
def test_monomial():
assert "MONOMIAL" in polybases
fitname = polyfitname("MONOMIAL")
domcoeff = polydomcoeff(5, "MONOMIAL")
assert fitname == "polyfit"
assert np.isclose(domcoeff, 1., rtol = 1e-5)
assert np.allclose(polyroots([0.+0.j, 1.+0.j, 0.+0.j, 1.+0.j], "MONOMIAL"),
np.array([0., 1.j, -1.j]), rtol = 1e-5)
Phi = polyvander(np.arange(5), 4, "MONOMIAL")
y = 2. * np.arange(5)
cFit = customFit(Phi, y)
assert np.allclose(cFit, [0, 2, 0, 0, 0], rtol = 1e-5)
assert np.allclose(polyval(np.arange(5), cFit, "MONOMIAL"), y, rtol = 1e-5)
assert np.allclose(polyval(np.arange(5), cFit, "MONOMIAL", m = 1),
2. * np.ones(5), rtol = 1e-5)
def test_cheb_confluence():
x = np.arange(5)
x = np.delete(x, 3)
Phi = polyvander(x, 4, "CHEBYSHEV", [[0, 1]] + [[0]] * 3,
reorder = [0, 2, 3, 1, 4])
y = 2. * np.arange(5)
y[3] = 2.
cFit = customFit(Phi, y)
mask = np.arange(len(y)) != 3
assert np.allclose(cFit, [0, 2, 0, 0, 0], rtol = 1e-5)
assert np.allclose(polyval(x, cFit, "CHEBYSHEV"), y[mask],
rtol = 1e-5)
assert np.allclose(polyval(x[0], cFit, "CHEBYSHEV", m = 1), y[~mask],
rtol = 1e-5)
def test_mon_confluence_2d():
x, _ = checkParameterList([[0, 0], [1, 1], [-1, -1]])
y = np.array([3., 5., 1., 2., 12., -2.]).reshape((-1, 1)) # 3+y+5x+2xy+x2y
Phi = polyvander(x, [2, 1], "MONOMIAL",
[[[0, 0], [1, 0], [0, 1], [1, 1]]] + [[[0, 0]]] * 2)
cFit = customFit(Phi, y).reshape((3, 2))
mask = np.array([0, 4, 5])
assert np.allclose(cFit.flatten(), [3, 1, 5, 2, 0, 1], atol = 1e-5)
assert np.allclose(polyval(x, cFit, "MONOMIAL").flatten(),
y[mask].flatten(), rtol = 1e-5)
assert np.allclose(polyval([x[0]], cFit, "MONOMIAL", m = [1, 0]), y[1],
rtol = 1e-5)
assert np.allclose(polyval([x[0]], cFit, "MONOMIAL", m = [0, 1]), y[2],
rtol = 1e-5)
assert np.allclose(polyval([x[0]], cFit, "MONOMIAL", m = [1, 1]), y[3],
rtol = 1e-5)
def test_derivative_indices_4d():
idxs = nextDerivativeIndices([], 4, 70)
idxMag = [np.sum(idx) for idx in idxs]
idxMagUnique, idxMagCount = np.unique(idxMag, return_counts = True)
idxMagCount = np.cumsum(idxMagCount)
assert np.allclose(idxMagUnique, np.arange(5), atol = 1e-10)
assert np.allclose(idxMagCount, [1, 5, 15, 35, 70], atol = 1e-10)
diff --git a/tests/utilities/radial_fitting.py b/tests/utilities/radial_fitting.py
index d10448b..dd996f0 100644
--- a/tests/utilities/radial_fitting.py
+++ b/tests/utilities/radial_fitting.py
@@ -1,167 +1,167 @@
# 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.utilities.poly_fitting import customFit
from rrompy.utilities.poly_fitting.radial_basis import (radialGaussian,
thinPlateSpline,
multiQuadric,
polybases, polyfitname,
polydomcoeff,
polyval, polyvander,
- homogeneizedpolyvander)
-from rrompy.utilities.poly_fitting.polynomial import homogeneizedToFull
+ polyvanderTotal)
+from rrompy.utilities.numerical import degreeTotalToFull
from rrompy.parameter import checkParameterList
def test_monomial_gaussian():
polyrbname = "MONOMIAL_GAUSSIAN"
assert polyrbname in polybases
fitname = polyfitname(polyrbname)
domcoeff = polydomcoeff(5, polyrbname)
assert fitname == "polyfit_gaussian"
assert np.isclose(domcoeff, 1., rtol = 1e-5)
directionalWeights = np.array([5.])
xSupp = checkParameterList(np.arange(-1, 3), 1)[0]
cRBCoeffs = np.array([-1., 3., -3., 1., 1., 2., -.5])
globalCoeffs = cRBCoeffs[4 :]
localCoeffs = cRBCoeffs[: 4]
ySupp = 1 + 2. * xSupp.data - .5 * xSupp.data ** 2.
xx = np.linspace(-2., 3., 100)
yy = polyval(checkParameterList(xx, 1)[0], globalCoeffs, localCoeffs,
xSupp, directionalWeights, polyrbname)
yyman = 1. + 2. * xx - .5 * xx ** 2.
for j, xc in enumerate(np.arange(-1, 3)):
r2j = (5. * (xx - xc)) ** 2.
rbj = radialGaussian(r2j)
assert np.allclose(rbj, np.exp(-.5 * r2j))
yyman += localCoeffs[j] * rbj
ySupp += localCoeffs[j] * radialGaussian((directionalWeights[0]
* (xSupp.data - xc)) ** 2.)
assert np.allclose(yy, yyman, atol = 1e-5)
VanT = polyvander(xSupp, [2], polyrbname,
directionalWeights = directionalWeights)
ySupp = np.pad(ySupp.flatten(), (0, len(VanT) - len(xSupp)), "constant")
out = customFit(VanT, ySupp)
assert np.allclose(out, cRBCoeffs, atol = 1e-8)
def test_legendre_thinplate():
polyrbname = "LEGENDRE_THINPLATE"
assert polyrbname in polybases
fitname = polyfitname(polyrbname)
domcoeff = polydomcoeff(5, polyrbname)
assert fitname == "legfit_thinplate"
assert np.isclose(domcoeff, 63. / 8, rtol = 1e-5)
directionalWeights = np.array([.5])
xSupp = checkParameterList(np.arange(-1, 3), 1)[0]
cRBCoeffs = np.array([-1., 3., -3., 1., 1., 2., -.5])
localCoeffs = cRBCoeffs[: 4]
globalCoeffs = cRBCoeffs[4 :]
ySupp = 1 + 2. * xSupp.data - .5 * (.5 * (3. * xSupp.data ** 2. - 1.))
xx = np.linspace(-2., 3., 100)
yy = polyval(checkParameterList(xx, 1)[0], globalCoeffs, localCoeffs,
xSupp, directionalWeights, polyrbname)
yyman = 1. + 2. * xx - .5 * (.5 * (3. * xx ** 2. - 1.))
for j, xc in enumerate(np.arange(-1, 3)):
r2j = (directionalWeights[0] * (xx - xc)) ** 2.
rbj = thinPlateSpline(r2j)
assert np.allclose(rbj, .5 * r2j * np.log(np.finfo(float).eps + r2j))
yyman += localCoeffs[j] * rbj
ySupp += localCoeffs[j] * thinPlateSpline((directionalWeights[0]
* (xSupp.data - xc)) ** 2.)
assert np.allclose(yy, yyman, atol = 1e-5)
VanT = polyvander(xSupp, [2], polyrbname,
directionalWeights = directionalWeights)
ySupp = np.pad(ySupp.flatten(), (0, len(VanT) - len(xSupp)), "constant")
out = customFit(VanT, ySupp)
assert np.allclose(out, cRBCoeffs, atol = 1e-8)
def test_chebyshev_multiquadric():
polyrbname = "CHEBYSHEV_MULTIQUADRIC"
assert polyrbname in polybases
fitname = polyfitname(polyrbname)
domcoeff = polydomcoeff(5, polyrbname)
assert fitname == "chebfit_multiquadric"
assert np.isclose(domcoeff, 16, rtol = 1e-5)
directionalWeights = np.array([1.])
xSupp = checkParameterList(np.arange(-1, 3), 1)[0]
cRBCoeffs = np.array([-1., 3., -3., 1., 1., 2., -.5])
localCoeffs = cRBCoeffs[: 4]
globalCoeffs = cRBCoeffs[4 :]
ySupp = 1 + 2. * xSupp.data - .5 * (2. * xSupp.data ** 2. - 1.)
xx = np.linspace(-2., 3., 100)
yy = polyval(checkParameterList(xx, 1)[0], globalCoeffs, localCoeffs,
xSupp, directionalWeights, polyrbname)
yyman = 1. + 2. * xx - .5 * (2. * xx ** 2. - 1.)
for j, xc in enumerate(np.arange(-1, 3)):
r2j = (directionalWeights[0] * (xx - xc)) ** 2.
rbj = multiQuadric(r2j)
assert np.allclose(rbj, np.power(r2j + 1, -.5))
yyman += localCoeffs[j] * rbj
ySupp += localCoeffs[j] * multiQuadric((directionalWeights[0]
* (xSupp.data - xc)) ** 2.)
assert np.allclose(yy, yyman, atol = 1e-5)
VanT = polyvander(xSupp, [2], polyrbname,
directionalWeights = directionalWeights)
ySupp = np.pad(ySupp.flatten(), (0, len(VanT) - len(xSupp)), "constant")
out = customFit(VanT, ySupp)
assert np.allclose(out, cRBCoeffs, atol = 1e-8)
def test_total_degree_2d():
values = lambda x, y: (x - 3.) ** 2. * y - (x + 1.) * y ** 2.
polyrbname = "CHEBYSHEV_GAUSSIAN"
xs, ys = np.meshgrid(np.linspace(0., 4., 5), np.linspace(0., 4., 4))
xySupp = np.concatenate((xs.reshape(-1, 1), ys.reshape(-1, 1)), axis = 1)
zs = values(xs, ys)
zSupp = zs.flatten()
deg = 3
directionalWeights = [2., 1.]
- VanT, _, reidxs = homogeneizedpolyvander(xySupp, deg, polyrbname,
- directionalWeights = directionalWeights)
+ VanT, _, reidxs = polyvanderTotal(xySupp, deg, polyrbname,
+ directionalWeights = directionalWeights)
VanT = VanT[reidxs]
VanT = VanT[:, reidxs]
cFit = np.linalg.solve(VanT, np.pad(zSupp, (0, len(VanT) - len(zSupp)),
'constant'))
- globCoeff = homogeneizedToFull([deg + 1] * 2, 2, cFit[len(zSupp) :])
+ globCoeff = degreeTotalToFull([deg + 1] * 2, 2, cFit[len(zSupp) :])
localCoeffs = cFit[: len(zSupp)]
globalCoeffs = globCoeff
xx, yy = np.meshgrid(np.linspace(0., 4., 100), np.linspace(0., 4., 100))
xxyy = np.concatenate((xx.reshape(-1, 1), yy.reshape(-1, 1)), axis = 1)
zz = polyval(xxyy, globalCoeffs, localCoeffs, xySupp, directionalWeights,
polyrbname).reshape(xx.shape)
zzex = values(xx, yy)
error = np.abs(zz - zzex)
print(np.max(error))
assert np.max(error) < 1e-10
diff --git a/tests/utilities/sampling.py b/tests/utilities/sampling.py
index a441267..e843740 100644
--- a/tests/utilities/sampling.py
+++ b/tests/utilities/sampling.py
@@ -1,78 +1,65 @@
# 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
import scipy.sparse as sp
-from rrompy.hfengines.base import MatrixEngineBase as MEB
+from rrompy.hfengines.base import MatrixEngineBase
from rrompy.sampling.standard import (SamplingEngineStandard,
SamplingEngineStandardPOD)
from rrompy.parameter import parameterList
+class matrixEngine(MatrixEngineBase):
+ def __init__(self):
+ super().__init__(verbosity = 0)
+ self._affinePoly = True
+ N = 100
+ self.npar = 1
+ self.nAs, self.nbs = 2, 1
+ self.As = [sp.spdiags([np.arange(1, 1 + N)], [0], N, N),
+ - sp.eye(N)]
+ self.bs = [np.exp(1.j * np.linspace(0, -np.pi, N))]
+ self.thAs = self.getMonomialWeights(self.nAs)
+ self.thbs = self.getMonomialWeights(self.nbs)
+
def test_krylov():
- N = 100
mu = 10. + .5j
- solver = MEB(verbosity = 0)
- solver.npar = 1
- solver.nAs = 2
-
- solver.As = [sp.spdiags([np.arange(1, 1 + N)], [0], N, N),
- - sp.eye(N)]
- solver.nbs = 1
- solver.bs = [np.exp(1.j * np.linspace(0, -np.pi, N))]
+ solver = matrixEngine()
samplingEngine = SamplingEngineStandard(solver, verbosity = 0)
-
samples = samplingEngine.iterSample([mu] * 5).data
assert samples.shape == (100, 5)
assert np.isclose(np.linalg.norm(samples), 37.02294804524299, rtol = 1e-5)
def test_distributed():
- N = 100
mus = parameterList(np.linspace(5, 15, 11) + .5j)
- solver = MEB(verbosity = 0)
- solver.npar = 1
- solver.nAs = 2
-
- solver.As = [sp.spdiags([np.arange(1, 1 + N)], [0], N, N),
- - sp.eye(N)]
- solver.nbs = 1
- solver.bs = [np.exp(1.j * np.linspace(0, -np.pi, N))]
+ solver = matrixEngine()
samplingEngine = SamplingEngineStandard(solver, verbosity = 0)
-
samples = samplingEngine.iterSample(mus).data
assert samples.shape == (100, 11)
assert np.isclose(np.linalg.norm(samples), 8.59778606421386, rtol = 1e-5)
def test_distributed_pod():
- N = 100
mus = np.linspace(5, 15, 11) + .5j
- solver = MEB(verbosity = 0)
- solver.npar = 1
- solver.nAs = 2
-
- solver.As = [sp.spdiags([np.arange(1, 1 + N)], [0], N, N),
- - sp.eye(N)]
- solver.nbs = 1
- solver.bs = [np.exp(1.j * np.linspace(0, -np.pi, N))]
+ solver = matrixEngine()
samplingEngine = SamplingEngineStandardPOD(solver, verbosity = 0)
samples = samplingEngine.iterSample(mus).data
assert samples.shape == (100, 11)
assert np.isclose(np.linalg.norm(samples), 3.3166247903553994, rtol = 1e-5)
assert np.isclose(np.linalg.cond(samples.conj().T.dot(samples)), 1.,
rtol = 1e-5)
diff --git a/tests/utilities/scipy_tensorize.py b/tests/utilities/scipy_tensorize.py
deleted file mode 100644
index 037cdf5..0000000
--- a/tests/utilities/scipy_tensorize.py
+++ /dev/null
@@ -1,57 +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
-import scipy.sparse as scsp
-from rrompy.solver.scipy import tensorizeLS, detensorizeLS
-
-def test_dense():
- N = 5
- A1 = np.random.rand(N, N)
- x1 = np.random.rand(N)
- b1 = A1.dot(x1)
- A2 = np.diag(np.arange(1, N + 1) * 2.)
- x2 = np.ones(N)
- b2 = A2.dot(x2)
- A3 = np.eye(N)
- x3 = np.ones(N)
- b3 = A3.dot(x3)
- A, b = tensorizeLS([A1, A2, A3], [b1, b2, b3])
- assert np.allclose(A.shape, (3 * N, 3 * N))
- assert np.allclose(b.shape, (3 * N,))
- x = scsp.linalg.spsolve(A, b)
- x1O, x2O, x3O = detensorizeLS(x, 3)
- assert np.allclose(x1O, x1, rtol = 1e-8)
- assert np.allclose(x2O, x2, rtol = 1e-8)
- assert np.allclose(x3O, x3, rtol = 1e-8)
-
-def test_sparse():
- N = 5
- A1 = scsp.eye(N, format = "csr")
- x1 = np.random.rand(N)
- b1 = A1.dot(x1)
- A2 = scsp.diags(np.arange(1, N + 1) * 2., 0, format = "csr")
- x2 = np.ones(N)
- b2 = A2.dot(x2)
- A, b = tensorizeLS([A1, A2], [b1, b2])
- assert np.allclose(A.shape, (2 * N, 2 * N))
- assert np.allclose(b.shape, (2 * N,))
- x = scsp.linalg.spsolve(A, b)
- x1O, x2O = detensorizeLS(x, sizes = [5, 5])
- assert np.allclose(x1O, x1, rtol = 1e-8)
- assert np.allclose(x2O, x2, rtol = 1e-8)