/
TransientMultiApp.C
171 lines (132 loc) · 4.56 KB
/
TransientMultiApp.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/****************************************************************/
/* DO NOT MODIFY THIS HEADER */
/* MOOSE - Multiphysics Object Oriented Simulation Environment */
/* */
/* (c) 2010 Battelle Energy Alliance, LLC */
/* ALL RIGHTS RESERVED */
/* */
/* Prepared by Battelle Energy Alliance, LLC */
/* Under Contract No. DE-AC07-05ID14517 */
/* With the U. S. Department of Energy */
/* */
/* See COPYRIGHT for full restrictions */
/****************************************************************/
#include "TransientMultiApp.h"
#include "LayeredSideFluxAverage.h"
// libMesh
#include "libmesh/mesh_tools.h"
template<>
InputParameters validParams<TransientMultiApp>()
{
InputParameters params = validParams<MultiApp>();
params += validParams<TransientInterface>();
params.addParam<bool>("sub_cycling", false, "Set to true to allow this MultiApp to take smaller timesteps than the rest of the simulation. More than one timestep will be performed for each 'master' timestep");
return params;
}
TransientMultiApp::TransientMultiApp(const std::string & name, InputParameters parameters):
MultiApp(name, parameters),
TransientInterface(parameters, name, "multiapps"),
_sub_cycling(getParam<bool>("sub_cycling"))
{
if(!_has_an_app)
return;
MPI_Comm swapped = Moose::swapLibMeshComm(_my_comm);
if(_has_an_app)
{
_transient_executioners.resize(_my_num_apps);
// Grab Transient Executioners from each app
for(unsigned int i=0; i<_my_num_apps; i++)
{
MooseApp * app = _apps[i];
Transient * ex = dynamic_cast<Transient *>(app->getExecutioner());
if(!ex)
mooseError("MultiApp " << name << " is not using a Transient Executioner!");
appProblem(_first_local_app + i)->initialSetup();
ex->preExecute();
appProblem(_first_local_app + i)->copyOldSolutions();
_transient_executioners[i] = ex;
}
}
// Swap back
Moose::swapLibMeshComm(swapped);
}
TransientMultiApp::~TransientMultiApp()
{
if(!_has_an_app)
return;
MPI_Comm swapped = Moose::swapLibMeshComm(_my_comm);
for(unsigned int i=0; i<_my_num_apps; i++)
{
Transient * ex = _transient_executioners[i];
ex->postExecute();
}
// Swap back
Moose::swapLibMeshComm(swapped);
}
void
TransientMultiApp::solveStep()
{
if(!_has_an_app)
return;
std::cout<<"Solving MultiApp "<<_name<<std::endl;
MPI_Comm swapped = Moose::swapLibMeshComm(_my_comm);
int rank;
MPI_Comm_rank(_orig_comm, &rank);
for(unsigned int i=0; i<_my_num_apps; i++)
{
Transient * ex = _transient_executioners[i];
if(_sub_cycling)
{
// Get the dt this app wants to take
Real dt = ex->computeConstrainedDT();
// Divide the "master" dt by that
Real partial_steps = _dt / dt;
unsigned int num_steps = 0;
if(partial_steps-std::floor(partial_steps) <= 2.0e-14)
num_steps = std::floor(partial_steps);
else
num_steps = std::ceil(partial_steps);
// Split the master dt up into the number of steps (so we can hit the time perfectly)
dt = _dt / (Real)num_steps;
// Now do all of the solves we need
for(unsigned int i=0; i<num_steps; i++)
{
ex->takeStep(dt);
if(!ex->lastSolveConverged())
mooseWarning("While sub_cycling "<<_name<<_first_local_app+i<<" failed to converge!"<<std::endl);
ex->endStep();
}
}
else
{
ex->takeStep(_dt);
if(!ex->lastSolveConverged())
mooseWarning(_name<<_first_local_app+i<<" failed to converge!"<<std::endl);
ex->endStep();
}
}
// Swap back
Moose::swapLibMeshComm(swapped);
std::cout<<"Finished Solving MultiApp "<<_name<<std::endl;
}
Real
TransientMultiApp::computeDT()
{
if(_sub_cycling) // Bow out of the timestep selection dance
return std::numeric_limits<Real>::max();
Real smallest_dt = std::numeric_limits<Real>::max();
if(_has_an_app)
{
MPI_Comm swapped = Moose::swapLibMeshComm(_my_comm);
for(unsigned int i=0; i<_my_num_apps; i++)
{
Transient * ex = _transient_executioners[i];
Real dt = ex->computeConstrainedDT();
smallest_dt = std::min(dt, smallest_dt);
}
// Swap back
Moose::swapLibMeshComm(swapped);
}
Parallel::min(smallest_dt);
return smallest_dt;
}