Skip to content

Commit 106f623

Browse files
committed
TL: adding local work
1 parent 9d0223e commit 106f623

File tree

8 files changed

+228
-150
lines changed

8 files changed

+228
-150
lines changed

blockops/blockIterationGenerator.py

Lines changed: 65 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,10 @@
44
import re
55

66

7-
SIMPLE_FORM = False
7+
SIMPLE_FORM = True
88

99
class BlockIterationGenerator():
1010

11-
def __init__(self):
12-
pass
13-
1411
def solve(self, lhs, rhs, u):
1512
tmp = []
1613
for i in range(len(u)):
@@ -38,8 +35,8 @@ def createZeros(self, n):
3835
return sy.zeros(n, 1)
3936

4037
def jacobi(self, A, u, f, w=1):
41-
D = A.lower_triangular(0).upper_triangular(0)
42-
return self.simplifyElementwise(u + w * D.inv() * (f - A * u))
38+
Dinv = sy.diag([d**(-1) for d in A.diagonal()[:]], unpack=True)
39+
return self.simplifyElementwise(u + w * Dinv * (f - A * u))
4340

4441
def gausseidel(self, A, u, f, A_c, u_res):
4542
return self.solve(lhs=A_c * (u_res - u), rhs=f - A * u, u=u_res)
@@ -59,13 +56,13 @@ def checkResults(self, u):
5956
tmp = gen.generateBlockRule()
6057

6158
if SIMPLE_FORM:
62-
dico = self.generateData(6, 4)
59+
dico = self.symbols
6360
subDico = {}
6461
prol = 1
6562
rest = 1
6663
for i, (phiOp, chiOp, TCtoF, TFtoC, prop) in enumerate(zip(
6764
dico['phi'], dico['chi'], dico['T_c_to_f'], dico['T_f_to_c'],
68-
['F', 'G', 'H', 'K'])):
65+
['F', 'G', 'H', 'K', 'L', 'M'])):
6966
sym = sy.symbols(prop, commutative=False)
7067
subDico[prol*phiOp**(-1)*chiOp*rest] = sym
7168
subDico[prol * (phiOp**(-1)*chiOp)**2 * rest] = sym**2
@@ -81,31 +78,34 @@ def checkResults(self, u):
8178
else:
8279
gen.check(expr=u[i], n=i + 1)
8380

