Skip to content

Commit ff63941

Browse files
Prepare for dynamic timesteps
This patch removes the Dynamic.set_timestep method, which is not a good fit in a situation where time steps may vary. Instead the add_and_plot method is rewritten to use dimensional times rather than a fixed-length deque, and the newmark_defo and newmark_velo methods receive a timestep argument to replace the attribute. The latter will be further modified in a subsequent commit to allow for truly dynamic time steps.
1 parent 8ed9e29 commit ff63941

2 files changed

Lines changed: 31 additions & 31 deletions

File tree

turek-hron-fsi3/fluid-nutils/fluid.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,22 +86,23 @@ class Dynamic:
8686
gamma: float = .8
8787
beta: float = .4
8888

89-
def set_timestep(self, timestep):
90-
self.timestep = timestep
91-
self.timeseries = defaultdict(
92-
deque(maxlen=round(self.window / timestep)).copy)
89+
def __post_init__(self):
90+
self.timeseries = defaultdict(deque)
9391

9492
def ramp_up(self, t):
9593
return .5 - .5 * numpy.cos(numpy.pi * min(t / self.init, 1))
9694

97-
def add_and_plot(self, name, t, v, ax):
95+
def add_and_plot(self, name, t, tunit, v, vunit, ax):
9896
'Add data point and plot time series for past window.'
9997

10098
d = self.timeseries[name]
10199
d.append((t, v))
102-
times, values = numpy.stack(d, axis=1)
100+
while t - d[0][0] > self.window:
101+
d.popleft()
102+
times = numpy.array([t / tunit for t, _ in d])
103+
values = numpy.array([v / vunit for _, v in d])
103104
ax.plot(times, values)
104-
ax.set_ylabel(name)
105+
ax.set_ylabel(f'{name} [{vunit}]')
105106
ax.grid()
106107
ax.autoscale(enable=True, axis='x', tight=True)
107108

@@ -123,19 +124,19 @@ def newmark_defo_args(self, d, d0=0., u0δt=0., a0δt2=0., **args):
123124
aδt2 = a0δt2 + δaδt2
124125
return dict(args, d=d + uδt + .5 * aδt2, d0=d, u0δt=uδt, a0δt2=aδt2)
125126

126-
def newmark_defo(self, d):
127+
def newmark_defo(self, d, timestep):
127128
D = self.newmark_defo_args(
128129
d, *[function.replace_arguments(d, [('d', t)]) for t in ('d0', 'u0δt', 'a0δt2')])
129-
return D['u0δt'] / self.timestep, D['a0δt2'] / self.timestep**2
130+
return D['u0δt'] / timestep, D['a0δt2'] / timestep**2
130131

131132
def newmark_velo_args(self, u, u0=0., a0δt=0., **args):
132133
aδt = a0δt + (u - u0 - a0δt) / self.gamma
133134
return dict(args, u=u + aδt, u0=u, a0δt=aδt)
134135

135-
def newmark_velo(self, u):
136+
def newmark_velo(self, u, timestep):
136137
D = self.newmark_velo_args(
137138
u, *[function.replace_arguments(u, [('u', t)]) for t in ('u0', 'a0δt')])
138-
return D['a0δt'] / self.timestep
139+
return D['a0δt'] / timestep
139140

140141

