1 // Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and
2 // other Axom Project Developers. See the top-level LICENSE file for details.
3 //
4 // SPDX-License-Identifier: (BSD-3-Clause)
5
6 /**
7 * \file
8 *
9 * \brief 1D shock tube, split flux Euler equations
10 *
11 * \author J. Keasler (original)
12 * \author K. Weiss (modified to use axom's Slam component)
13 *
14 * \details Developing example to use and demo features of Slam on shock tube
15 * example over structured 1D mesh.
16 *
17 * Tests:
18 * * Sets and subsets.
19 * * Relations over regular grid (should be implicit; currently
20 * implemented as explicit static constant relations)
21 * * Fields/maps over the data -- and access to a local datastore
22 * (using Slam::FieldRegistry, can easily convert to Sidre).
23 *
24 * \verbatim
25 * | m | | mv |
26 * Q = | mv | F = | mv^2 + P |
27 * | E | | v(E+P) |
28 *
29 * P = (gamma - 1.0)[E - 0.5 mv^2 ]
30 *
31 * Cp
32 * gamma = -- m = mass/volume v = velocity
33 * Cv
34 *
35 * All quantities are non-dimensionalized.
36 *
37 * @Q @F @Q @F @Q
38 * -- + -- = -- + -- -- = 0
39 * @t @x @t @Q @x
40 * \endverbatim
41 */
42
43 #include "axom/config.hpp"
44 #include "axom/slic.hpp"
45 #include "axom/slam.hpp"
46
47 #include <cmath>
48 #include <string>
49 #include <iomanip>
50 #include <sstream>
51
52 namespace slamShocktube
53 {
54 namespace slam = axom::slam;
55
56 using PositionType = slam::DefaultPositionType;
57 using ElementType = slam::DefaultElementType;
58
59 using BaseSet = slam::Set<PositionType, ElementType>;
60
61 PositionType const UPWIND = 0;
62 PositionType const DOWNWIND = 1;
63
64 const double gammaa = M_SQRT2;
65 const double gammaaInverse = M_SQRT1_2;
66
67 const int INIT_NUM_ELEMS = 100;
68 const int INIT_NUM_OUTPUT_DUMPS = 5;
69 const int INIT_NUM_CYCLES_PER_DUMP = 200;
70
71 const double INIT_P_RATIO = 0.5;
72 const double INIT_D_RATIO = 0.5;
73
74 #ifdef AXOM_DEBUG
75 const bool verboseOutput = false;
76 #endif
77
78 /**
79 * \brief Simple representation of the mesh for this 1D example
80 *
81 * \details Mesh contains a set of elements and a set of faces between elements.
82 * It also contains three subsets: a single inflow; a single outflow
83 * element; all internal 'tube' elements. (added 5/2015)
84 * The mesh contains the relations from faces to elements and from tube
85 * elements to faces.
86 *
87 * \note (5/2015) We are currently missing an implicit constant grid relation.
88 *
89 * \note For current implementation with explicit static (constant) relations.
90 * \note We are missing a nice way to set the relation elements.
91 * It should not have to be done explicitly in each user code --especially
92 in common use cases
93 *
94 * Idea: We could have a relationInverter function that takes a relation
95 * from sets A to B and generates a relation from set B to set A with all
96 the arrows reversed.
97 */
98 class ShockTubeMesh
99 {
100 public:
101 /// types for Element and Face sets
102 using PositionType = slamShocktube::PositionType;
103
104 using ElemSet = slam::PositionSet<PositionType, ElementType>;
105 using FaceSet = slam::PositionSet<PositionType, ElementType>;
106
107 using IndexType = PositionType;
108
109 /// types for Tube and {In,Out}Flow subsets
110 using StrideOnePolicy = slam::policies::StrideOne<PositionType>;
111 using NoIndirectionPolicy =
112 slam::policies::NoIndirection<PositionType, ElementType>;
113 using TubeSubsetPolicy = slam::policies::ConcreteParentSubset<ElemSet>;
114 using ElemSubset = slam::GenericRangeSet<PositionType,
115 ElementType,
116 StrideOnePolicy,
117 NoIndirectionPolicy,
118 TubeSubsetPolicy>;
119 using RangeSet = slam::RangeSet<PositionType, ElementType>;
120
121 /// types for relations
122 enum
123 {
124 ELEMS_PER_FACE = 2,
125 FACES_PER_ELEM = 2
126 };
127
128 using EFStride =
129 slam::policies::CompileTimeStride<PositionType, FACES_PER_ELEM>;
130 using FEStride =
131 slam::policies::CompileTimeStride<PositionType, ELEMS_PER_FACE>;
132
133 using EFCard = slam::policies::ConstantCardinality<PositionType, EFStride>;
134 using FECard = slam::policies::ConstantCardinality<PositionType, FEStride>;
135 using STLIndirection =
136 slam::policies::STLVectorIndirection<PositionType, ElementType>;
137 using IndexVec = STLIndirection::VectorType;
138
139 using TubeElemToFaceRelation =
140 slam::StaticRelation<PositionType, ElementType, EFCard, STLIndirection, ElemSubset, FaceSet>;
141 using FaceToElemRelation =
142 slam::StaticRelation<PositionType, ElementType, FECard, STLIndirection, FaceSet, ElemSet>;
143
144 public:
145 ElemSet elems; // The entire set of elements
146 ElemSubset tubeElems; // Subset of internal elements
147 ElemSubset inFlowElems; // Subset of inflow elements
148 ElemSubset outFlowElems; // Subset of outflow elements
149 FaceSet faces; // Faces between adjacent pairs of elements
150
151 FaceToElemRelation relationFaceElem; // co-boundary relation of faces
152 // to their elements
153 TubeElemToFaceRelation relationTubeFace; // boundary relation of
154 // internal 'tube' elements
155 };
156
157 // Define explicit instances of local (key/value) datastore for int and double
158 using IntsRegistry = slam::FieldRegistry<BaseSet, BaseSet::ElementType>;
159 using RealsRegistry = slam::FieldRegistry<BaseSet, double>;
160 using IntField = IntsRegistry::MapType;
161 using RealField = RealsRegistry::MapType;
162
163 IntsRegistry intsRegistry;
164 RealsRegistry realsRegistry;
165
166 /**************************************************************************
167 * Subroutine: GetUserInput
168 * Purpose : Ask for control and output information
169 *************************************************************************/
170
GetUserInput()171 void GetUserInput()
172 {
173 /**********************************/
174 /* Get mesh info, and create mesh */
175 /**********************************/
176 {
177 int numElems;
178 int numFaces;
179
180 SLIC_INFO("How many zones for the 1D shock tube? ");
181 numElems = INIT_NUM_ELEMS;
182 SLIC_INFO("\t\t" << numElems);
183
184 // add an inflow and outflow zone
185 numElems += 2;
186 numFaces = numElems - 1;
187
188 intsRegistry.addScalar("numElems", numElems);
189 intsRegistry.addScalar("numFaces", numFaces);
190 }
191
192 /********************/
193 /* Get physics info */
194 /********************/
195 {
196 double pratio = -1.0;
197 double dratio = -1.0;
198
199 while(pratio < 0.0 || pratio > 1.0)
200 {
201 SLIC_INFO("What pressure ratio would you like (0 <= x <= 1)? ");
202 pratio = INIT_P_RATIO;
203 SLIC_INFO("\t\t" << pratio);
204 }
205
206 while(dratio < 0.0 || dratio > 1.0)
207 {
208 SLIC_INFO("What density ratio would you like (0 <= x <= 1)? ");
209 dratio = INIT_D_RATIO;
210 SLIC_INFO("\t\t" << dratio);
211 }
212
213 realsRegistry.addScalar("pressureRatio", pratio);
214 realsRegistry.addScalar("densityRatio", dratio);
215 }
216
217 /********************/
218 /* Get output info */
219 /********************/
220 {
221 int numOutputDumps;
222 int numCyclesPerDump;
223
224 SLIC_INFO("How many dumps would you like? ");
225 numOutputDumps = INIT_NUM_OUTPUT_DUMPS;
226 SLIC_INFO("\t\t" << numOutputDumps);
227
228 SLIC_INFO("How many cycles between dumps would you like? ");
229 numCyclesPerDump = INIT_NUM_CYCLES_PER_DUMP;
230 SLIC_INFO("\t\t" << numCyclesPerDump);
231
232 int numTotalCycles = numOutputDumps * numCyclesPerDump;
233 SLIC_INFO("Simulation will run for " << numTotalCycles << " cycles.\n");
234
235 intsRegistry.addScalar("numOutputDumps", numOutputDumps);
236 intsRegistry.addScalar("numCyclesPerDump", numCyclesPerDump);
237 intsRegistry.addScalar("numTotalCycles", numTotalCycles);
238 }
239
240 return;
241 }
242
243 /**
244 * \brief Build an empty mesh for the shock tube
245 * \details Shocktube mesh layout
246 * \verbatim
247 * Gaps between elements are faces
248 * |
249 * -------------------------------
250 * | | | | | |
251 *
252 * ### ### ### ### ### ### ### ###
253 * ### ### ### ### ... ### ### ### ### <--- 1D Shock tube model
254 * ### ### ### ### ### ### ### ###
255 *
256 * | | | |
257 * | ----------------------------- |
258 * Inflow | Outflow
259 * Element Tube Elements Element
260 *
261 * \endverbatim
262 */
CreateShockTubeMesh(ShockTubeMesh * mesh)263 void CreateShockTubeMesh(ShockTubeMesh* mesh)
264 {
265 // ------------ Generate the Sets and Subsets
266
267 // create element and face sets
268 mesh->elems = ShockTubeMesh::ElemSet(intsRegistry.getScalar("numElems"));
269 mesh->faces = ShockTubeMesh::FaceSet(intsRegistry.getScalar("numFaces"));
270
271 // construct the element subsets
272 ShockTubeMesh::PositionType numElems = mesh->elems.size();
273 using ElemSubsetBuilder = ShockTubeMesh::ElemSubset::SetBuilder;
274 mesh->inFlowElems = ElemSubsetBuilder() //
275 .range(0, 1) //
276 .parent(&mesh->elems);
277 mesh->tubeElems = ElemSubsetBuilder() //
278 .range(1, numElems - 1) //
279 .parent(&mesh->elems);
280 mesh->outFlowElems = ElemSubsetBuilder() //
281 .range(numElems - 1, numElems) //
282 .parent(&mesh->elems);
283
284 // ------------ Generate the Relations
285
286 // TODO: Need to define DynamicConstantRelation
287 // which will allow modifying the relation elements
288 // TODO: Need to define ImplicitConstantRelation
289 // since the relations are actually implicit
290 // no storage should be necessary for regular grid neighbors
291 // For now, we use explicitly storage for the relation data.
292
293 using IndexVec = ShockTubeMesh::IndexVec;
294
295 /// Setup the FaceToElem relation
296 IndexVec& feRelVec =
297 intsRegistry.addBuffer("feRel",
298 ShockTubeMesh::FACES_PER_ELEM * mesh->faces.size());
299 IndexVec::iterator relIt = feRelVec.begin();
300 for(ShockTubeMesh::IndexType idx = 0;
301 idx < static_cast<ShockTubeMesh::IndexType>(mesh->faces.size());
302 ++idx)
303 {
304 *relIt++ = mesh->faces[idx];
305 *relIt++ = mesh->faces[idx] + 1;
306 }
307
308 mesh->relationFaceElem =
309 ShockTubeMesh::FaceToElemRelation(&mesh->faces, &mesh->elems);
310 mesh->relationFaceElem.bindIndices(static_cast<int>(feRelVec.size()),
311 &feRelVec);
312 SLIC_ASSERT(mesh->relationFaceElem.isValid(verboseOutput));
313
314 /// Setup the TubeElementToFace relation:
315 /// A relation from the tubes subset of the elements to their incident faces
316 ShockTubeMesh::PositionType numTubeElems = mesh->tubeElems.size();
317 IndexVec& efRelVec =
318 intsRegistry.addBuffer("efRel", ShockTubeMesh::ELEMS_PER_FACE * numTubeElems);
319 relIt = efRelVec.begin();
320 for(ShockTubeMesh::IndexType idx = 0;
321 idx < static_cast<ShockTubeMesh::IndexType>(numTubeElems);
322 ++idx)
323 {
324 *relIt++ = mesh->tubeElems[idx] - 1;
325 *relIt++ = mesh->tubeElems[idx];
326 }
327
328 mesh->relationTubeFace =
329 ShockTubeMesh::TubeElemToFaceRelation(&mesh->tubeElems, &mesh->faces);
330 mesh->relationTubeFace.bindIndices(static_cast<int>(efRelVec.size()),
331 &efRelVec);
332 SLIC_ASSERT(mesh->relationTubeFace.isValid(verboseOutput));
333 }
334
335 /**************************************************************************
336 * Subroutine: InitializeShockTube
337 * Purpose : Populate the mesh with values
338 *************************************************************************/
InitializeShockTube(ShockTubeMesh const & mesh)339 void InitializeShockTube(ShockTubeMesh const& mesh)
340 {
341 using IndexType = ShockTubeMesh::IndexType;
342 using RangeSet = ShockTubeMesh::RangeSet;
343
344 // Create element centered fields
345 RealField& mass = realsRegistry.addField("mass", &mesh.elems);
346 RealField& momentum = realsRegistry.addField("momentum", &mesh.elems);
347 RealField& energy = realsRegistry.addField("energy", &mesh.elems);
348 RealField& pressure = realsRegistry.addField("pressure", &mesh.elems);
349
350 // Create face centered fields
351 realsRegistry.addField("F0", &mesh.faces); // mv
352 realsRegistry.addField("F1", &mesh.faces); // mv^2+P
353 realsRegistry.addField("F2", &mesh.faces); // v(E+P)
354
355 // Fill left half with high pressure, right half with low pressure
356 IndexType endTube = mesh.elems.size();
357 IndexType midTube = endTube / 2;
358
359 // Non-dimensionalized reference values
360 double massInitial = 1.0;
361 double momentumInitial = 0.0;
362 double pressureInitial = gammaaInverse;
363 double energyInitial = pressureInitial / (gammaa - 1.0);
364
365 // Initialize zonal quantities
366 RangeSet lowerTube(0, midTube);
367 for(IndexType i = 0; i < lowerTube.size(); ++i)
368 {
369 IndexType ind = lowerTube[i];
370 mass[ind] = massInitial;
371 momentum[ind] = momentumInitial;
372 pressure[ind] = pressureInitial;
373 energy[ind] = energyInitial;
374 }
375
376 // adjust parameters for low pressure portion of tube
377 massInitial *= realsRegistry.getScalar("densityRatio");
378 pressureInitial *= realsRegistry.getScalar("pressureRatio");
379 energyInitial = pressureInitial / (gammaa - 1.0);
380
381 RangeSet upperTube(midTube, mesh.elems.size());
382 for(IndexType i = 0; i < upperTube.size(); ++i)
383 {
384 IndexType ind = upperTube[i];
385 mass[ind] = massInitial;
386 momentum[ind] = momentumInitial;
387 pressure[ind] = pressureInitial;
388 energy[ind] = energyInitial;
389 }
390
391 // Create needed time info
392 realsRegistry.addScalar("time", 0.0);
393 intsRegistry.addScalar("cycle", 0);
394
395 double dx = 1.0 / static_cast<double>(endTube);
396 realsRegistry.addScalar("dx", dx);
397 realsRegistry.addScalar("dt", 0.4 * dx);
398 }
399
400 /**
401 * \brief Compute F quantities at faces.
402 *
403 * \details
404 *
405 * \verbatim
406 * @F @F0 @F1 @F2
407 * -- = --- + --- + ---
408 * @x @x @x @x
409 * \endverbatim
410 *
411 * Calculate F0, F1 and F2 at the face centers.
412 *
413 */
ComputeFaceInfo(ShockTubeMesh const & mesh)414 void ComputeFaceInfo(ShockTubeMesh const& mesh)
415 {
416 using IndexType = ShockTubeMesh::IndexType;
417
418 // Face fields
419 RealField& F0 = realsRegistry.getField("F0");
420 RealField& F1 = realsRegistry.getField("F1");
421 RealField& F2 = realsRegistry.getField("F2");
422
423 // Element fields
424 const RealField& mass = realsRegistry.getField("mass");
425 const RealField& momentum = realsRegistry.getField("momentum");
426 const RealField& energy = realsRegistry.getField("energy");
427
428 // Update face data using element data using the face->elem relation
429 ShockTubeMesh::PositionType numFaceElems =
430 static_cast<ShockTubeMesh::PositionType>(mesh.faces.size());
431 for(ShockTubeMesh::PositionType fIdx = 0; fIdx < numFaceElems; ++fIdx)
432 {
433 // each face has an upwind and downwind element.
434 IndexType upWind = mesh.relationFaceElem[fIdx][UPWIND]; // upwind
435 // element
436 IndexType downWind = mesh.relationFaceElem[fIdx][DOWNWIND]; // downwind
437 // element
438
439 // calculate face centered quantities as avg of element centered ones
440 double massf = 0.5 * (mass[upWind] + mass[downWind]);
441 double momentumf = 0.5 * (momentum[upWind] + momentum[downWind]);
442 double energyf = 0.5 * (energy[upWind] + energy[downWind]);
443 double pressuref =
444 (gammaa - 1.0) * (energyf - 0.5 * momentumf * momentumf / massf);
445 double c = sqrt(gammaa * pressuref / massf);
446 double v = momentumf / massf;
447
448 double ev;
449 double cLocal;
450
451 // Now that we have the wave speeds, we might want to
452 // look for the max wave speed here, and update dt
453 // appropriately right before leaving this function.
454
455 // OK, calculate face quantities
456 F0[fIdx] = F1[fIdx] = F2[fIdx] = 0.0;
457
458 IndexType contributor = ((v >= 0.0) ? upWind : downWind);
459 massf = mass[contributor];
460 momentumf = momentum[contributor];
461 energyf = energy[contributor];
462 pressuref = energyf - 0.5 * momentumf * momentumf / massf;
463 ev = v * (gammaa - 1.0);
464
465 F0[fIdx] += ev * massf;
466 F1[fIdx] += ev * momentumf;
467 F2[fIdx] += ev * (energyf - pressuref);
468
469 contributor = ((v + c >= 0.0) ? upWind : downWind);
470 massf = mass[contributor];
471 momentumf = momentum[contributor];
472 energyf = energy[contributor];
473 pressuref = (gammaa - 1.0) * (energyf - 0.5 * momentumf * momentumf / massf);
474 ev = 0.5 * (v + c);
475 cLocal = sqrt(gammaa * pressuref / massf);
476
477 F0[fIdx] += ev * massf;
478 F1[fIdx] += ev * (momentumf + massf * cLocal);
479 F2[fIdx] += ev * (energyf + pressuref + momentumf * cLocal);
480
481 contributor = ((v - c >= 0.0) ? upWind : downWind);
482 massf = mass[contributor];
483 momentumf = momentum[contributor];
484 energyf = energy[contributor];
485 pressuref = (gammaa - 1.0) * (energyf - 0.5 * momentumf * momentumf / massf);
486 ev = 0.5 * (v - c);
487 cLocal = sqrt(gammaa * pressuref / massf);
488
489 F0[fIdx] += ev * massf;
490 F1[fIdx] += ev * (momentumf - massf * cLocal);
491 F2[fIdx] += ev * (energyf + pressuref - momentumf * cLocal);
492 }
493 }
494
495 /**************************************************************************
496 * Subroutine: UpdateElemInfo
497 * Purpose : Q(elem) = Q(elem) + deltaQ(elem)
498 *
499 * deltaQ(elem) = - (F(downWindFace) - F(upWindFace)) * dt / dx ;
500 *
501 *************************************************************************/
502
UpdateElemInfo(ShockTubeMesh const & mesh)503 void UpdateElemInfo(ShockTubeMesh const& mesh)
504 {
505 // get the element quantities we want to update
506 RealField& mass = realsRegistry.getField("mass");
507 RealField& momentum = realsRegistry.getField("momentum");
508 RealField& energy = realsRegistry.getField("energy");
509 RealField& pressure = realsRegistry.getField("pressure");
510
511 // The element update is calculated as the flux between faces
512 const RealField& F0 = realsRegistry.getField("F0");
513 const RealField& F1 = realsRegistry.getField("F1");
514 const RealField& F2 = realsRegistry.getField("F2");
515
516 double dx = realsRegistry.getScalar("dx");
517 double dt = realsRegistry.getScalar("dt");
518 double& time = realsRegistry.getScalar("time");
519
520 /// Update the element fields based on the face data using the elem->face
521 // relation
522 ShockTubeMesh::PositionType numTubeElems =
523 static_cast<ShockTubeMesh::PositionType>(mesh.tubeElems.size());
524
525 for(ShockTubeMesh::PositionType tPos = 0; tPos < numTubeElems; ++tPos)
526 {
527 // Relation is over tube elements.
528 ShockTubeMesh::IndexType elemIdx = mesh.tubeElems[tPos];
529
530 // Each element inside the tube has an upwind and downwind face
531 ShockTubeMesh::IndexType upWind =
532 mesh.relationTubeFace[tPos][UPWIND]; // upwind
533 // face
534 ShockTubeMesh::IndexType downWind =
535 mesh.relationTubeFace[tPos][DOWNWIND]; // downwind
536 // face
537
538 mass[elemIdx] -= gammaaInverse * (F0[downWind] - F0[upWind]) * dt / dx;
539 momentum[elemIdx] -= gammaaInverse * (F1[downWind] - F1[upWind]) * dt / dx;
540 energy[elemIdx] -= gammaaInverse * (F2[downWind] - F2[upWind]) * dt / dx;
541 pressure[elemIdx] = (gammaa - 1.0) *
542 (energy[elemIdx] -
543 0.5 * momentum[elemIdx] * momentum[elemIdx] / mass[elemIdx]);
544 }
545
546 // update the time
547 time += dt;
548 }
549
dumpData(ShockTubeMesh const & mesh)550 void dumpData(ShockTubeMesh const& mesh)
551 {
552 RealField const& mass = realsRegistry.getField("mass");
553 RealField const& momentum = realsRegistry.getField("momentum");
554 RealField const& energy = realsRegistry.getField("energy");
555 RealField const& pressure = realsRegistry.getField("pressure");
556
557 static const ShockTubeMesh::PositionType MAX_ELEM_DUMP = 20;
558 const int maxDumpPerSide = std::min(mesh.elems.size(), MAX_ELEM_DUMP) / 2;
559
560 using ElemSubsetBuilder = ShockTubeMesh::ElemSubset::SetBuilder;
561 ShockTubeMesh::ElemSubset begSet, endSet;
562 begSet = ElemSubsetBuilder() //
563 .parent(&mesh.elems) //
564 .size(maxDumpPerSide);
565 endSet = ElemSubsetBuilder()
566 .parent(&mesh.elems)
567 .size(maxDumpPerSide)
568 .offset(mesh.elems.size() - maxDumpPerSide);
569
570 SLIC_ASSERT(begSet.isValid(verboseOutput));
571 SLIC_ASSERT(endSet.isValid(verboseOutput));
572
573 // Use subsets to output a few samples from the beginning and end of the tube
574 std::stringstream elemStream, mStream, pStream, eStream, rStream;
575
576 elemStream << std::setw(5) << std::setfill(' ');
577 mStream << std::setw(5) << std::setfill(' ') << std::setprecision(3);
578 pStream << std::setw(5) << std::setfill(' ') << std::setprecision(3);
579 eStream << std::setw(5) << std::setfill(' ') << std::setprecision(3);
580 rStream << std::setw(5) << std::setfill(' ') << std::setprecision(3);
581
582 for(int i = 0; i < begSet.size(); ++i)
583 {
584 ShockTubeMesh::IndexType ind = begSet[i];
585 if(i == 0)
586 elemStream << "IN"
587 << "\t";
588 else
589 elemStream << ind << "\t";
590
591 mStream << mass[ind] << "\t";
592 pStream << momentum[ind] << "\t";
593 eStream << energy[ind] << "\t";
594 rStream << pressure[ind] << "\t";
595 }
596
597 elemStream << "...\t";
598 mStream << "...\t";
599 pStream << "...\t";
600 eStream << "...\t";
601 rStream << "...\t";
602
603 for(int i = 0; i < endSet.size(); ++i)
604 {
605 ShockTubeMesh::IndexType ind = endSet[i];
606 if(ind == endSet.parentSet()->size() - 1)
607 elemStream << "OUT"
608 << "\t";
609 else
610 elemStream << ind << "\t";
611
612 mStream << mass[ind] << "\t";
613 pStream << momentum[ind] << "\t";
614 eStream << energy[ind] << "\t";
615 rStream << pressure[ind] << "\t";
616 }
617
618 SLIC_INFO("Data dump: \n"
619 << "Elem idx: " << elemStream.str() << "\n"
620 << "mass: " << mStream.str() << "\n"
621 << "momemtum: " << pStream.str() << "\n"
622 << "energy: " << eStream.str() << "\n"
623 << "pressure: " << rStream.str() << "\n");
624 }
625
626 } // end namespace slamShocktube
627
628 /**************************************************************************
629 * Subroutine: main
630 * Purpose : Simulate a 1D Shock Tube using split flux Euler formulation
631 *************************************************************************/
632
main(void)633 int main(void)
634 {
635 using namespace slamShocktube;
636 axom::slic::SimpleLogger logger;
637
638 // We should be able to parallelize pretty easily by
639 // adding an MPI_Init() here, modifying the setup slightly,
640 // adding a communication subroutine in the main loop,
641 // and calling MPI_Finalize() at the end of main()
642
643 ShockTubeMesh mesh;
644
645 GetUserInput();
646
647 CreateShockTubeMesh(&mesh); // setup sets and relations
648 InitializeShockTube(mesh); // setup fields
649
650 int numTotalCycles = intsRegistry.getScalar("numTotalCycles");
651 int dumpInterval = intsRegistry.getScalar("numCyclesPerDump");
652
653 // use the & operation when you want to update the param directly
654 auto& currCycle = intsRegistry.getScalar("cycle");
655 for(currCycle = 0; currCycle < numTotalCycles; ++currCycle)
656 {
657 if(currCycle % dumpInterval == 0)
658 {
659 SLIC_INFO("\tStarting cycle " << currCycle << " at time "
660 << realsRegistry.getScalar("time"));
661 dumpData(mesh);
662 }
663
664 ComputeFaceInfo(mesh);
665 UpdateElemInfo(mesh);
666 }
667
668 SLIC_INFO("\tFinished cycle " << currCycle << " at time "
669 << realsRegistry.getScalar("time"));
670
671 dumpData(mesh);
672
673 SLIC_INFO("done.");
674
675 return 0;
676 }
677