84-
def generateData(self, n, L, pre_s=1, post_s=0):
81+
def generateSymbols(self, nBlocks, nLevels, nPreSmooth=1, nPostSmooth=0):
8582
save_symbols = {}
8683
u_0 = sy.Symbol(r'u_0', commutative=False)
87-
phi = [sy.Symbol(f'\phi_{i}', commutative=False) for i in range(L)]
88-
chi = [sy.Symbol(f'\chi_{i}', commutative=False) for i in range(L)]
89-
T_c_to_f = [sy.Symbol(f'T_{i + 1}^{i}', commutative=False) for i in range(L)]
90-
T_f_to_c = [sy.Symbol(f'T_{i}^{i + 1}', commutative=False) for i in range(L)]
91-
A = [sy.Matrix(np.eye(n, dtype=int) * phi[i]) + sy.Matrix(np.eye(n, k=-1, dtype=int) * -chi[i]) for i in
92-
range(L)]
84+
phi = [sy.Symbol(f'\phi_{i}', commutative=False) for i in range(nLevels)]
85+
chi = [sy.Symbol(f'\chi_{i}', commutative=False) for i in range(nLevels)]
86+
T_c_to_f = [sy.Symbol(f'T_{i + 1}^{i}', commutative=False) for i in range(nLevels)]
87+
T_f_to_c = [sy.Symbol(f'T_{i}^{i + 1}', commutative=False) for i in range(nLevels)]
88+
A = [sy.Matrix(np.eye(nBlocks, dtype=int) * phi[i]) + sy.Matrix(np.eye(nBlocks, k=-1, dtype=int) * -chi[i]) for i in
89+
range(nLevels)]
9390
u_k = [
94-
[self.createVec('u^0', n=n, ss=save_symbols), self.createVec('u^0', n=n, ss=save_symbols)] if i == 0 else [
95-
self.createVec(f'u^0_{i}', n=n, ss=save_symbols),
96-
self.createZeros(n)] for i in range(L)]
91+
[self.createVec('u^0', n=nBlocks, ss=save_symbols),
92+
self.createVec('u^0', n=nBlocks, ss=save_symbols)] if i == 0 else [
93+
self.createVec(f'u^0_{i}', n=nBlocks, ss=save_symbols),
94+
self.createZeros(nBlocks)] for i in range(nLevels)]
9795
u_k_1 = [
98-
[self.createVec('u^1', n=n, ss=save_symbols), self.createVec('u^1', n=n, ss=save_symbols)] if i == 0 else [
99-
self.createVec(f'u^1_{i}', n=n, ss=save_symbols),
100-
self.createVec(f'u^1_{i}', n=n, ss=save_symbols)] for i in
101-
range(L)]
102-
f = [sy.Matrix([[chi[0] * u_0 if i == 0 else 0 for i in range(n)]]).transpose() if i == 0 else None for i in
103-
range(L)]
104-
pre_smoothing = [pre_s for _ in range(L)]
105-
post_smoothing = [post_s for _ in range(L)]
106-
return {
107-
'L': L,
108-
'n': n,
96+
[self.createVec('u^1', n=nBlocks, ss=save_symbols),
97+
self.createVec('u^1', n=nBlocks, ss=save_symbols)] if i == 0 else [
98+
self.createVec(f'u^1_{i}', n=nBlocks, ss=save_symbols),
99+
self.createVec(f'u^1_{i}', n=nBlocks, ss=save_symbols)] for i in
100+
range(nLevels)]
101+
f = [sy.Matrix([[chi[0] * u_0 if i == 0 else 0 for i in range(nBlocks)]]).transpose()
102+
if i == 0 else None for i in range(nLevels)]
103+
pre_smoothing = [nPreSmooth for _ in range(nLevels)]
104+
post_smoothing = [nPostSmooth for _ in range(nLevels)]
105+
106+
self.symbols = {
107+
'L': nLevels,
108+
'n': nBlocks,
109109
'phi': phi,
110110
'chi': chi,
111111
'T_c_to_f': T_c_to_f,
@@ -117,21 +117,23 @@ def generateData(self, n, L, pre_s=1, post_s=0):
117117
'pre_smoothing': pre_smoothing,
118118
'post_smoothing': post_smoothing,
119119
}
120+
return self.symbols
120121

121122

122123
class PararealGenerator(BlockIterationGenerator):
123124

124-
def __init__(self, n):
125-
super().__init__()
126-
res = self.parareal(settings=self.generateData(n=n, L=2))
127-
self.checkResults(res)
128-
129-
def parareal(self, settings, overlapping=False):
130-
u = settings['u_k']
131-
chi = settings['chi']
132-
A = settings['A']
133-
f = settings['f']
134-
u_k_1 = settings['u_k_1']
125+
def __init__(self, nBlocks):
126+
self.generateSymbols(nBlocks=nBlocks, nLevels=2)
127+
self.res = self.parareal()
128+
self.checkResults(self.res)
129+
130+
def parareal(self, overlapping=False):
131+
symbols = self.symbols
132+
u = symbols['u_k']
133+
chi = symbols['chi']
134+
A = symbols['A']
135+
f = symbols['f']
136+
u_k_1 = symbols['u_k_1']
135137
jac = self.jacobi(u=u[0][1], A=A[0], f=f[0])
136138
if overlapping:
137139
jac = self.jacobi(u=jac, A=A[0], f=f[0])
@@ -140,23 +142,25 @@ def parareal(self, settings, overlapping=False):
140142

141143

