Skip to content

Commit a549854

Browse files
Removed nested explicit loop in Allen Cahn 2D FD exact solution (#435)
* Removed nested explicit loop in Allen Cahn 2D FD exact solution * Simplified hook for computing the radius for Allen-Cahn in TOMS project * Removed unused legacy function
1 parent 7e7e73f commit a549854

File tree

2 files changed

+31
-62
lines changed

2 files changed

+31
-62
lines changed

pySDC/implementations/problem_classes/AllenCahn_2D_FD.py

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -134,41 +134,6 @@ def __init__(
134134
self.work_counters['rhs'] = WorkCounter()
135135
self.work_counters['linear'] = WorkCounter()
136136

137-
@staticmethod
138-
def __get_A(N, dx):
139-
"""
140-
Helper function to assemble FD matrix A in sparse format.
141-
142-
Parameters
143-
----------
144-
N : list
145-
Number of degrees of freedom.
146-
dx : float
147-
Distance between two spatial nodes.
148-
149-
Returns
150-
-------
151-
A : scipy.sparse.csc_matrix
152-
Matrix in CSC format.
153-
"""
154-
155-
stencil = [1, -2, 1]
156-
zero_pos = 2
157-
158-
dstencil = np.concatenate((stencil, np.delete(stencil, zero_pos - 1)))
159-
offsets = np.concatenate(
160-
(
161-
[N[0] - i - 1 for i in reversed(range(zero_pos - 1))],
162-
[i - zero_pos + 1 for i in range(zero_pos - 1, len(stencil))],
163-
)
164-
)
165-
doffsets = np.concatenate((offsets, np.delete(offsets, zero_pos - 1) - N[0]))
166-
167-
A = sp.diags(dstencil, doffsets, shape=(N[0], N[0]), format='csc')
168-
A = sp.kron(A, sp.eye(N[0])) + sp.kron(sp.eye(N[1]), A)
169-
A *= 1.0 / (dx**2)
170-
return A
171-
172137
# noinspection PyTypeChecker
173138
def solve_system(self, rhs, factor, u0, t):
174139
"""
@@ -286,10 +251,9 @@ def eval_rhs(t, u):
286251
me[:] = self.generate_scipy_reference_solution(eval_rhs, t, u_init, t_init)
287252

288253
else:
289-
for i in range(self.nvars[0]):
290-
for j in range(self.nvars[1]):
291-
r2 = self.xvalues[i] ** 2 + self.xvalues[j] ** 2
292-
me[i, j] = np.tanh((self.radius - np.sqrt(r2)) / (np.sqrt(2) * self.eps))
254+
X, Y = np.meshgrid(self.xvalues, self.xvalues)
255+
r2 = X**2 + Y**2
256+
me[:] = np.tanh((self.radius - np.sqrt(r2)) / (np.sqrt(2) * self.eps))
293257

294258
return me
295259

pySDC/projects/TOMS/AllenCahn_monitor.py

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,45 @@
44

55

66
class monitor(hooks):
7+
phase_thresh = 0.0 # count everything above this threshold to the high phase.
8+
79
def __init__(self):
810
"""
911
Initialization of Allen-Cahn monitoring
1012
"""
11-
super(monitor, self).__init__()
13+
super().__init__()
1214

1315
self.init_radius = None
1416

17+
def get_exact_radius(self, t):
18+
return np.sqrt(max(self.init_radius**2 - 2.0 * t, 0))
19+
20+
@classmethod
21+
def get_radius(cls, u, dx):
22+
c = np.count_nonzero(u > cls.phase_thresh)
23+
return np.sqrt(c / np.pi) * dx
24+
25+
@staticmethod
26+
def get_interface_width(u, L):
27+
# TODO: How does this generalize to different phase transitions?
28+
rows1 = np.where(u[L.prob.init[0][0] // 2, : L.prob.init[0][0] // 2] > -0.99)
29+
rows2 = np.where(u[L.prob.init[0][0] // 2, : L.prob.init[0][0] // 2] < 0.99)
30+
31+
return (rows2[0][-1] - rows1[0][0]) * L.prob.dx / L.prob.eps
32+
1533
def pre_run(self, step, level_number):
1634
"""
17-
Overwrite standard pre run hook
35+
Record radius of the blob, exact radius and interface width.
1836
1937
Args:
2038
step (pySDC.Step.step): the current step
2139
level_number (int): the current level number
2240
"""
23-
super(monitor, self).pre_run(step, level_number)
41+
super().pre_run(step, level_number)
2442
L = step.levels[0]
2543

26-
c = np.count_nonzero(L.u[0] > 0.0)
27-
radius = np.sqrt(c / np.pi) * L.prob.dx
28-
29-
radius1 = 0
30-
rows, cols = np.where(L.u[0] > 0.0)
31-
for r in rows:
32-
radius1 = max(radius1, abs(L.prob.xvalues[r]))
33-
34-
rows1 = np.where(L.u[0][int((L.prob.init[0][0]) / 2), : int((L.prob.init[0][0]) / 2)] > -0.99)
35-
rows2 = np.where(L.u[0][int((L.prob.init[0][0]) / 2), : int((L.prob.init[0][0]) / 2)] < 0.99)
36-
interface_width = (rows2[0][-1] - rows1[0][0]) * L.prob.dx / L.prob.eps
37-
44+
radius = self.get_radius(L.u[0], L.prob.dx)
45+
interface_width = self.get_interface_width(L.u[0], L)
3846
self.init_radius = L.prob.radius
3947

4048
if L.time == 0.0:
@@ -68,24 +76,21 @@ def pre_run(self, step, level_number):
6876

6977
def post_step(self, step, level_number):
7078
"""
71-
Overwrite standard post step hook
79+
Record radius of the blob, exact radius and interface width.
7280
7381
Args:
7482
step (pySDC.Step.step): the current step
7583
level_number (int): the current level number
7684
"""
77-
super(monitor, self).post_step(step, level_number)
85+
super().post_step(step, level_number)
7886

7987
# some abbreviations
8088
L = step.levels[0]
8189

82-
c = np.count_nonzero(L.uend >= 0.0)
83-
radius = np.sqrt(c / np.pi) * L.prob.dx
90+
radius = self.get_radius(L.uend, L.prob.dx)
91+
interface_width = self.get_interface_width(L.uend, L)
8492

85-
exact_radius = np.sqrt(max(self.init_radius**2 - 2.0 * (L.time + L.dt), 0))
86-
rows1 = np.where(L.uend[int((L.prob.init[0][0]) / 2), : int((L.prob.init[0][0]) / 2)] > -0.99)
87-
rows2 = np.where(L.uend[int((L.prob.init[0][0]) / 2), : int((L.prob.init[0][0]) / 2)] < 0.99)
88-
interface_width = (rows2[0][-1] - rows1[0][0]) * L.prob.dx / L.prob.eps
93+
exact_radius = self.get_exact_radius(L.time + L.dt)
8994

9095
self.add_to_stats(
9196
process=step.status.slot,

0 commit comments

Comments
 (0)