Canoe
Comprehensive Atmosphere N' Ocean Engine
implicit_hydro_tasks.cpp
Go to the documentation of this file.
1 // athena
2 #include <athena/athena.hpp>
3 #include <athena/coordinates/coordinates.hpp>
4 #include <athena/field/field.hpp>
5 #include <athena/hydro/hydro.hpp>
6 #include <athena/mesh/mesh.hpp>
7 #include <athena/parameter_input.hpp>
8 #include <athena/scalars/scalars.hpp>
9 
10 // application
11 #include <application/exceptions.hpp>
12 
13 // canoe
14 #include <air_parcel.hpp>
15 #include <impl.hpp>
16 
17 // snap
20 
21 // harp
22 #include <harp/radiation.hpp>
23 
24 // microphysics
26 
27 // tasklist
28 #include "extra_tasks.hpp"
29 
30 using TaskFunction = TaskStatus (TaskList::*)(MeshBlock *, int);
31 
32 int find_task(Task const *task_list, int ntasks, TaskID const &id) {
33  for (int i = 0; i < ntasks; ++i) {
34  if (task_list[i].task_id == id) return i;
35  }
36  throw NotFoundError("find_task", "Task Function");
37 }
38 
39 ImplicitHydroTasks::ImplicitHydroTasks(ParameterInput *pin, Mesh *pm)
40  : TimeIntegratorTaskList(pin, pm) {
41  using namespace HydroIntegratorTaskNames; // NOLINT (build/namespace)
42  int itask;
43 
44  // update IntegrateHydro
45  itask = find_task(task_list_, ntasks, INT_HYD);
46  task_list_[itask].TaskFunc =
48 
49  // update AddSourceTerms
50  itask = find_task(task_list_, ntasks, SRC_TERM);
51  task_list_[itask].TaskFunc =
53 
54  // inject canoe tasks
55  // **ATHENA TASKS**: ... -> (CALC_HYDFLX | CALC_SCLRFLX) ->
56  // **CANOE TASKS** : ADD_FLX_CONS ->
57  // **ATHENA TASKS**: (INT_HYD | INT_SCLR) -> SRC_TERM ->
58  // **CANOE TASKS** : IMPLICIT_CORR -> UPDATE_ALLCONS ->
59  // **ATHENA TASKS**: (SEND_HYD | SEND_SCLR) -> ...
60  if (NSCALARS > 0) {
61  AddTask(ADD_FLX_CONS, (CALC_HYDFLX | CALC_SCLRFLX));
62  } else {
63  AddTask(ADD_FLX_CONS, CALC_HYDFLX);
64  }
65 
66  AddTask(IMPLICIT_CORR, SRC_TERM);
68 
69  // update dependency
70  if (ORBITAL_ADVECTION) {
71  itask = find_task(task_list_, ntasks, SEND_HYDORB);
72  task_list_[itask].dependency = UPDATE_ALLCONS;
73  } else {
74  itask = find_task(task_list_, ntasks, SEND_HYD);
75  task_list_[itask].dependency = UPDATE_ALLCONS;
76 
77  itask = find_task(task_list_, ntasks, SETB_HYD);
78  task_list_[itask].dependency = (RECV_HYD | UPDATE_ALLCONS);
79  }
80 
81  if (pm->multilevel || SHEAR_PERIODIC) { // SMR or AMR or shear periodic
82  itask = find_task(task_list_, ntasks, SEND_HYDFLX);
83  task_list_[itask].dependency = ADD_FLX_CONS;
84 
85  itask = find_task(task_list_, ntasks, RECV_HYDFLX);
86  task_list_[itask].dependency = ADD_FLX_CONS;
87  } else {
88  itask = find_task(task_list_, ntasks, INT_HYD);
89  task_list_[itask].dependency = ADD_FLX_CONS;
90  }
91 
92  if (NSCALARS > 0) {
93  if (!ORBITAL_ADVECTION) {
94  itask = find_task(task_list_, ntasks, SEND_SCLR);
95  task_list_[itask].dependency = UPDATE_ALLCONS;
96 
97  itask = find_task(task_list_, ntasks, SETB_SCLR);
98  task_list_[itask].dependency = (RECV_SCLR | UPDATE_ALLCONS);
99  }
100  }
101 }
102 
103 void ImplicitHydroTasks::AddTask(TaskID const &id, TaskID const &dep) {
104  task_list_[ntasks].task_id = id;
105  task_list_[ntasks].dependency = dep;
106 
107  using namespace HydroIntegratorTaskNames;
108 
109  if (id == ADD_FLX_CONS) {
110  task_list_[ntasks].TaskFunc =
112  task_list_[ntasks].lb_time = true;
113  } else if (id == IMPLICIT_CORR) {
114  task_list_[ntasks].TaskFunc =
116  task_list_[ntasks].lb_time = true;
117  } else if (id == UPDATE_ALLCONS) {
118  task_list_[ntasks].TaskFunc =
120  task_list_[ntasks].lb_time = true;
121  } else {
122  throw NotFoundError("AddTask", "Task ID");
123  }
124 
125  ntasks++;
126 }
127 
128 TaskStatus ImplicitHydroTasks::IntegrateHydro(MeshBlock *pmb, int stage) {
129  auto ph = pmb->phydro;
130  auto pf = pmb->pfield;
131  auto phevi = pmb->pimpl->phevi;
132 
133  if (pmb->pmy_mesh->fluid_setup != FluidFormulation::evolve)
134  return TaskStatus::next;
135 
136  if (stage <= nstages) {
137  if (stage_wghts[stage - 1].main_stage) {
138  // This time-integrator-specific averaging operation logic is identical to
139  // FieldInt
140  Real ave_wghts[5];
141  ave_wghts[0] = 1.0;
142  ave_wghts[1] = stage_wghts[stage - 1].delta;
143  ave_wghts[2] = 0.0;
144  ave_wghts[3] = 0.0;
145  ave_wghts[4] = 0.0;
146  pmb->WeightedAve(ph->u1, ph->u, ph->u2, ph->u0, ph->fl_div, ave_wghts);
147 
148  ave_wghts[0] = stage_wghts[stage - 1].gamma_1;
149  ave_wghts[1] = stage_wghts[stage - 1].gamma_2;
150  ave_wghts[2] = stage_wghts[stage - 1].gamma_3;
151  if (ave_wghts[0] == 0.0 && ave_wghts[1] == 1.0 && ave_wghts[2] == 0.0)
152  ph->u.SwapAthenaArray(ph->u1);
153  else
154  pmb->WeightedAve(ph->u, ph->u1, ph->u2, ph->u0, ph->fl_div, ave_wghts);
155 
156  const Real wght = stage_wghts[stage - 1].beta * pmb->pmy_mesh->dt;
157  pmb->pimpl->du.ZeroClear();
158  ph->AddFluxDivergence(wght, pmb->pimpl->du);
159  // add coordinate (geometric) source terms
160  pmb->pcoord->AddCoordTermsDivergence(wght, ph->flux, ph->w, pf->bcc,
161  pmb->pimpl->du);
162 
163  // Hardcode an additional flux divergence weighted average for the
164  // penultimate stage of SSPRK(5,4) since it cannot be expressed in a 3S*
165  // framework
166  if (stage == 4 && integrator == "ssprk5_4") {
167  // From Gottlieb (2009), u^(n+1) partial calculation
168  ave_wghts[0] = -1.0; // -u^(n) coeff.
169  ave_wghts[1] = 0.0;
170  ave_wghts[2] = 0.0;
171  const Real beta = 0.063692468666290; // F(u^(3)) coeff.
172  const Real wght_ssp = beta * pmb->pmy_mesh->dt;
173  // writing out to u2 register
174  pmb->WeightedAve(ph->u2, ph->u1, ph->u2, ph->u0, ph->fl_div, ave_wghts);
175  ph->AddFluxDivergence(wght_ssp, ph->u2);
176  // add coordinate (geometric) source terms
177  pmb->pcoord->AddCoordTermsDivergence(wght_ssp, ph->flux, ph->w, pf->bcc,
178  ph->u2);
179  }
180  }
181  return TaskStatus::next;
182  }
183  return TaskStatus::fail;
184 }
185 
186 TaskStatus ImplicitHydroTasks::AddSourceTerms(MeshBlock *pmb, int stage) {
187  Hydro *ph = pmb->phydro;
188  Field *pf = pmb->pfield;
189  PassiveScalars *ps = pmb->pscalars;
190 
191  // return if there are no source terms to be added
192  if (!(ph->hsrc.hydro_sourceterms_defined) ||
193  pmb->pmy_mesh->fluid_setup != FluidFormulation::evolve)
194  return TaskStatus::next;
195 
196  if (stage <= nstages) {
197  if (stage_wghts[stage - 1].main_stage) {
198  // Time at beginning of stage for u()
199  Real t_start_stage = pmb->pmy_mesh->time +
200  stage_wghts[(stage - 1)].sbeta * pmb->pmy_mesh->dt;
201  // Scaled coefficient for RHS update
202  Real dt = (stage_wghts[(stage - 1)].beta) * (pmb->pmy_mesh->dt);
203  // Evaluate the source terms at the time at the beginning of the stage
204  ph->hsrc.AddSourceTerms(t_start_stage, dt, ph->flux, ph->w, ps->r,
205  pf->bcc, pmb->pimpl->du, ps->s);
206  // pmb->pphy->ApplyPhysicsPackages(phevi->du, ph->w, pmb->pmy_mesh->time,
207  // pmb->pmy_mesh->dt);
208  }
209  return TaskStatus::next;
210  }
211  return TaskStatus::fail;
212 }
213 
214 TaskStatus ImplicitHydroTasks::AddFluxToConserved(MeshBlock *pmb, int stage) {
215  int is = pmb->is, js = pmb->js, ks = pmb->ks;
216  int ie = pmb->ie, je = pmb->je, ke = pmb->ke;
217 
218  auto prad = pmb->pimpl->prad;
219 
220  if (stage <= nstages) {
221  if (stage_wghts[stage - 1].main_stage) {
222  for (int k = ks; k <= ke; ++k)
223  for (int j = js; j <= je; ++j) {
224  prad->AddRadiativeFlux(pmb->phydro, k, j, is, ie + 1);
225  }
226 
227  if (stage == nstages) { // last stage
228  if (prad->GetCounter() > 0.) { // reuse previous flux
229  prad->DecrementCounter(pmb->pmy_mesh->dt);
230  } else { // update radiative flux
231  prad->ResetCounter();
232  for (int k = ks; k <= ke; ++k)
233  for (int j = js; j <= je; ++j)
234  prad->CalRadiativeFlux(pmb, k, j, is, ie + 1);
235  }
236  }
237  }
238  return TaskStatus::next;
239  }
240  return TaskStatus::fail;
241 }
242 
243 TaskStatus ImplicitHydroTasks::ImplicitCorrection(MeshBlock *pmb, int stage) {
244  Hydro *ph = pmb->phydro;
245  auto phevi = pmb->pimpl->phevi;
246  Real dt = pmb->pmy_mesh->dt;
247 
248  if (stage <= nstages) {
249  if (stage_wghts[stage - 1].main_stage) {
250  // do implicit coorection at every stage
251  // X3DIR
252  if ((phevi->implicit_flag & (1 << 2)) && (pmb->ncells3 > 1)) {
253  phevi->SetDirection(X3DIR);
254  if (phevi->implicit_flag & (1 << 3))
255  phevi->FullCorrection(pmb->pimpl->du, ph->w,
256  stage_wghts[stage - 1].beta * dt);
257  else
258  phevi->PartialCorrection(pmb->pimpl->du, ph->w,
259  stage_wghts[stage - 1].beta * dt);
260  }
261 
262  // X2DIR
263  if ((phevi->implicit_flag & (1 << 1)) && (pmb->ncells2 > 1)) {
264  phevi->SetDirection(X2DIR);
265  if (phevi->implicit_flag & (1 << 3))
266  phevi->FullCorrection(pmb->pimpl->du, ph->w,
267  stage_wghts[stage - 1].beta * dt);
268  else
269  phevi->PartialCorrection(pmb->pimpl->du, ph->w,
270  stage_wghts[stage - 1].beta * dt);
271  }
272 
273  // X1DIR
274  if (phevi->implicit_flag & 1) {
275  phevi->SetDirection(X1DIR);
276  if (phevi->implicit_flag & (1 << 3))
277  phevi->FullCorrection(pmb->pimpl->du, ph->w,
278  stage_wghts[stage - 1].beta * dt);
279  else
280  phevi->PartialCorrection(pmb->pimpl->du, ph->w,
281  stage_wghts[stage - 1].beta * dt);
282  }
283 
284  Real wghts[5];
285  wghts[0] = 1.;
286  wghts[1] = 1.;
287  wghts[2] = 0.;
288  wghts[3] = 0.;
289  wghts[4] = 0.;
290  pmb->WeightedAve(ph->u, pmb->pimpl->du, ph->u2, ph->u2, ph->u2, wghts);
291  }
292  return TaskStatus::next;
293  }
294  return TaskStatus::fail;
295 }
296 
297 TaskStatus ImplicitHydroTasks::UpdateAllConserved(MeshBlock *pmb, int stage) {
298  if (stage <= nstages) {
299  pmb->pimpl->pmicro->SetVsedFromConserved(pmb->phydro);
300  } else {
301  return TaskStatus::fail;
302  }
303 
304  // only do chemistry and thermodynamcis at last rk step
305  if (stage != nstages) return TaskStatus::next;
306 
307  int is = pmb->is, js = pmb->js, ks = pmb->ks;
308  int ie = pmb->ie, je = pmb->je, ke = pmb->ke;
309 
310  auto pthermo = Thermodynamics::GetInstance();
311 
312  auto pmicro = pmb->pimpl->pmicro;
313 
314  for (int k = ks; k <= ke; k++)
315  for (int j = js; j <= je; j++) {
316  auto &&ac = AirParcelHelper::gather_from_conserved(pmb, k, j, is, ie);
317 
318  // pmicro->AddFrictionalHeating(air_column);
319 
320  pmicro->EvolveSystems(ac, pmb->pmy_mesh->time, pmb->pmy_mesh->dt);
321 
322  pthermo->SaturationAdjustment(ac);
323 
324  AirParcelHelper::distribute_to_conserved(pmb, k, j, is, ie, ac);
325  }
326 
327  return TaskStatus::success;
328 }
TaskStatus AddFluxToConserved(MeshBlock *pmb, int stage)
TaskStatus IntegrateHydro(MeshBlock *pmb, int stage)
TaskStatus ImplicitCorrection(MeshBlock *pmb, int stage)
ImplicitHydroTasks(ParameterInput *pin, Mesh *pm)
TaskStatus UpdateAllConserved(MeshBlock *pmb, int stage)
TaskStatus AddSourceTerms(MeshBlock *pmb, int stage)
void AddTask(TaskID const &id, TaskID const &dep) override
static Thermodynamics const * GetInstance()
Return a pointer to the one and only instance of Thermodynamics.
int find_task(Task const *task_list, int ntasks, TaskID const &id)
TaskStatus(TaskList::*)(MeshBlock *, int) TaskFunction
void distribute_to_conserved(MeshBlock *pmb, int k, int j, int i, AirParcel const &air_in)
Definition: air_parcel.cpp:662
AirParcel gather_from_conserved(MeshBlock const *pmb, int k, int j, int i)
Definition: air_parcel.cpp:555
This should track the largest task ID in the athena/task_list/task_list.hpp.
Definition: extra_tasks.hpp:62
const TaskID IMPLICIT_CORR(80)
const TaskID UPDATE_ALLCONS(82)
const TaskID ADD_FLX_CONS(81)