142144
class MultilevelGenerator(BlockIterationGenerator):
143-
def __init__(self, n, L, pre_smoothing=1, post_smoothing=1):
144-
super().__init__()
145-
res = self.multilevel(
146-
setting=self.generateData(n=n, L=L, pre_s=pre_smoothing, post_s=post_smoothing))
147-
self.checkResults(res)
148-
149-
def multilevel(self, setting, l=0):
150-
L = setting['L'] - 1
151-
T_c_f_s = setting['T_c_to_f']
152-
T_f_c_s = setting['T_f_to_c']
153-
A = setting['A']
154-
u_k = setting['u_k']
155-
u_k_1 = setting['u_k_1']
156-
f = setting['f']
157-
pre = setting['pre_smoothing']
158-
post = setting['post_smoothing']
159-
chi = setting['chi']
145+
146+
def __init__(self, nBlocks, nLevels, nPreSmooth=1, nPostSmooth=1):
147+
self.generateSymbols(nBlocks=nBlocks, nLevels=nLevels, nPreSmooth=nPreSmooth, nPostSmooth=nPostSmooth)
148+
self.res = self.multilevel()
149+
self.checkResults(self.res)
150+
151+
def multilevel(self, l=0):
152+
symbols = self.symbols
153+
154+
L = symbols['L'] - 1
155+
T_c_f_s = symbols['T_c_to_f']
156+
T_f_c_s = symbols['T_f_to_c']
157+
A = symbols['A']
158+
u_k = symbols['u_k']
159+
u_k_1 = symbols['u_k_1']
160+
f = symbols['f']
161+
pre = symbols['pre_smoothing']
162+
post = symbols['post_smoothing']
163+
chi = symbols['chi']
160164

161165
state = {}
162166
state2 = {}
@@ -179,7 +183,7 @@ def multilevel(self, setting, l=0):
179183
else:
180184
u_k_1[l][1] = self.jacobi(u=u_k_1[l][1], A=A[l], f=f[l])
181185
f[l + 1] = (T_f_c_s[l] * (f[l] - A[l] * u_k_1[l][1]))
182-
self.multilevel(l=l + 1, setting=setting)
186+
self.multilevel(l=l+1)
183187
tmp = self.solve(lhs=u_k_1[l][0],
184188
rhs=u_k_1[l][1] + T_c_f_s[l] * u_k_1[l + 1][0],
185189
u=u_k_1[l + 1][0]).subs(state2)
@@ -285,5 +289,6 @@ def u(n, k):
285289
return tmp
286290

287291

288-
# PararealGenerator(n=6)
289-
MultilevelGenerator(n=6, L=3, pre_smoothing=1, post_smoothing=0)
292+
if __name__ == "__main__":
293+
# PararealGenerator(n=4)
294+
MultilevelGenerator(nBlocks=7, nLevels=3, nPreSmooth=1, nPostSmooth=0)

blockops/iteration.py

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import numpy as np
99
import sympy as sy
1010
from typing import Dict
11-
import time
1211

1312
from blockops.block import BlockOperator, I
1413
from blockops.run import PintRun
@@ -289,7 +288,7 @@ def plotSchedule(self, N: int, K, nProc: int, schedulerType: str = 'BLOCK-BY-BLO
289288
pool = TaskPool(run=run)
290289
schedule = getSchedule(taskPool=pool, nProc=nProc, nPoints=N + 1, schedulerType=schedulerType)
291290
return schedule.plotPlotly()
292-
291+
293292
# schedule.plot(figName=None if self.name is None else self.name + f' ({schedule.NAME} schedule)',
294293
# figSize=figSize, saveFig=saveFig)
295294

@@ -318,22 +317,26 @@ def register(cls):
318317
'explicit': 'F'}
319318

320319

320+
def u(n, k):
321+
n = "" if n == 0 else f"+{n}" if n > 0 else f"{n}"
322+
k = "" if k == 0 else f"+{k}" if k > 0 else f"{k}"
323+
return "u_{n"+n+"}^{k"+k+"}"
324+
325+
321326
@register
322327
class Parareal(BlockIteration):
323328
needApprox = True
324329

325-
def __init__(self, implicitForm=True, approxPred=True, **blockOps):
326-
if implicitForm:
327-
B00 = "(phi**(-1)*chi-phiApprox**(-1)*chi) * u_{n}^k"
328-
B01 = "phiApprox**(-1)*chi * u_{n}^{k+1}"
329-
predictor = "phiApprox**(-1)*chi" if approxPred else None
330-
else:
331-
B00 = "(F-G) * u_{n}^k"
332-
B01 = "G * u_{n}^{k+1}"
333-
predictor = "G" if approxPred else None
334-
update = f"{B00} + {B01}"
330+
def __init__(self, implicitForm=True, approxPred=True, nOverlap=0, **blockOps):
331+
F = "(phi**(-1)*chi)" if implicitForm else "F"
332+
G = "(phiApprox**(-1)*chi)" if implicitForm else "G"
333+
predictor = G if approxPred else None
334+
335+
overlapTerm = "" if nOverlap == 0 else f"*{F}**{nOverlap}"
336+
update = f"({F}-{G}){overlapTerm} {u(0-nOverlap, 0)} + {G} {u(0, 1)}"
335337
propagator = DEFAULT_PROP['implicit'] if implicitForm \
336338
else DEFAULT_PROP['explicit']
339+
print(update)
337340
super().__init__(update, propagator, predictor,
338341
rules=None, name='Parareal', **blockOps)
339342

