Coverage for pySDC/implementations/sweeper_classes/explicit.py: 0%
46 statements
« prev ^ index » next coverage.py v7.6.7, created at 2024-11-16 14:51 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2024-11-16 14:51 +0000
1from pySDC.core.sweeper import Sweeper
4class explicit(Sweeper):
5 """
6 Custom sweeper class, implements Sweeper.py
8 Attributes:
9 QE: explicit Euler integration matrix
10 """
12 def __init__(self, params):
13 """
14 Initialization routine for the custom sweeper
16 Args:
17 params: parameters for the sweeper
18 """
20 if 'QE' not in params:
21 params['QE'] = 'EE'
23 # call parent's initialization routine
24 super(explicit, self).__init__(params)
26 # integration matrix
27 self.QE = self.get_Qdelta_explicit(qd_type=self.params.QE)
29 def integrate(self):
30 """
31 Integrates the right-hand side
33 Returns:
34 list of dtype_u: containing the integral as values
35 """
37 # get current level and problem description
38 L = self.level
39 P = L.prob
41 me = []
43 # integrate RHS over all collocation nodes
44 for m in range(1, self.coll.num_nodes + 1):
45 # new instance of dtype_u, initialize values with 0
46 me.append(P.dtype_u(P.init, val=0.0))
47 for j in range(1, self.coll.num_nodes + 1):
48 me[-1] += L.dt * self.coll.Qmat[m, j] * L.f[j]
50 return me
52 def update_nodes(self):
53 """
54 Update the u- and f-values at the collocation nodes -> corresponds to a single sweep over all nodes
56 Returns:
57 None
58 """
60 # get current level and problem description
61 L = self.level
62 P = L.prob
64 # only if the level has been touched before
65 assert L.status.unlocked
67 # get number of collocation nodes for easier access
68 M = self.coll.num_nodes
70 # gather all terms which are known already (e.g. from the previous iteration)
71 # this corresponds to u0 + QF(u^k) - QEFE(u^k) + tau
73 # get QF(u^k)
74 integral = self.integrate()
75 for m in range(M):
76 # subtract QEFE(u^k)_m
77 for j in range(1, M + 1):
78 integral[m] -= L.dt * self.QE[m + 1, j] * L.f[j]
79 # add initial value
80 integral[m] += L.u[0]
81 # add tau if associated
82 if L.tau[m] is not None:
83 integral[m] += L.tau[m]
85 # do the sweep
86 for m in range(0, M):
87 # build new u, consisting of the known values from above and new values from previous nodes (at k+1)
88 L.u[m + 1] = P.dtype_u(integral[m])
89 for j in range(1, m + 1):
90 L.u[m + 1] += L.dt * self.QE[m + 1, j] * L.f[j]
92 # update function values
93 L.f[m + 1] = P.eval_f(L.u[m + 1], L.time + L.dt * self.coll.nodes[m])
95 # indicate presence of new values at this level
96 L.status.updated = True
98 return None
100 def compute_end_point(self):
101 """
102 Compute u at the right point of the interval
104 The value uend computed here is a full evaluation of the Picard formulation unless do_full_update==False
106 Returns:
107 None
108 """
110 # get current level and problem description
111 L = self.level
112 P = L.prob
114 # check if Mth node is equal to right point and do_coll_update is false, perform a simple copy
115 if self.coll.right_is_node and not self.params.do_coll_update:
116 # a copy is sufficient
117 L.uend = P.dtype_u(L.u[-1])
118 else:
119 # start with u0 and add integral over the full interval (using coll.weights)
120 L.uend = P.dtype_u(L.u[0])
121 for m in range(self.coll.num_nodes):
122 L.uend += L.dt * self.coll.weights[m] * L.f[m + 1]
123 # add up tau correction of the full interval (last entry)
124 if L.tau[-1] is not None:
125 L.uend += L.tau[-1]
127 return None