Skip to content

Commit 09ab709

Browse files
Fix subcycling and checkpointing for two-scale-heat-conduction participant macro-dumux (#666)
* [macro-dumux] Handle subcycling in macro-dumux. Fix checkpointing. * [macro-dumux] Warn about different dt after solve * [macro-dumux] Negotiate dt before solve * [macro-dumux] Advance DuMux by default after solve * [macro-dumux] Cleanup time loop * Add changelog entry * Formatting and making code comment more informative --------- Co-authored-by: Ishaan Desai <[email protected]>
1 parent 24d9214 commit 09ab709

File tree

4 files changed

+82
-76
lines changed

4 files changed

+82
-76
lines changed

changelog-entries/666.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Fix subcycling and checkpointing in macro-dumux of two-scale-heat-conduction [#666](https://github.com/precice/tutorials/pull/666)

two-scale-heat-conduction/macro-dumux/appl/main.cc

Lines changed: 78 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ int main(int argc, char **argv)
100100

101101
auto &couplingParticipant = Dumux::Precice::CouplingAdapter::getInstance();
102102

103-
if (getParam<bool>("Precice.RunWithCoupling") == true) {
103+
const auto runWithCoupling = getParam<bool>("Precice.RunWithCoupling");
104+
105+
if (runWithCoupling) {
104106
couplingParticipant.announceSolver("macro-heat", preciceConfigFilename,
105107
mpiHelper.rank(), mpiHelper.size());
106108
// verify that dimensions match
@@ -132,13 +134,13 @@ int main(int argc, char **argv)
132134
std::cout << " ;" << std::endl;
133135
}
134136
}
137+
135138
std::cout << "Number of Coupled Cells:" << coupledElementIdxs.size()
136139
<< std::endl;
137140

138-
// initialize preCICE
139141
auto numberOfElements =
140142
coords.size() / couplingParticipant.getMeshDimensions(meshName);
141-
if (getParam<bool>("Precice.RunWithCoupling") == true) {
143+
if (runWithCoupling) {
142144
couplingParticipant.setMesh(meshName, coords);
143145

144146
// couples between dumux element indices and preciceIndices;
@@ -154,7 +156,7 @@ int main(int argc, char **argv)
154156
const std::string writeDataConcentration = "concentration";
155157
// const std::string writeDataTemperature = "temperature";
156158

157-
if (getParam<bool>("Precice.RunWithCoupling") == true) {
159+
if (runWithCoupling) {
158160
couplingParticipant.announceQuantity(meshName, readDatak00);
159161
couplingParticipant.announceQuantity(meshName, readDatak01);
160162
couplingParticipant.announceQuantity(meshName, readDatak10);
@@ -171,13 +173,17 @@ int main(int argc, char **argv)
171173
problem->applyInitialSolution(x);
172174
auto xOld = x;
173175

176+
auto xCheckpoint = x;
177+
double timeCheckpoint = 0.0;
178+
int timeStepCheckpoint = 0;
179+
174180
// initialize the coupling data
175181
std::vector<double> temperatures;
176182
for (int solIdx = 0; solIdx < numberOfElements; ++solIdx) {
177183
temperatures.push_back(x[solIdx][problem->returnTemperatureIdx()]);
178184
};
179185

180-
if (getParam<bool>("Precice.RunWithCoupling") == true) {
186+
if (runWithCoupling) {
181187
couplingParticipant.writeQuantityVector(meshName, writeDataConcentration,
182188
temperatures);
183189
if (couplingParticipant
@@ -203,7 +209,7 @@ int main(int argc, char **argv)
203209
auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry);
204210
gridVariables->init(x);
205211

206-
// intialize the vtk output module
212+
// initialize the vtk output module
207213
using IOFields = GetPropType<TypeTag, Properties::IOFields>;
208214
VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, x,
209215
problem->name());
@@ -220,7 +226,7 @@ int main(int argc, char **argv)
220226
// output every vtkOutputInterval time step
221227
const int vtkOutputInterval = getParam<int>("TimeLoop.OutputInterval");
222228

223-
// initialize
229+
// initialize preCICE
224230
couplingParticipant.initialize();
225231

226232
// time loop parameters
@@ -229,7 +235,7 @@ int main(int argc, char **argv)
229235
double solverDt;
230236
double dt;
231237

232-
if (getParam<bool>("Precice.RunWithCoupling") == true) {
238+
if (runWithCoupling) {
233239
solverDt = getParam<Scalar>("TimeLoop.InitialDt");
234240
dt = std::min(preciceDt, solverDt);
235241
} else {
@@ -261,16 +267,25 @@ int main(int argc, char **argv)
261267
std::cout << "Time Loop starts" << std::endl;
262268
timeLoop->start();
263269
do {
264-
if (getParam<bool>("Precice.RunWithCoupling") == true) {
270+
if (runWithCoupling) {
265271
if (couplingParticipant.isCouplingOngoing() == false)
266272
break;
267273

268274
// write checkpoint
269275
if (couplingParticipant.requiresToWriteCheckpoint()) {
270-
xOld = x;
276+
xCheckpoint = x;
277+
timeCheckpoint = timeLoop->time();
278+
timeStepCheckpoint = timeLoop->timeStepIndex();
271279
}
272280

281+
preciceDt = couplingParticipant.getMaxTimeStepSize();
282+
solverDt = std::min(nonLinearSolver.suggestTimeStepSize(timeLoop->timeStepSize()),
283+
timeLoop->maxTimeStepSize());
284+
dt = std::min(preciceDt, solverDt);
285+
273286
// read porosity and conductivity data from other solver
287+
// TODO: data needs to be updated if Newton solver adapts time-step size
288+
// and coupling data is interpolated in time
274289
couplingParticipant.readQuantityFromOtherSolver(meshName, readDatak00,
275290
dt);
276291
couplingParticipant.readQuantityFromOtherSolver(meshName, readDatak01,
@@ -281,89 +296,79 @@ int main(int argc, char **argv)
281296
dt);
282297
couplingParticipant.readQuantityFromOtherSolver(meshName,
283298
readDataPorosity, dt);
284-
// store coupling data in problem
299+
// store coupling data in spatial params, exchange with MPI
285300
problem->spatialParams().updateCouplingData();
301+
} else {
302+
dt = std::min(
303+
nonLinearSolver.suggestTimeStepSize(timeLoop->timeStepSize()),
304+
timeLoop->maxTimeStepSize());
286305
}
287-
std::cout << "Solver starts" << std::endl;
306+
// set new dt as suggested by the Newton solver or by preCICE
307+
timeLoop->setTimeStepSize(dt);
308+
309+
std::cout << "Solver starts with target dt: " << dt << std::endl;
288310

289311
// linearize & solve
290312
nonLinearSolver.solve(x, *timeLoop);
291313

292-
int solIdx = 0;
293-
for (const auto &element : elements(leafGridView, Dune::Partitions::interior)) {
294-
auto fvGeometry = localView(*gridGeometry);
295-
fvGeometry.bindElement(element);
296-
for (const auto &scv : scvs(fvGeometry)) {
297-
temperatures[solIdx++] =
298-
x[scv.elementIndex()][problem->returnTemperatureIdx()];
299-
}
314+
// save dt value that was actually used by the non-linear solver
315+
dt = timeLoop->timeStepSize();
316+
317+
// DuMux advance + report
318+
gridVariables->advanceTimeStep();
319+
timeLoop->advanceTimeStep();
320+
timeLoop->reportTimeStep();
321+
xOld = x;
322+
323+
// Vtk output
324+
// TODO: output interval does not work seamlessly when subcycling
325+
n += 1;
326+
if (n == vtkOutputInterval) {
327+
problem->updateVtkOutput(x);
328+
vtkWriter.write(timeLoop->time());
329+
n = 0;
300330
}
301331

302-
if (getParam<bool>("Precice.RunWithCoupling") == true) {
332+
if (runWithCoupling) {
333+
int solIdx = 0;
334+
for (const auto &element : elements(leafGridView, Dune::Partitions::interior)) {
335+
auto fvGeometry = localView(*gridGeometry);
336+
fvGeometry.bindElement(element);
337+
for (const auto &scv : scvs(fvGeometry)) {
338+
temperatures[solIdx++] =
339+
x[scv.elementIndex()][problem->returnTemperatureIdx()];
340+
}
341+
}
342+
303343
couplingParticipant.writeQuantityVector(meshName,
304344
writeDataConcentration, temperatures);
305345
couplingParticipant.writeQuantityToOtherSolver(meshName,
306346
writeDataConcentration);
307-
}
308-
309-
// advance precice
310-
if (getParam<bool>("Precice.RunWithCoupling") == true) {
311-
couplingParticipant.advance(timeLoop->timeStepSize());
312-
313-
preciceDt = couplingParticipant.getMaxTimeStepSize();
314-
solverDt = std::min(nonLinearSolver.suggestTimeStepSize(timeLoop->timeStepSize()), timeLoop->maxTimeStepSize());
315-
dt = std::min(preciceDt, solverDt);
316347

348+
// advance preCICE
317349
if ((!fabs(preciceDt - dt)) < 1e-14) {
318-
std::cout << "dt from preCICE is different than dt from DuMuX. "
319-
"preCICE dt = "
320-
<< preciceDt << " and DuMuX dt =" << solverDt << std::endl;
350+
std::cout << "dt from preCICE is different than dt from DuMuX."
351+
<< " preCICE dt = " << preciceDt
352+
<< " and DuMuX dt = " << solverDt
353+
<< " resulted in dt = " << dt
354+
<< std::endl;
321355
}
322-
} else
323-
dt = std::min(
324-
nonLinearSolver.suggestTimeStepSize(timeLoop->timeStepSize()),
325-
getParam<Scalar>("TimeLoop.MaxDt"));
356+
std::flush(std::cout);
357+
couplingParticipant.advance(dt);
326358

327-
std::cout << "Using dt: " << dt << std::endl;
328-
329-
if (getParam<bool>("Precice.RunWithCoupling") == true) {
359+
// reset to checkpoint if not converged
330360
if (couplingParticipant.requiresToReadCheckpoint()) {
331-
// make the new solution the old solution
332-
x = xOld;
361+
x = xCheckpoint;
362+
xOld = x;
363+
timeLoop->setTime(timeCheckpoint, timeStepCheckpoint);
364+
365+
// TODO: previousTimeStep might be more appropriate, last one could be small
366+
timeLoop->setTimeStepSize(dt);
333367
gridVariables->update(x);
334368
gridVariables->advanceTimeStep();
335-
} else // coupling successful
336-
{
337-
n += 1;
338-
if (n == vtkOutputInterval) {
339-
problem->updateVtkOutput(x);
340-
vtkWriter.write(timeLoop->time());
341-
n = 0;
342-
}
343-
gridVariables->advanceTimeStep();
344-
// advance the time loop to the next step
345-
timeLoop->advanceTimeStep();
346-
// report statistics of this time step
347-
timeLoop->reportTimeStep();
348-
}
349-
} else {
350-
xOld = x;
351-
gridVariables->advanceTimeStep();
352-
// advance the time loop to the next step
353-
timeLoop->advanceTimeStep();
354-
// report statistics of this time step
355-
timeLoop->reportTimeStep();
356-
357-
// output every outputinterval steps
358-
n += 1;
359-
if (n == vtkOutputInterval) {
360-
problem->updateVtkOutput(x);
361-
vtkWriter.write(timeLoop->time());
362-
n = 0;
369+
continue;
363370
}
364371
}
365-
// set new dt as suggested by the newton solver or by preCICE
366-
timeLoop->setTimeStepSize(dt);
367372

368373
std::cout << "Time: " << timeLoop->time() << std::endl;
369374

@@ -374,7 +379,7 @@ int main(int argc, char **argv)
374379
////////////////////////////////////////////////////////////
375380
// finalize, print dumux message to say goodbye
376381
////////////////////////////////////////////////////////////
377-
if (getParam<bool>("Precice.RunWithCoupling") == true) {
382+
if (runWithCoupling) {
378383
couplingParticipant.finalize();
379384
}
380385
// print dumux end message

two-scale-heat-conduction/macro-dumux/params.input

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ UpperRight = 1 0.5
1414
Cells = 8 4
1515

1616
[TimeLoop]
17-
TEnd = 0.25
17+
TEnd = 0.025
1818
OutputInterval = 1 # output after every n timesteps
19-
MaxDt = 0.01
19+
MaxDt = 0.004
2020
InitialDt = 0.01
2121

2222
[Problem]

two-scale-heat-conduction/precice-config.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363

6464
<coupling-scheme:serial-implicit>
6565
<participants first="macro-heat" second="Micro-Manager" />
66-
<max-time value="0.02" />
66+
<max-time value="0.025" />
6767
<time-window-size value="1.0e-2" />
6868
<max-iterations value="30" />
6969
<exchange data="k_00" mesh="macro-mesh" from="Micro-Manager" to="macro-heat" />

0 commit comments

Comments
 (0)