@@ -344,12 +347,12 @@ class ABJ(BlockIteration):
344347

345348
def __init__(self, implicitForm=True, approxPred=True, **blockOps):
346349
if implicitForm:
347-
B00 = "phiApprox**(-1)*chi * u_{n}^k"
348-
B10 = "(I-phiApprox**-1 * phi) * u_{n+1}^{k}"
350+
B00 = "phiApprox**(-1)*chi" + u(0, 0)
351+
B10 = "(I-phiApprox**-1 * phi)" + u(1, 0)
349352
predictor = "phiApprox**(-1)*chi" if approxPred else None
350353
else:
351-
B00 = "G * u_{n}^k"
352-
B10 = "(I-G*F**(-1)) * u_{n}^{k+1}"
354+
B00 = "G" + u(0, 0)
355+
B10 = "(I-G*F**(-1))" + u(1, 0)
353356
predictor = "G" if approxPred else None
354357
update = f"{B10} + {B00}"
355358
blockOps['I'] = I
@@ -365,12 +368,12 @@ class ABGS(BlockIteration):
365368

366369
def __init__(self, implicitForm=True, approxPred=True, **blockOps):
367370
if implicitForm:
368-
B01 = "phiApprox**(-1)*chi * u_{n}^{k+1}"
369-
B10 = "(I-phiApprox**-1 * phi) * u_{n+1}^{k}"
371+
B01 = "phiApprox**(-1)*chi" + u(0, 1)
372+
B10 = "(I-phiApprox**-1 * phi)" + u(1, 0)
370373
predictor = "phiApprox**(-1)*chi" if approxPred else None
371374
else:
372-
B01 = "G * u_{n}^{k+1}"
373-
B10 = "(I-G*F**(-1)) * u_{n}^{k+1}"
375+
B01 = "G" + u(0, 1)
376+
B10 = "(I-G*F**(-1))" + u(1, 0)
374377
predictor = "G" if approxPred else None
375378
update = f"{B10} + {B01}"
376379
blockOps['I'] = I
@@ -384,20 +387,20 @@ def __init__(self, implicitForm=True, approxPred=True, **blockOps):
384387
class TMG(BlockIteration):
385388
needCoarse = True
386389

387-
def __init__(self, coarsePred=True, **blockOps):
388-
omega = blockOps.get('omega', 1)
389-
blockOps.update({'omega': omega})
390+
def __init__(self, coarsePred=True, omega=1, nRelax=1, **blockOps):
390391
phiC = "TCtoF * phiCoarse**(-1) * TFtoC"
392+
391393
B01 = f"{phiC}*chi"" * u_{n}^{k+1}"
392394
B00 = f"omega*(phi**(-1)*chi - {phiC}*chi)"" * u_{n}^{k}"
393395
B10 = f"(1-omega)*(I-{phiC}*phi)"" * u_{n+1}^{k}"
396+
394397
predictor = f"{phiC}*chi" if coarsePred else None
395398
update = f"{B10} + {B01} + {B00}"
396399
blockOps['I'] = I
397400
rules = [("TFtoC * TCtoF", I)]
398401
propagator = DEFAULT_PROP['implicit']
399402
super().__init__(update, propagator, predictor,
400-
rules=rules, name='TMG', **blockOps)
403+
rules=rules, name='TMG', omega=1, **blockOps)
401404
self.omega = omega
402405

403406