141142
def main(domain: Domain = Domain(), fluid: Fluid = Fluid(), dynamic: Dynamic = Dynamic()):
@@ -164,7 +165,6 @@ def main(domain: Domain = Domain(), fluid: Fluid = Fluid(), dynamic: Dynamic = D
164165
participant.initialize()
165166

166167
timestep = participant.get_max_time_step_size()
167-
dynamic.set_timestep(timestep * precice_time)
168168

169169
ns = Namespace()
170170
ns.δ = function.eye(2)
@@ -184,8 +184,8 @@ def main(domain: Domain = Domain(), fluid: Fluid = Fluid(), dynamic: Dynamic = D
184184

185185
ns.urel = topo.field('u', btype='std', degree=2,
186186
shape=(2,)) * fluid.velocity
187-
ns.v, ns.a = dynamic.newmark_defo(ns.d)
188-
ns.arel = dynamic.newmark_velo(ns.urel)
187+
ns.v, ns.a = dynamic.newmark_defo(ns.d, timestep * precice_time)
188+
ns.arel = dynamic.newmark_velo(ns.urel, timestep * precice_time)
189189
ns.u_i = 'v_i + urel_i'
190190
ns.DuDt_i = 'a_i + arel_i + ∇_j(u_i) urel_j' # material derivative
191191

@@ -252,7 +252,7 @@ def main(domain: Domain = Domain(), fluid: Fluid = Fluid(), dynamic: Dynamic = D
252252
if participant.requires_writing_checkpoint():
253253
checkpoint = t, args
254254

255-
t += dynamic.timestep
255+
t += timestep * precice_time
256256

257257
cons['d'][r_where] = participant.read_data(
258258
r_name, 'Displacement', r_ids, timestep)
@@ -298,9 +298,9 @@ def main(domain: Domain = Domain(), fluid: Fluid = Fluid(), dynamic: Dynamic = D
298298
log.info(f'drag: {D:N/m}')
299299
with export.mplfigure('force.jpg', dpi=150) as fig:
300300
dynamic.add_and_plot(
301-
'lift [N/m]', t / 's', L / 'N/m', ax=fig.add_subplot(211))
301+
'lift', t, 's', L, 'N/m', ax=fig.add_subplot(211))
302302
dynamic.add_and_plot(
303-
'drag [N/m]', t / 's', D / 'N/m', ax=fig.add_subplot(212, xlabel='time [s]'))
303+
'drag', t, 's', D, 'N/m', ax=fig.add_subplot(212, xlabel='time [s]'))
304304

305305
participant.finalize()
306306

turek-hron-fsi3/solid-nutils/solid.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,20 @@ class Dynamic:
7777
gamma: float = .8
7878
beta: float = .4
7979

80-
def set_timestep(self, timestep):
81-
self.timestep = timestep
82-
self.timeseries = defaultdict(
83-
deque(maxlen=round(self.window / timestep)).copy)
80+
def __post_init__(self):
81+
self.timeseries = defaultdict(deque)
8482

85-
def add_and_plot(self, name, t, v, ax):
83+
def add_and_plot(self, name, t, tunit, v, vunit, ax):
8684
'Add data point and plot time series for past window.'
8785

8886
d = self.timeseries[name]
8987
d.append((t, v))
90-
times, values = numpy.stack(d, axis=1)
88+
while t - d[0][0] > self.window:
89+
d.popleft()
90+
times = numpy.array([t / tunit for t, _ in d])
91+
values = numpy.array([v / vunit for _, v in d])
9192
ax.plot(times, values)
92-
ax.set_ylabel(name)
93+
ax.set_ylabel(f'{name} [{vunit}]')
9394
ax.grid()
9495
ax.autoscale(enable=True, axis='x', tight=True)
9596

@@ -111,10 +112,10 @@ def newmark_defo_args(self, d, d0=0., u0δt=0., a0δt2=0., **args):
111112
aδt2 = a0δt2 + δaδt2
112113
return dict(args, d=d + uδt + .5 * aδt2, d0=d, u0δt=uδt, a0δt2=aδt2)
113114

114-
def newmark_defo(self, d):
115+
def newmark_defo(self, d, timestep):
115116
D = self.newmark_defo_args(
116117
d, *[function.replace_arguments(d, [('d', t)]) for t in ('d0', 'u0δt', 'a0δt2')])
117-
return D['u0δt'] / self.timestep, D['a0δt2'] / self.timestep**2
118+
return D['u0δt'] / timestep, D['a0δt2'] / timestep**2
118119

119120

120121
def main(domain: Domain = Domain(), solid: Solid = Solid(), dynamic: Dynamic = Dynamic()):
@@ -131,7 +132,6 @@ def main(domain: Domain = Domain(), solid: Solid = Solid(), dynamic: Dynamic = D
131132
participant.initialize()
132133

133134
timestep = participant.get_max_time_step_size()
134-
dynamic.set_timestep(timestep * precice_time)
135135

136136
ns = Namespace()
137137
ns.δ = function.eye(2)
@@ -144,7 +144,7 @@ def main(domain: Domain = Domain(), solid: Solid = Solid(), dynamic: Dynamic = D
144144

145145
ns.d = topo.field('d', btype='std', degree=2, shape=(
146146
2,)) * domain.cylinder_radius # deformation at the end of the timestep
147-
ns.v, ns.a = dynamic.newmark_defo(ns.d)
147+
ns.v, ns.a = dynamic.newmark_defo(ns.d, timestep * precice_time)
148148

149149
ns.dtest = function.replace_arguments(
150150
ns.d, 'd:dtest') / (solid.shear_modulus * domain.cylinder_radius**2)
@@ -182,7 +182,7 @@ def main(domain: Domain = Domain(), solid: Solid = Solid(), dynamic: Dynamic = D
182182
if participant.requires_writing_checkpoint():
183183
checkpoint = t, args
184184

185-
t += dynamic.timestep
185+
t += timestep * precice_time
186186

187187
args = dynamic.newmark_defo_args(**args)
188188
args['traction'] = participant.read_data(
@@ -213,9 +213,9 @@ def main(domain: Domain = Domain(), solid: Solid = Solid(), dynamic: Dynamic = D
213213
log.info(f'ux: {ux:mm}')
214214
with export.mplfigure('tip-displacement.jpg', dpi=150) as fig:
215215
dynamic.add_and_plot(
216-
'uy [mm]', t / 's', uy / 'mm', ax=fig.add_subplot(211))
216+
'uy', t, 's', uy, 'mm', ax=fig.add_subplot(211))
217217
dynamic.add_and_plot(
218-
'ux [mm]', t / 's', ux / 'mm', ax=fig.add_subplot(212, xlabel='time [s]'))
218+
'ux', t, 's', ux, 'mm', ax=fig.add_subplot(212, xlabel='time [s]'))
219219

220220
participant.finalize()
221221

0 commit comments

Comments
 (0)