blockops/problem.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class BlockProblem(ParamClass):
7171
**schemeArgs :
7272
Additional keyword arguments used for the time-discretization scheme.
7373
"""
74-
def __init__(self, lam, tEnd, nBlocks, scheme, u0=1, **schemeArgs):
74+
def __init__(self, lam, tEnd, nBlocks, scheme, u0=1.0, **schemeArgs):
7575

7676
# Initialize parameters
7777
self.initialize(locals())
@@ -114,6 +114,10 @@ def __init__(self, lam, tEnd, nBlocks, scheme, u0=1, **schemeArgs):
114114
if np.size(lam) == 1:
115115
self.u0 = self.u0.squeeze(axis=0)
116116

117+
@property
118+
def lamDt(self):
119+
return self.lam*self.dt
120+
117121
@property
118122
def points(self):
119123
return self.scheme.points
@@ -166,7 +170,7 @@ def setApprox(self, scheme, **schemeArgs):
166170
raise ValueError(f'{scheme} scheme is not implemented')
167171
self.schemeApprox = SCHEMES[scheme](**schemeArgs)
168172
self.phiApprox, _ = self.schemeApprox.getBlockOperators(
169-
self.lam*self.dt, r'\tilde{\phi}', r'\tilde{\chi}')
173+
self.lamDt, r'\tilde{\phi}', r'\tilde{\chi}')
170174
self.propApprox = self.phiApprox**(-1) * self.chi
171175

172176
# Eventually set the coarse approximate block operators
@@ -186,7 +190,7 @@ def approxIsSet(self):
186190
# -------------------------------------------------------------------------
187191
# Method for coarse level operators
188192
# -------------------------------------------------------------------------
189-
def setCoarseLevel(self, nPoints, **schemeArgs):
193+
def setCoarseLevel(self, nPoints, tType="GEOM", **schemeArgs):
190194
# Retrieve parameters and BlockScheme class from fine level
191195
params = self.scheme.getParamsValue()
192196
params.update(schemeArgs)
@@ -196,11 +200,11 @@ def setCoarseLevel(self, nPoints, **schemeArgs):
196200
# Build coarse block operators
197201
self.schemeCoarse = BlockScheme(**params)
198202
self.phiCoarse, self.chiCoarse = self.schemeCoarse.getBlockOperators(
199-
self.lam*self.dt, r'\phi_C', r'\chi_C')
203+
self.lamDt, r'\phi_C', r'\chi_C')
200204

201205
# Build transfer operators
202206
TFtoC, TCtoF = self.scheme.getTransferMatrices(
203-
self.pointsCoarse, vectorized=self.nLam > 1)
207+
self.pointsCoarse, self.lamDt, tType=tType)
204208
self.TFtoC = BlockOperator('T_F^C', matrix=TFtoC, cost=0)
205209
self.TCtoF = BlockOperator('T_C^F', matrix=TCtoF, cost=0)
206210

@@ -355,7 +359,7 @@ def getError(self, uNum='fine', uRef='exact') -> np.ndarray:
355359
# -------------------------------------------------------------------------
356360
# Method for block iterations
357361
# -------------------------------------------------------------------------
358-
def getBlockIteration(self, algo: str) -> BlockIteration:
362+
def getBlockIteration(self, algo:str, **algoArgs) -> BlockIteration:
359363
"""
360364
Generate a block iteration object associated to the block problem.
361365
@@ -370,24 +374,27 @@ def getBlockIteration(self, algo: str) -> BlockIteration:
370374
The block iteration object.
371375
"""
372376
try:
377+
373378
BlockIter = ALGORITHMS[algo]
374379
if BlockIter.needApprox and not self.approxIsSet:
375380
raise ValueError(f'{algo} need an approximate block operator')
376381
if BlockIter.needCoarse and not self.coarseIsSet:
377382
raise ValueError(f'{algo} need a coarse block operator')
378-
blockIter = BlockIter(
383+
384+
blockIter = BlockIter(**algoArgs,
379385
phi=self.phi, phiApprox=self.phiApprox, chi=self.chi,
380386
phiCoarse=self.phiCoarse, chiCoarse=self.chiCoarse,
381387
TFtoC=self.TFtoC, TCtoF=self.TCtoF,
382388
phiCoarseApprox=self.phiCoarseApprox)
383389
blockIter.prob = self
390+
384391
return blockIter
392+
385393
except KeyError:
386394
raise NotImplementedError(
387395
f'block iteration for {algo} not implemented')
388396

389397

390-
391398
if __name__ == '__main__':
392399
# Quick module testing
393400

0 commit comments

Comments
 (0)