Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Inciter/Transporter.cpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.
7 : : All rights reserved. See the LICENSE file for details.
8 : : \brief Transporter drives the time integration of transport equations
9 : : \details Transporter drives the time integration of transport equations.
10 : : The implementation uses the Charm++ runtime system and is fully asynchronous,
11 : : overlapping computation, communication as well as I/O. The algorithm
12 : : utilizes the structured dagger (SDAG) Charm++ functionality. The high-level
13 : : overview of the algorithm structure and how it interfaces with Charm++ is
14 : : discussed in the Charm++ interface file src/Inciter/transporter.ci.
15 : : */
16 : : // *****************************************************************************
17 : :
18 : : #include <string>
19 : : #include <iostream>
20 : : #include <cstddef>
21 : : #include <unordered_set>
22 : : #include <limits>
23 : : #include <cmath>
24 : :
25 : : #include <brigand/algorithms/for_each.hpp>
26 : :
27 : : #include "Macro.hpp"
28 : : #include "Transporter.hpp"
29 : : #include "Fields.hpp"
30 : : #include "PDEStack.hpp"
31 : : #include "UniPDF.hpp"
32 : : #include "PDFWriter.hpp"
33 : : #include "ContainerUtil.hpp"
34 : : #include "LoadDistributor.hpp"
35 : : #include "MeshReader.hpp"
36 : : #include "Inciter/InputDeck/InputDeck.hpp"
37 : : #include "NodeDiagnostics.hpp"
38 : : #include "ElemDiagnostics.hpp"
39 : : #include "DiagWriter.hpp"
40 : : #include "Callback.hpp"
41 : : #include "CartesianProduct.hpp"
42 : :
43 : : #include "NoWarning/inciter.decl.h"
44 : : #include "NoWarning/partitioner.decl.h"
45 : :
46 : : extern CProxy_Main mainProxy;
47 : :
48 : : namespace inciter {
49 : :
50 : : extern ctr::InputDeck g_inputdeck_defaults;
51 : : extern ctr::InputDeck g_inputdeck;
52 : : extern std::vector< CGPDE > g_cgpde;
53 : : extern std::vector< DGPDE > g_dgpde;
54 : : extern std::vector< FVPDE > g_fvpde;
55 : :
56 : : }
57 : :
58 : : using inciter::Transporter;
59 : :
60 : 190 : Transporter::Transporter() :
61 : : m_input( input() ),
62 : : m_nchare( m_input.size() ),
63 : : m_meshid(),
64 [ + - ]: 190 : m_ncit( m_nchare.size(), 0 ),
65 : : m_nload( 0 ),
66 : : m_ntrans( 0 ),
67 : : m_ndtmsh( 0 ),
68 : : m_dtmsh(),
69 : : m_npart( 0 ),
70 : : m_nstat( 0 ),
71 : : m_ndisc( 0 ),
72 : : m_nchk( 0 ),
73 : : m_ncom( 0 ),
74 [ + - ]: 190 : m_nt0refit( m_nchare.size(), 0 ),
75 : 380 : m_ndtrefit( m_nchare.size(), 0 ),
76 : 380 : m_noutrefit( m_nchare.size(), 0 ),
77 : 380 : m_noutderefit( m_nchare.size(), 0 ),
78 : : m_scheme(),
79 : : m_partitioner(),
80 : : m_refiner(),
81 : : m_meshwriter(),
82 : : m_sorter(),
83 : : m_nelem( m_nchare.size() ),
84 : : m_npoin(),
85 [ + - ]: 190 : m_finished( m_nchare.size(), 0 ),
86 : : m_meshvol( m_nchare.size() ),
87 : : m_minstat( m_nchare.size() ),
88 : : m_maxstat( m_nchare.size() ),
89 : : m_avgstat( m_nchare.size() ),
90 : : m_timer(),
91 [ + - ]: 190 : m_progMesh( g_inputdeck.get< tag::cmd, tag::feedback >(),
92 : : ProgMeshPrefix, ProgMeshLegend ),
93 : 190 : m_progWork( g_inputdeck.get< tag::cmd, tag::feedback >(),
94 [ + - ][ + - ]: 950 : ProgWorkPrefix, ProgWorkLegend )
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + + ][ + - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
95 : : // *****************************************************************************
96 : : // Constructor
97 : : // *****************************************************************************
98 : : {
99 : : // Echo configuration to screen
100 [ + - ][ + - ]: 190 : info( printer() );
101 : :
102 : 190 : const auto nstep = g_inputdeck.get< tag::nstep >();
103 : 190 : const auto t0 = g_inputdeck.get< tag::t0 >();
104 : 190 : const auto term = g_inputdeck.get< tag::term >();
105 : 190 : const auto constdt = g_inputdeck.get< tag::dt >();
106 : :
107 : : // If the desired max number of time steps is larger than zero, and the
108 : : // termination time is larger than the initial time, and the constant time
109 : : // step size (if that is used) is smaller than the duration of the time to be
110 : : // simulated, we have work to do, otherwise, finish right away. If a constant
111 : : // dt is not used, that part of the logic is always true as the default
112 : : // constdt is zero, see inciter::ctr::InputDeck::InputDeck().
113 [ + - ][ + - ]: 190 : if ( nstep != 0 && term > t0 && constdt < term-t0 ) {
[ + - ]
114 : :
115 : : // Enable SDAG waits for collecting mesh statistics
116 [ + - ]: 190 : thisProxy.wait4stat();
117 : :
118 : : // Configure and write diagnostics file header
119 [ + - ]: 190 : diagHeader();
120 : :
121 : : // Create mesh partitioner AND boundary condition object group
122 [ + - ]: 190 : createPartitioner();
123 : :
124 [ - - ]: 0 : } else finish(); // stop if no time stepping requested
125 : 190 : }
126 : :
127 : 2 : Transporter::Transporter( CkMigrateMessage* m ) :
128 : : CBase_Transporter( m ),
129 [ + - ]: 2 : m_progMesh( g_inputdeck.get< tag::cmd, tag::feedback >(),
130 : : ProgMeshPrefix, ProgMeshLegend ),
131 : 2 : m_progWork( g_inputdeck.get< tag::cmd, tag::feedback >(),
132 [ + - ][ + + ]: 10 : ProgWorkPrefix, ProgWorkLegend )
[ + - ]
133 : : // *****************************************************************************
134 : : // Migrate constructor: returning from a checkpoint
135 : : //! \param[in] m Charm++ migrate message
136 : : // *****************************************************************************
137 : : {
138 [ + - ]: 2 : auto print = printer();
139 [ + - ][ + - ]: 2 : print.diag( "Restarted from checkpoint" );
140 [ + - ]: 2 : info( print );
141 [ + - ]: 2 : inthead( print );
142 : 2 : }
143 : :
144 : : std::vector< std::string >
145 : 190 : Transporter::input()
146 : : // *****************************************************************************
147 : : // Generate list of input mesh filenames configured by the user
148 : : //! \return List of input mesh filenames configured by the user
149 : : //! \details If the input file is given on the command line, a single solver
150 : : //! will be instantiated on the single mesh, solving potentially multiple
151 : : //! systems of (potentially coupled) equations. If the input file is not given
152 : : //! on the command line, the mesh files are expected to be configured in the
153 : : //! control/input file, associating a potentially different mesh to each
154 : : //! solver. Both configurations allow the solution of coupled systems, but the
155 : : //! first one solves all equations on the same mesh, while the latter can
156 : : //! couple solutions computed on multiple different meshes.
157 : : // *****************************************************************************
158 : : {
159 : : // Query input mesh filename specified on the command line
160 : : const auto& cmdinput = g_inputdeck.get< tag::cmd, tag::io, tag::input >();
161 : :
162 : : // Extract mesh filenames specified in the control file (assigned to solvers)
163 : 190 : std::vector< std::string > ctrinput;
164 [ + + ]: 381 : for (const auto& im : g_inputdeck.get< tag::mesh >()) {
165 [ + - ]: 191 : ctrinput.push_back(im.get< tag::filename >());
166 : : }
167 : :
168 [ + + ][ - + ]: 190 : ErrChk( not cmdinput.empty() or not ctrinput.empty(),
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
169 : : "Either a single input mesh must be given on the command line or multiple "
170 : : "meshes must be configured in the control file." );
171 : :
172 : : // Prepend control file path to mesh filenames in given in control file
173 [ + - ]: 190 : if (not ctrinput.empty()) {
174 : : const auto& ctr = g_inputdeck.get< tag::cmd, tag::io, tag::control >();
175 [ + - ]: 190 : auto path = ctr.substr( 0, ctr.find_last_of("/")+1 );
176 [ + + ][ + - ]: 381 : for (auto& f : ctrinput) f = path + f;
177 : : }
178 : :
179 [ + + ][ - + ]: 552 : if (cmdinput.empty()) return ctrinput; else return { cmdinput };
[ + + ][ + + ]
[ - - ][ - - ]
180 : : }
181 : :
182 : : void
183 : 192 : Transporter::info( const InciterPrint& print )
184 : : // *****************************************************************************
185 : : // Echo configuration to screen
186 : : //! \param[in] print Pretty printer object to use for printing
187 : : // *****************************************************************************
188 : : {
189 [ + - ][ + - ]: 384 : print.part( "Factory" );
190 : :
191 : : // Print out info data layout
192 [ + - ][ + - ]: 384 : print.list( "Unknowns data layout (CMake: FIELD_DATA_LAYOUT)",
193 [ + - ][ + + ]: 576 : std::list< std::string >{ tk::Fields::layout() } );
[ - + ][ - - ]
[ - - ]
194 : :
195 : : // Re-create partial differential equations stack for output
196 : 384 : PDEStack stack;
197 : :
198 : : // Print out information on PDE factories
199 [ + - ][ + - ]: 384 : print.eqlist( "Registered PDEs using continuous Galerkin (CG) methods",
[ + - ]
200 : : stack.cgfactory(), stack.cgntypes() );
201 [ + - ][ + - ]: 384 : print.eqlist( "Registered PDEs using discontinuous Galerkin (DG) methods",
[ + - ]
202 : : stack.dgfactory(), stack.dgntypes() );
203 [ + - ][ + - ]: 384 : print.eqlist( "Registered PDEs using finite volume (DG) methods",
[ + - ]
204 : : stack.fvfactory(), stack.fvntypes() );
205 : : print.endpart();
206 : :
207 : : // Print out information on problem
208 [ + - ][ + - ]: 384 : print.part( "Problem" );
[ + - ]
209 : :
210 : : // Print out info on problem title
211 [ + - ]: 192 : if ( !g_inputdeck.get< tag::title >().empty() )
212 [ + - ]: 192 : print.title( g_inputdeck.get< tag::title >() );
213 : :
214 : 192 : const auto nstep = g_inputdeck.get< tag::nstep >();
215 : 192 : const auto t0 = g_inputdeck.get< tag::t0 >();
216 : 192 : const auto term = g_inputdeck.get< tag::term >();
217 : 192 : const auto constdt = g_inputdeck.get< tag::dt >();
218 : 192 : const auto cfl = g_inputdeck.get< tag::cfl >();
219 : 192 : const auto scheme = g_inputdeck.get< tag::scheme >();
220 : :
221 : : // Print discretization parameters
222 [ + - ][ + - ]: 192 : print.section( "Discretization parameters" );
223 [ + - ]: 192 : print.Item< ctr::Scheme, tag::scheme >();
224 [ + - ][ + - ]: 192 : print.item( "Implicit-Explicit Runge-Kutta",
225 : : g_inputdeck.get< tag::imex_runge_kutta >() );
226 : :
227 [ + - ][ + + ]: 192 : if (g_inputdeck.centering() == tk::Centering::ELEM)
228 : : {
229 [ + - ]: 108 : print.Item< ctr::Limiter, tag::limiter >();
230 : :
231 [ + - ][ + - ]: 108 : print.item("Shock detection based limiting",
232 : : g_inputdeck.get< tag::shock_detector_coeff >());
233 : :
234 [ - + ]: 108 : if (g_inputdeck.get< tag::accuracy_test >())
235 : : {
236 [ - - ][ - - ]: 0 : print.item("WARNING: order-of-accuracy testing enabled",
237 : : "robustness corrections inactive");
238 : : }
239 : :
240 [ + - ]: 216 : print.item("Limited solution projection",
241 [ + - ]: 108 : g_inputdeck.get< tag::limsol_projection >());
242 : : }
243 [ + - ]: 192 : print.item( "PE-locality mesh reordering",
244 [ + - ]: 192 : g_inputdeck.get< tag::pelocal_reorder >() );
245 [ + - ]: 192 : print.item( "Operator-access mesh reordering",
246 [ + - ]: 192 : g_inputdeck.get< tag::operator_reorder >() );
247 : 192 : auto steady = g_inputdeck.get< tag::steady_state >();
248 [ + - ][ + - ]: 192 : print.item( "Local time stepping", steady );
249 [ + + ]: 192 : if (steady) {
250 [ + - ][ + - ]: 2 : print.item( "L2-norm residual convergence criterion",
251 : : g_inputdeck.get< tag::residual >() );
252 [ + - ][ + - ]: 4 : print.item( "Convergence criterion component index",
253 : : g_inputdeck.get< tag::rescomp >() );
254 : : }
255 [ + - ][ + - ]: 192 : print.item( "Number of time steps", nstep );
256 [ + - ][ + - ]: 192 : print.item( "Start time", t0 );
257 [ + - ][ + - ]: 192 : print.item( "Terminate time", term );
258 : :
259 [ + + ]: 192 : if (constdt > std::numeric_limits< tk::real >::epsilon())
260 [ + - ][ + - ]: 250 : print.item( "Constant time step size", constdt );
261 [ + - ]: 67 : else if (cfl > std::numeric_limits< tk::real >::epsilon())
262 : : {
263 [ + - ][ + - ]: 134 : print.item( "CFL coefficient", cfl );
264 : : }
265 : :
266 : : const auto& meshes = g_inputdeck.get< tag::mesh >();
267 : : const auto& depvars = g_inputdeck.get< tag::depvar >();
268 [ + + ]: 385 : for (std::size_t i=0; i<meshes.size(); ++i) {
269 [ + - ][ + - ]: 772 : print.item( "Dependent var name and assoc. mesh", std::string{depvars[i]}
[ + - ][ + + ]
270 [ + - ][ + - ]: 386 : + " - " + meshes[i].get< tag::filename >() );
[ - + ][ - + ]
[ - - ][ - - ]
271 : : }
272 : :
273 : : const auto& rbmotion = g_inputdeck.get< tag::rigid_body_motion >();
274 [ - + ]: 192 : if (rbmotion.get< tag::rigid_body_movt >()) {
275 : : const auto& rbdof = rbmotion.get< tag::rigid_body_dof >();
276 [ - - ][ - - ]: 0 : print.item( "Rigid body motion DOF", rbdof );
277 [ - - ]: 0 : if (rbdof == 3)
278 [ - - ][ - - ]: 0 : print.item( "Rigid body 3-DOF symmetry plane",
279 : : rbmotion.get< tag::symmetry_plane >() );
280 : : }
281 : :
282 : : // Print out info on settings of selected partial differential equations
283 [ + - ][ + - ]: 384 : print.pdes( "Partial differential equations integrated", stack.info() );
[ + - ]
284 : :
285 : : // Print out adaptive polynomial refinement configuration
286 [ + + ]: 192 : if (scheme == ctr::SchemeType::PDG) {
287 [ + - ][ + - ]: 12 : print.section( "Polynomial refinement (p-ref)" );
288 [ + - ]: 12 : print.item( "p-refinement",
289 [ + - ]: 12 : g_inputdeck.get< tag::pref, tag::pref >() );
290 [ + - ]: 12 : print.Item< ctr::PrefIndicator, tag::pref, tag::indicator >();
291 [ + - ][ + - ]: 12 : print.item( "Max degrees of freedom",
292 : : g_inputdeck.get< tag::pref, tag::ndofmax >() );
293 [ + - ][ + - ]: 24 : print.item( "Tolerance",
294 : : g_inputdeck.get< tag::pref, tag::tolref >() );
295 : : }
296 : :
297 : : // Print out adaptive mesh refinement configuration
298 : 192 : const auto amr = g_inputdeck.get< tag::amr, tag::amr >();
299 [ + + ]: 192 : if (amr) {
300 [ + - ][ + - ]: 20 : print.section( "Mesh refinement (h-ref)" );
301 : 20 : auto maxlevels = g_inputdeck.get< tag::amr, tag::maxlevels >();
302 [ + - ][ + - ]: 20 : print.item( "Maximum mesh refinement levels", maxlevels );
303 [ + - ]: 20 : print.Item< ctr::AMRError, tag::amr, tag::error >();
304 : 20 : auto t0ref = g_inputdeck.get< tag::amr, tag::t0ref >();
305 [ + - ][ + - ]: 20 : print.item( "Refinement at t<0 (t0ref)", t0ref );
306 [ + - ]: 20 : if (t0ref) {
307 : : const auto& initref = g_inputdeck.get< tag::amr, tag::initial >();
308 [ + - ][ + - ]: 20 : print.item( "Initial refinement steps", initref.size() );
309 : :
310 : : auto eps = std::numeric_limits< tk::real >::epsilon();
311 : :
312 : : const auto& amr_coord = g_inputdeck.get< tag::amr, tag::coords >();
313 : : const auto& amr_defcoord = g_inputdeck_defaults.get< tag::amr, tag::coords >();
314 : :
315 : 20 : auto xminus = amr_coord.get< tag::xminus >();
316 : 20 : auto xminus_default = amr_defcoord.get< tag::xminus >();
317 [ + + ]: 20 : if (std::abs( xminus - xminus_default ) > eps)
318 [ + - ][ + - ]: 2 : print.item( "Initial refinement x-", xminus );
319 : 20 : auto xplus = amr_coord.get< tag::xplus >();
320 : 20 : auto xplus_default = amr_defcoord.get< tag::xplus >();
321 [ - + ]: 20 : if (std::abs( xplus - xplus_default ) > eps)
322 [ - - ][ - - ]: 0 : print.item( "Initial refinement x+", xplus );
323 : :
324 : 20 : auto yminus = amr_coord.get< tag::yminus >();
325 : 20 : auto yminus_default = amr_defcoord.get< tag::yminus >();
326 [ - + ]: 20 : if (std::abs( yminus - yminus_default ) > eps)
327 [ - - ][ - - ]: 0 : print.item( "Initial refinement y-", yminus );
328 : 20 : auto yplus = amr_coord.get< tag::yplus >();
329 : 20 : auto yplus_default = amr_defcoord.get< tag::yplus >();
330 [ - + ]: 20 : if (std::abs( yplus - yplus_default ) > eps)
331 [ - - ][ - - ]: 0 : print.item( "Initial refinement y+", yplus );
332 : :
333 : 20 : auto zminus = amr_coord.get< tag::zminus >();
334 : 20 : auto zminus_default = amr_defcoord.get< tag::zminus >();
335 [ - + ]: 20 : if (std::abs( zminus - zminus_default ) > eps)
336 [ - - ][ - - ]: 0 : print.item( "Initial refinement z-", zminus );
337 : 20 : auto zplus = amr_coord.get< tag::zplus >();
338 : 20 : auto zplus_default = amr_defcoord.get< tag::zplus >();
339 [ - + ]: 20 : if (std::abs( zplus - zplus_default ) > eps)
340 [ - - ][ - - ]: 0 : print.item( "Initial refinement z+", zplus );
341 : : }
342 : 20 : auto dtref = g_inputdeck.get< tag::amr, tag::dtref >();
343 [ + - ][ + - ]: 20 : print.item( "Refinement at t>0 (dtref)", dtref );
344 [ - + ]: 20 : if (dtref) {
345 : 0 : auto dtfreq = g_inputdeck.get< tag::amr, tag::dtfreq >();
346 [ - - ][ - - ]: 0 : print.item( "Mesh refinement frequency, t>0", dtfreq );
347 [ - - ]: 0 : print.item( "Uniform-only mesh refinement, t>0",
348 [ - - ]: 0 : g_inputdeck.get< tag::amr, tag::dtref_uniform >() );
349 : : }
350 [ + - ][ + - ]: 20 : print.item( "Refinement tolerance",
351 : : g_inputdeck.get< tag::amr, tag::tol_refine >() );
352 [ + - ][ + - ]: 40 : print.item( "De-refinement tolerance",
353 : : g_inputdeck.get< tag::amr, tag::tol_derefine >() );
354 : : }
355 : :
356 : : // Print out ALE configuration
357 : 192 : const auto ale = g_inputdeck.get< tag::ale, tag::ale >();
358 [ + + ]: 192 : if (ale) {
359 [ + - ][ + - ]: 10 : print.section( "Arbitrary Lagrangian-Eulerian (ALE) mesh motion" );
360 : 10 : auto dvcfl = g_inputdeck.get< tag::ale, tag::dvcfl >();
361 [ + - ][ + - ]: 10 : print.item( "Volume-change CFL coefficient", dvcfl );
362 [ + - ]: 10 : print.Item< ctr::MeshVelocity, tag::ale, tag::mesh_velocity >();
363 [ + - ]: 10 : print.Item< ctr::MeshVelocitySmoother, tag::ale, tag::smoother >();
364 [ + - ][ + - ]: 20 : print.item( "Mesh motion dimensions", tk::parameters(
[ + - ][ - + ]
365 : : g_inputdeck.get< tag::ale, tag::mesh_motion >() ) );
366 : : const auto& meshforce = g_inputdeck.get< tag::ale, tag::meshforce >();
367 [ + - ][ + - ]: 20 : print.item( "Mesh velocity force coefficients", tk::parameters(meshforce) );
[ + - ][ - + ]
368 [ + - ][ + - ]: 10 : print.item( "Vorticity multiplier",
369 : : g_inputdeck.get< tag::ale, tag::vortmult >() );
370 [ + - ][ + - ]: 10 : print.item( "Mesh velocity linear solver tolerance",
371 : : g_inputdeck.get< tag::ale, tag::tolerance >() );
372 [ + - ][ + - ]: 20 : print.item( "Mesh velocity linear solver maxit",
[ + + ]
373 : : g_inputdeck.get< tag::ale, tag::maxit >() );
374 : : const auto& dir = g_inputdeck.get< tag::ale, tag::dirichlet >();
375 [ + + ]: 10 : if (not dir.empty())
376 [ + - ][ + - ]: 10 : print.item( "Mesh velocity Dirichlet BC sideset(s)",
[ - + ]
377 [ + - ]: 10 : tk::parameters( dir ) );
378 : : const auto& sym = g_inputdeck.get< tag::ale, tag::symmetry >();
379 [ + + ]: 10 : if (not sym.empty())
380 [ + - ][ + - ]: 6 : print.item( "Mesh velocity symmetry BC sideset(s)",
[ - + ]
381 [ + - ]: 6 : tk::parameters( sym ) );
382 : : std::size_t i = 1;
383 [ + + ]: 12 : for (const auto& m : g_inputdeck.get< tag::ale, tag::move >()) {
384 [ + - ]: 2 : tk::ctr::UserTable opt;
385 [ + - ][ + - ]: 4 : print.item( opt.group() + ' ' + std::to_string(i) + " interpreted as",
[ + - ][ + - ]
[ - + ][ - + ]
[ - + ][ + - ]
[ - - ][ - - ]
[ - - ]
386 : 2 : opt.name( m.get< tag::fntype >() ) );
387 : : const auto& s = m.get< tag::sideset >();
388 [ + - ]: 2 : if (not s.empty())
389 [ + - ][ + - ]: 4 : print.item( "Moving sideset(s) with table " + std::to_string(i),
[ - + ][ - + ]
[ - - ][ - - ]
390 [ + - ]: 4 : tk::parameters(s));
391 : 2 : ++i;
392 : : }
393 : : }
394 : :
395 : : // Print I/O filenames
396 [ + - ][ + - ]: 192 : print.section( "Input/Output filenames and directories" );
397 [ + - ][ + - ]: 384 : print.item( "Input mesh(es)", tk::parameters( m_input ) );
[ + - ][ + + ]
398 : : const auto& of = g_inputdeck.get< tag::cmd, tag::io, tag::output >();
399 [ + - ][ + - ]: 384 : print.item( "Volume field output file(s)",
[ + - ]
400 [ + - ]: 192 : of + ".e-s.<meshid>.<numchares>.<chareid>" );
401 [ + - ][ + - ]: 384 : print.item( "Surface field output file(s)",
[ + - ]
402 [ + - ]: 192 : of + "-surf.<surfid>.e-s.<meshid>.<numchares>.<chareid>" );
403 [ + - ][ + - ]: 384 : print.item( "History output file(s)", of + ".hist.{pointid}" );
[ + - ][ + - ]
404 [ + - ][ + - ]: 192 : print.item( "Diagnostics file",
405 : : g_inputdeck.get< tag::cmd, tag::io, tag::diag >() );
406 [ + - ][ + - ]: 384 : print.item( "Checkpoint/restart directory",
[ - + ]
407 [ + - ]: 192 : g_inputdeck.get< tag::cmd, tag::io, tag::restart >() + '/' );
408 : :
409 : : // Print output intervals
410 [ + - ][ + - ]: 192 : print.section( "Output intervals (in units of iteration count)" );
411 [ + - ][ + - ]: 192 : print.item( "TTY", g_inputdeck.get< tag::ttyi>() );
412 [ + - ][ + - ]: 192 : print.item( "Field and surface",
413 : : g_inputdeck.get< tag::field_output, tag::interval >() );
414 [ + - ][ + - ]: 192 : print.item( "History",
415 : : g_inputdeck.get< tag::history_output, tag::interval >() );
416 [ + - ][ + - ]: 192 : print.item( "Diagnostics",
417 : : g_inputdeck.get< tag::diagnostics, tag::interval >() );
418 [ + - ][ + - ]: 192 : print.item( "Checkpoint/restart",
419 : : g_inputdeck.get< tag::cmd, tag::rsfreq >() );
420 : 192 : auto tf = g_inputdeck.get< tag::field_output, tag::time_interval >();
421 : 192 : auto th = g_inputdeck.get< tag::history_output, tag::time_interval >();
422 [ - + ][ - - ]: 192 : if (tf>0.0 || th>0.0) {
423 [ + - ][ + - ]: 192 : print.section( "Output intervals (in units of physics time)" );
424 [ + - ][ + - ]: 384 : if (tf > 0.0) print.item( "Field and surface", tf );
[ + - ]
425 [ + - ][ + - ]: 384 : if (th > 0.0) print.item( "History", th );
[ + - ]
426 : : }
427 : : const auto& rf = g_inputdeck.get< tag::field_output, tag::time_range >();
428 : : const auto& rh = g_inputdeck.get< tag::history_output, tag::time_range >();
429 [ + - ][ - + ]: 192 : if (not rf.empty() or not rh.empty()) {
430 [ - - ][ - - ]: 0 : print.section( "Output time ranges (in units of physics time)" );
431 [ - - ][ - - ]: 0 : print.item("Field output { mintime, maxtime, dt }", tk::parameters(rf));
[ - - ][ - - ]
432 [ - - ][ - - ]: 0 : print.item("History output { mintime, maxtime, dt }", tk::parameters(rh));
[ - - ][ - - ]
433 : : }
434 : :
435 : : //// Print output variables: fields and surfaces
436 : : //const auto nodeoutvars = g_inputdeck.outvars( tk::Centering::NODE );
437 : : //const auto elemoutvars = g_inputdeck.outvars( tk::Centering::ELEM );
438 : : //const auto outsets = g_inputdeck.outsets();
439 : : //if (!nodeoutvars.empty() || !elemoutvars.empty() || !outsets.empty())
440 : : // print.section( "Output fields" );
441 : : //if (!nodeoutvars.empty())
442 : : // print.item( "Node field(s)", tk::parameters(nodeoutvars) );
443 : : //if (!elemoutvars.empty())
444 : : // print.item( "Elem field(s)", tk::parameters(elemoutvars) );
445 : : //if (!aliases.empty())
446 : : // print.item( "Alias(es)", tk::parameters(aliases) );
447 : : //if (!outsets.empty())
448 : : // print.item( "Surface side set(s)", tk::parameters(outsets) );
449 : :
450 : : // Print output variables: history
451 : : const auto& pt = g_inputdeck.get< tag::history_output, tag::point >();
452 [ + + ]: 192 : if (!pt.empty()) {
453 [ + - ][ + - ]: 8 : print.section( "Output time history" );
454 [ + + ]: 12 : for (std::size_t p=0; p<pt.size(); ++p) {
455 : : const auto& id = pt[p].get< tag::id >();
456 [ + - ]: 8 : std::stringstream ss;
457 : 8 : auto prec = g_inputdeck.get< tag::history_output, tag::precision >();
458 [ + - ]: 8 : ss << std::setprecision( static_cast<int>(prec) );
459 : : ss << of << ".hist." << id;
460 [ + - ][ + - ]: 16 : print.longitem( "At point " + id + ' ' +
[ + - ][ + - ]
[ - + ][ - + ]
[ - + ][ - - ]
[ - - ][ - - ]
461 [ + - ][ - + ]: 16 : tk::parameters(pt[p].get<tag::coord>()), ss.str() );
[ - - ]
462 : : }
463 : : }
464 : :
465 : : print.endsubsection();
466 : 192 : }
467 : :
468 : : bool
469 [ + - ]: 274 : Transporter::matchBCs( std::map< int, std::vector< std::size_t > >& bnd )
470 : : // *****************************************************************************
471 : : // Verify that side sets specified in the control file exist in mesh file
472 : : //! \details This function does two things: (1) it verifies that the side
473 : : //! sets used in the input file (either to which boundary conditions (BC)
474 : : //! are assigned or listed as field output by the user in the
475 : : //! input file) all exist among the side sets read from the input mesh
476 : : //! file and errors out if at least one does not, and (2) it matches the
477 : : //! side set ids at which the user has configured BCs (or listed as an output
478 : : //! surface) to side set ids read from the mesh file and removes those face
479 : : //! and node lists associated to side sets that the user did not set BCs or
480 : : //! listed as field output on (as they will not need processing further since
481 : : //! they will not be used).
482 : : //! \param[in,out] bnd Node or face lists mapped to side set ids
483 : : //! \return True if sidesets have been used and found in mesh
484 : : // *****************************************************************************
485 : : {
486 : : // Query side set ids at which BCs assigned for all BC types for all PDEs
487 : : std::unordered_set< int > usedsets;
488 : :
489 : : using bclist = ctr::bclist::Keys;
490 : : const auto& bcs = g_inputdeck.get< tag::bc >();
491 [ + - ]: 274 : brigand::for_each< bclist >( UserBC( g_inputdeck, usedsets ) );
492 : :
493 : : // Query side sets of time dependent and inlet BCs (since these are not a part
494 : : // of tag::bc)
495 [ + + ]: 552 : for (const auto& bci : bcs) {
496 [ + + ]: 287 : for (const auto& b : bci.get< tag::inlet >()) {
497 [ + + ]: 18 : for (auto i : b.get< tag::sideset >())
498 [ + - ]: 9 : usedsets.insert(static_cast<int>(i));
499 : : }
500 [ + + ]: 282 : for (const auto& b : bci.get< tag::timedep >()) {
501 [ + + ]: 8 : for (auto i : b.get< tag::sideset >())
502 [ + - ]: 4 : usedsets.insert(static_cast<int>(i));
503 : : }
504 : : }
505 : :
506 : : // Query side sets of boundaries prescribed as moving with ALE
507 [ + + ]: 278 : for (const auto& move : g_inputdeck.get< tag::ale, tag::move >())
508 [ + + ]: 8 : for (auto i : move.get< tag::sideset >())
509 [ + - ]: 4 : usedsets.insert(static_cast<int>(i));
510 : :
511 : : // Add sidesets requested for field output
512 : : const auto& ss = g_inputdeck.get< tag::cmd, tag::io, tag::surface >();
513 [ - + ]: 274 : for (const auto& s : ss) {
514 [ - - ]: 0 : std::stringstream conv( s );
515 : : int num;
516 [ - - ]: 0 : conv >> num;
517 : : usedsets.insert( num );
518 : : }
519 : :
520 : : // Find user-configured side set ids among side sets read from mesh file
521 : : std::unordered_set< int > sidesets_used;
522 [ + + ]: 1145 : for (auto i : usedsets) { // for all side sets used in control file
523 [ + + ]: 871 : if (bnd.find(i) != end(bnd)) // used set found among side sets in file
524 : : sidesets_used.insert( i ); // store side set id configured as BC
525 : : //else {
526 : : // Throw( "Boundary conditions specified on side set " +
527 : : // std::to_string(i) + " which does not exist in mesh file" );
528 : : //}
529 : : }
530 : :
531 : : // Remove sidesets not used (will not process those further)
532 : 274 : tk::erase_if( bnd, [&]( auto& item ) {
533 : 1355 : return sidesets_used.find( item.first ) == end(sidesets_used);
534 : : });
535 : :
536 : 548 : return !bnd.empty();
537 : : }
538 : :
539 : : void
540 : 190 : Transporter::createPartitioner()
541 : : // *****************************************************************************
542 : : // Create mesh partitioner AND boundary conditions group
543 : : // *****************************************************************************
544 : : {
545 : 190 : auto scheme = g_inputdeck.get< tag::scheme >();
546 [ + - ]: 190 : auto centering = ctr::Scheme().centering( scheme );
547 : 190 : auto print = printer();
548 : :
549 : : // Create partitioner callbacks (order important)
550 : : tk::PartitionerCallback cbp {{
551 [ + - ][ + - ]: 380 : CkCallback( CkReductionTarget(Transporter,load), thisProxy )
552 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,partitioned), thisProxy )
553 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,distributed), thisProxy )
554 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,refinserted), thisProxy )
555 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,refined), thisProxy )
556 : 190 : }};
557 : :
558 : : // Create refiner callbacks (order important)
559 : : tk::RefinerCallback cbr {{
560 [ + - ][ + - ]: 380 : CkCallback( CkReductionTarget(Transporter,queriedRef), thisProxy )
561 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,respondedRef), thisProxy )
562 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,compatibility), thisProxy )
563 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,bndint), thisProxy )
564 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,matched), thisProxy )
565 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,refined), thisProxy )
566 : 190 : }};
567 : :
568 : : // Create sorter callbacks (order important)
569 : : tk::SorterCallback cbs {{
570 [ + - ]: 190 : CkCallback( CkReductionTarget(Transporter,queried), thisProxy )
571 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,responded), thisProxy )
572 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,discinserted), thisProxy )
573 [ + - ]: 380 : , CkCallback( CkReductionTarget(Transporter,workinserted), thisProxy )
574 : 190 : }};
575 : :
576 : : // Start timer measuring preparation of mesh(es) for partitioning
577 [ + - ]: 190 : m_timer[ TimerTag::MESH_READ ];
578 : :
579 : : // Start preparing mesh(es)
580 [ + - ][ + - ]: 380 : print.diag( "Reading mesh(es)" );
581 : :
582 : : // Create (discretization) Scheme chare worker arrays for all meshes
583 [ + + ]: 381 : for ([[maybe_unused]] const auto& filename : m_input)
584 : : m_scheme.emplace_back( g_inputdeck.get< tag::scheme >(),
585 : : g_inputdeck.get< tag::ale, tag::ale >(),
586 : 191 : need_linearsolver(),
587 [ + - ][ + - ]: 191 : centering );
588 : :
589 [ - + ][ - - ]: 190 : ErrChk( !m_input.empty(), "No input mesh" );
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
590 : :
591 : : // Read boundary (side set) data from a list of input mesh files
592 : 190 : std::size_t meshid = 0;
593 [ + + ]: 381 : for (const auto& filename : m_input) {
594 : : // Create mesh reader for reading side sets from file
595 [ + - ]: 191 : tk::MeshReader mr( filename );
596 : :
597 : : // Read out total number of mesh points from mesh file
598 [ + - ][ + - ]: 191 : m_npoin.push_back( mr.npoin() );
[ + - ][ - - ]
599 : :
600 : : std::map< int, std::vector< std::size_t > > bface;
601 : : std::map< int, std::vector< std::size_t > > faces;
602 : : std::map< int, std::vector< std::size_t > > bnode;
603 : :
604 : : // Read boundary-face connectivity on side sets
605 : : mr.readSidesetFaces( bface, faces );
606 : :
607 : : bool bcs_set = false;
608 [ + + ]: 191 : if (centering == tk::Centering::ELEM) {
609 : :
610 : : // Verify boundarty condition (BC) side sets used exist in mesh file
611 [ + - ]: 108 : bcs_set = matchBCs( bface );
612 : :
613 [ + - ]: 83 : } else if (centering == tk::Centering::NODE) {
614 : :
615 : : // Read node lists on side sets
616 : 83 : bnode = mr.readSidesetNodes();
617 : : // Verify boundarty condition (BC) side sets used exist in mesh file
618 [ + - ]: 83 : bool bcnode_set = matchBCs( bnode );
619 [ + - ]: 83 : bool bcface_set = matchBCs( bface );
620 : 83 : bcs_set = bcface_set or bcnode_set;
621 : : }
622 : :
623 : : // Warn on no BCs
624 [ + + ]: 191 : if (!bcs_set) print << "\n>>> WARNING: No boundary conditions set\n\n";
625 : :
626 [ + - ]: 191 : auto opt = m_scheme[meshid].arrayoptions();
627 : : // Create empty mesh refiner chare array (bound to workers)
628 [ + - ][ + - ]: 382 : m_refiner.push_back( CProxy_Refiner::ckNew(opt) );
629 : : // Create empty mesh sorter Charm++ chare array (bound to workers)
630 [ + - ][ + - ]: 382 : m_sorter.push_back( CProxy_Sorter::ckNew(opt) );
631 : :
632 : : // Create MeshWriter chare group for mesh
633 : 382 : m_meshwriter.push_back(
634 : : tk::CProxy_MeshWriter::ckNew(
635 : : g_inputdeck.get< tag::field_output, tag::filetype >(),
636 : : centering,
637 : : g_inputdeck.get< tag::cmd, tag::benchmark >(),
638 [ + - ]: 191 : m_input.size() ) );
639 : :
640 : : // Create mesh partitioner Charm++ chare nodegroup for all meshes
641 : 0 : m_partitioner.push_back(
642 : : CProxy_Partitioner::ckNew( meshid, filename, cbp, cbr, cbs,
643 [ + - ]: 191 : thisProxy, m_refiner.back(), m_sorter.back(), m_meshwriter.back(),
644 [ + - ]: 191 : m_scheme, bface, faces, bnode ) );
645 : :
646 : 191 : ++meshid;
647 : : }
648 : 190 : }
649 : :
650 : : void
651 : 191 : Transporter::load( std::size_t meshid, std::size_t nelem )
652 : : // *****************************************************************************
653 : : // Reduction target: the mesh has been read from file on all PEs
654 : : //! \param[in] meshid Mesh id (summed accross all compute nodes)
655 : : //! \param[in] nelem Number of mesh elements per mesh (summed across all
656 : : //! compute nodes)
657 : : // *****************************************************************************
658 : : {
659 : 191 : meshid /= static_cast< std::size_t >( CkNumNodes() );
660 : : Assert( meshid < m_nelem.size(), "MeshId indexing out" );
661 : 191 : m_nelem[meshid] = nelem;
662 : :
663 : : // Compute load distribution given total work (nelem) and user-specified
664 : : // virtualization
665 : : uint64_t chunksize, remainder;
666 : 191 : m_nchare[meshid] = static_cast<int>(
667 : 191 : tk::linearLoadDistributor(
668 : : g_inputdeck.get< tag::cmd, tag::virtualization >(),
669 : 191 : m_nelem[meshid], CkNumPes(), chunksize, remainder ) );
670 : :
671 : : // Store sum of meshids (across all chares, key) for each meshid (value).
672 : : // This is used to look up the mesh id after collectives that sum their data.
673 : 191 : m_meshid[ static_cast<std::size_t>(m_nchare[meshid])*meshid ] = meshid;
674 : : Assert( meshid < m_nelem.size(), "MeshId indexing out" );
675 : :
676 : : // Tell the meshwriter for this mesh the total number of its chares
677 : 191 : m_meshwriter[meshid].nchare( meshid, m_nchare[meshid] );
678 : :
679 [ + + ]: 191 : if (++m_nload == m_nelem.size()) { // all meshes have been loaded
680 : 190 : m_nload = 0;
681 : 190 : auto print = printer();
682 : :
683 : : // Start timer measuring preparation of the mesh for partitioning
684 : : const auto& timer = tk::cref_find( m_timer, TimerTag::MESH_READ );
685 [ + - ][ + - ]: 380 : print.diag( "Mesh read time: " + std::to_string( timer.dsec() ) + " sec" );
[ + - ][ - + ]
[ - + ][ - - ]
[ - - ]
686 : :
687 : : // Print out mesh partitioning configuration
688 [ + - ][ + - ]: 190 : print.section( "Mesh partitioning" );
689 [ + - ]: 190 : print.Item< tk::ctr::PartitioningAlgorithm, tag::partitioning >();
690 [ + - ][ + - ]: 190 : print.item( "Virtualization [0.0...1.0]",
691 : : g_inputdeck.get< tag::cmd, tag::virtualization >() );
692 : : // Print out initial mesh statistics
693 [ + - ][ + - ]: 190 : meshstat( "Initial load distribution" );
694 : :
695 : : // Query number of initial mesh refinement steps
696 : : int nref = 0;
697 [ + + ]: 190 : if (g_inputdeck.get< tag::amr, tag::t0ref >())
698 : 20 : nref = static_cast<int>(g_inputdeck.get< tag::amr,
699 : 20 : tag::initial >().size());
700 : :
701 [ + - ]: 190 : m_progMesh.start( print, "Preparing mesh", {{ CkNumPes(), CkNumPes(), nref,
702 [ + - ]: 190 : m_nchare[0], m_nchare[0], m_nchare[0], m_nchare[0] }} );
703 : :
704 : : // Partition first mesh
705 [ + - ]: 190 : m_partitioner[0].partition( m_nchare[0] );
706 : : }
707 : 191 : }
708 : :
709 : : void
710 : 191 : Transporter::partitioned( std::size_t meshid )
711 : : // *****************************************************************************
712 : : // Reduction target: a mesh has been partitioned
713 : : //! \param[in] meshid Mesh id
714 : : // *****************************************************************************
715 : : {
716 [ + + ]: 191 : if (++m_npart == m_nelem.size()) { // all meshes have been partitioned
717 : 190 : m_npart = 0;
718 : : } else { // partition next mesh
719 : 1 : m_partitioner[meshid+1].partition( m_nchare[meshid+1] );
720 : : }
721 : 191 : }
722 : :
723 : : void
724 : 191 : Transporter::distributed( std::size_t meshid )
725 : : // *****************************************************************************
726 : : // Reduction target: all compute nodes have distributed their mesh after
727 : : // partitioning
728 : : //! \param[in] meshid Mesh id
729 : : // *****************************************************************************
730 : : {
731 : 191 : m_partitioner[meshid].refine();
732 : 191 : }
733 : :
734 : : void
735 : 191 : Transporter::refinserted( std::size_t meshid, std::size_t error )
736 : : // *****************************************************************************
737 : : // Reduction target: all compute nodes have created the mesh refiners
738 : : //! \param[in] meshid Mesh id (aggregated across all compute nodes with operator
739 : : //! max)
740 : : //! \param[in] error Error code (aggregated across all compute nodes with
741 : : //! operator max)
742 : : // *****************************************************************************
743 : : {
744 [ - + ]: 191 : if (error) {
745 : :
746 : 0 : printer() << "\n>>> ERROR: A worker chare was not assigned any mesh "
747 [ - - ][ - - ]: 0 : "elements after distributing mesh " + std::to_string(meshid) +
[ - - ][ - - ]
[ - - ][ - - ]
748 : : ". This can happen in SMP-mode with a large +ppn "
749 : : "parameter (number of worker threads per logical node) and is "
750 : : "most likely the fault of the mesh partitioning algorithm not "
751 : : "tolerating the case when it is asked to divide the "
752 : : "computational domain into a number of partitions different "
753 : : "than the number of ranks it is called on, i.e., in case of "
754 : : "overdecomposition and/or calling the partitioner in SMP mode "
755 : : "with +ppn larger than 1. Solution 1: Try a different "
756 : : "partitioning algorithm (e.g., rcb instead of mj). Solution 2: "
757 : : "Decrease +ppn.";
758 : 0 : finish( meshid );
759 : :
760 : : } else {
761 : :
762 : 191 : m_refiner[meshid].doneInserting();
763 : :
764 : : }
765 : 191 : }
766 : :
767 : : void
768 : 87 : Transporter::queriedRef( std::size_t meshid )
769 : : // *****************************************************************************
770 : : // Reduction target: all Refiner chares have queried their boundary edges
771 : : //! \param[in] meshid Mesh id
772 : : // *****************************************************************************
773 : : {
774 : 87 : m_refiner[meshid].response();
775 : 87 : }
776 : :
777 : : void
778 : 87 : Transporter::respondedRef( std::size_t meshid )
779 : : // *****************************************************************************
780 : : // Reduction target: all Refiner chares have setup their boundary edges
781 : : //! \param[in] meshid Mesh id
782 : : // *****************************************************************************
783 : : {
784 : 87 : m_refiner[meshid].refine();
785 : 87 : }
786 : :
787 : : void
788 : 48 : Transporter::compatibility( std::size_t meshid )
789 : : // *****************************************************************************
790 : : // Reduction target: all Refiner chares have received a round of edges,
791 : : // and have run their compatibility algorithm
792 : : //! \param[in] meshid Mesh id (aggregated across all chares using operator max)
793 : : //! \details This is called iteratively, until convergence by Refiner. At this
794 : : //! point all Refiner chares have received a round of edge data (tags whether
795 : : //! an edge needs to be refined, etc.), and applied the compatibility
796 : : //! algorithm independent of other Refiner chares. We keep going until the
797 : : //! mesh is no longer modified by the compatibility algorithm, based on a new
798 : : //! round of edge data communication started in Refiner::comExtra().
799 : : // *****************************************************************************
800 : : {
801 : 48 : m_refiner[meshid].correctref();
802 : 48 : }
803 : :
804 : : void
805 : 89 : Transporter::matched( std::size_t summeshid,
806 : : std::size_t nextra,
807 : : std::size_t nref,
808 : : std::size_t nderef,
809 : : std::size_t sumrefmode )
810 : : // *****************************************************************************
811 : : // Reduction target: all Refiner chares have matched/corrected the tagging
812 : : // of chare-boundary edges, all chares are ready to perform refinement.
813 : : //! \param[in] summeshid Mesh id (summed across all chares)
814 : : //! \param[in] nextra Sum (across all chares) of the number of edges on each
815 : : //! chare that need correction along chare boundaries
816 : : //! \param[in] nref Sum of number of refined tetrahedra across all chares.
817 : : //! \param[in] nderef Sum of number of derefined tetrahedra across all chares.
818 : : //! \param[in] sumrefmode Sum of contributions from all chares, encoding
819 : : //! refinement mode of operation.
820 : : // *****************************************************************************
821 : : {
822 : 89 : auto meshid = tk::cref_find( m_meshid, summeshid );
823 : :
824 : : // If at least a single edge on a chare still needs correction, do correction,
825 : : // otherwise, this mesh refinement step is complete
826 [ + + ]: 89 : if (nextra > 0) {
827 : :
828 : 2 : ++m_ncit[meshid];
829 : 2 : m_refiner[meshid].comExtra();
830 : :
831 : : } else {
832 : :
833 : 87 : auto print = printer();
834 : :
835 : : // decode refmode
836 : : auto refmode = static_cast< Refiner::RefMode >(
837 [ + + ]: 87 : sumrefmode / static_cast<std::size_t>(m_nchare[meshid]) );
838 : :
839 [ + + ]: 87 : if (refmode == Refiner::RefMode::T0REF) {
840 : :
841 [ + - ]: 57 : if (!g_inputdeck.get< tag::cmd, tag::feedback >()) {
842 [ + - ]: 57 : ctr::AMRInitial opt;
843 [ + - ][ + - ]: 798 : print.diag( { "meshid", "t0ref", "type", "nref", "nderef", "ncorr" },
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + + ][ - + ]
[ + + ][ - + ]
[ - - ][ - - ]
[ - - ][ - - ]
844 : : { std::to_string(meshid),
845 [ + - ]: 57 : std::to_string(m_nt0refit[meshid]),
846 : : "initial",
847 : : std::to_string(nref),
848 : : std::to_string(nderef),
849 [ + - ]: 57 : std::to_string(m_ncit[meshid]) } );
850 : 57 : ++m_nt0refit[meshid];
851 : : }
852 [ + - ]: 57 : m_progMesh.inc< REFINE >( print );
853 : :
854 [ - + ]: 30 : } else if (refmode == Refiner::RefMode::DTREF) {
855 : :
856 [ - - ]: 0 : auto dtref_uni = g_inputdeck.get< tag::amr, tag::dtref_uniform >();
857 [ - - ][ - - ]: 0 : print.diag( { "meshid", "dtref", "type", "nref", "nderef", "ncorr" },
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
858 : : { std::to_string(meshid),
859 [ - - ]: 0 : std::to_string(++m_ndtrefit[meshid]),
860 : : (dtref_uni?"uniform":"error"),
861 : : std::to_string(nref),
862 : : std::to_string(nderef),
863 [ - - ]: 0 : std::to_string(m_ncit[meshid]) },
864 : : false );
865 : :
866 [ + + ]: 30 : } else if (refmode == Refiner::RefMode::OUTREF) {
867 : :
868 [ + - ][ + - ]: 180 : print.diag( { "meshid", "outref", "nref", "nderef", "ncorr" },
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + + ][ - + ]
[ + + ][ - + ]
[ - - ][ - - ]
[ - - ][ - - ]
869 : : { std::to_string(meshid),
870 [ + - ]: 15 : std::to_string(++m_noutrefit[meshid]),
871 : : std::to_string(nref),
872 : : std::to_string(nderef),
873 [ + - ]: 15 : std::to_string(m_ncit[meshid]) }, false );
874 : :
875 [ + - ]: 15 : } else if (refmode == Refiner::RefMode::OUTDEREF) {
876 : :
877 [ + - ][ + - ]: 180 : print.diag( { "meshid", "outderef", "nref", "nderef", "ncorr" },
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + + ][ - + ]
[ + + ][ - + ]
[ - - ][ - - ]
[ - - ][ - - ]
878 : : { std::to_string(meshid),
879 [ + - ]: 15 : std::to_string(++m_noutderefit[meshid]),
880 : : std::to_string(nref),
881 : : std::to_string(nderef),
882 [ + - ]: 15 : std::to_string(m_ncit[meshid]) },
883 : : false );
884 : :
885 [ - - ][ - - ]: 0 : } else Throw( "RefMode not implemented" );
[ - - ][ - - ]
[ - - ][ - - ]
886 : :
887 [ + - ]: 87 : m_ncit[meshid] = 0;
888 [ + - ]: 87 : m_refiner[meshid].perform();
889 : :
890 : : }
891 : 89 : }
892 : :
893 : : void
894 : 108 : Transporter::bndint( tk::real sx, tk::real sy, tk::real sz, tk::real cb,
895 : : tk::real summeshid )
896 : : // *****************************************************************************
897 : : // Compute surface integral across the whole problem and perform leak-test
898 : : //! \param[in] sx X component of vector summed
899 : : //! \param[in] sy Y component of vector summed
900 : : //! \param[in] sz Z component of vector summed
901 : : //! \param[in] cb Invoke callback if positive
902 : : //! \param[in] summeshid Mesh id (summed accross all chares)
903 : : //! \details This function aggregates partial surface integrals across the
904 : : //! boundary faces of the whole problem. After this global sum a
905 : : //! non-zero vector result indicates a leak, e.g., a hole in the boundary,
906 : : //! which indicates an error in the boundary face data structures used to
907 : : //! compute the partial surface integrals.
908 : : // *****************************************************************************
909 : : {
910 : 108 : auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
911 : :
912 : 216 : std::stringstream err;
913 [ - + ]: 108 : if (cb < 0.0) {
914 : : err << "Mesh boundary leaky after mesh refinement step; this is due to a "
915 : : "problem with updating the side sets used to specify boundary conditions "
916 [ - - ]: 0 : "on faces: ";
917 [ + - ]: 108 : } else if (cb > 0.0) {
918 : : err << "Mesh boundary leaky during initialization; this is due to "
919 : : "incorrect or incompletely specified boundary conditions for a given input "
920 [ + - ]: 108 : "mesh: ";
921 : : }
922 : :
923 : : auto eps = 1.0e-10;
924 [ + - ][ + - ]: 108 : if (std::abs(sx) > eps || std::abs(sy) > eps || std::abs(sz) > eps) {
[ - + ]
925 : : err << "Integral result must be a zero vector: " << std::setprecision(12) <<
926 : : std::abs(sx) << ", " << std::abs(sy) << ", " << std::abs(sz) <<
927 : : ", eps = " << eps;
928 [ - - ][ - - ]: 0 : Throw( err.str() );
[ - - ][ - - ]
929 : : }
930 : :
931 [ + - ][ + - ]: 108 : if (cb > 0.0) m_scheme[meshid].ghosts().resizeComm();
932 : 108 : }
933 : :
934 : : void
935 : 191 : Transporter::refined( std::size_t summeshid,
936 : : std::size_t nelem,
937 : : std::size_t npoin )
938 : : // *****************************************************************************
939 : : // Reduction target: all chares have refined their mesh
940 : : //! \param[in] summeshid Mesh id (summed accross all Refiner chares)
941 : : //! \param[in] nelem Total number of elements in mesh summed across the
942 : : //! distributed mesh
943 : : //! \param[in] npoin Total number of mesh points summed across the distributed
944 : : //! mesh. Note that in parallel this is larger than the number of points in
945 : : //! the mesh, because the boundary nodes are multi-counted. But we only need
946 : : //! an equal or larger than npoin for Sorter::setup, so this is okay.
947 : : // *****************************************************************************
948 : : {
949 : 191 : auto meshid = tk::cref_find( m_meshid, summeshid );
950 : :
951 : : // Store new number of elements for initially refined mesh
952 : 191 : m_nelem[meshid] = nelem;
953 : :
954 : 191 : m_sorter[meshid].doneInserting();
955 : 191 : m_sorter[meshid].setup( npoin );
956 : 191 : }
957 : :
958 : : void
959 : 191 : Transporter::queried( std::size_t meshid )
960 : : // *****************************************************************************
961 : : // Reduction target: all Sorter chares have queried their boundary edges
962 : : //! \param[in] meshid Mesh id
963 : : // *****************************************************************************
964 : : {
965 : 191 : m_sorter[meshid].response();
966 : 191 : }
967 : :
968 : : void
969 : 191 : Transporter::responded( std::size_t meshid )
970 : : // *****************************************************************************
971 : : // Reduction target: all Sorter chares have responded with their boundary edges
972 : : //! \param[in] meshid Mesh id
973 : : // *****************************************************************************
974 : : {
975 : 191 : m_sorter[meshid].start();
976 : 191 : }
977 : :
978 : : void
979 : 360 : Transporter::resized( std::size_t meshid )
980 : : // *****************************************************************************
981 : : // Reduction target: all worker chares have resized their own mesh data after
982 : : // AMR or ALE
983 : : //! \param[in] meshid Mesh id
984 : : //! \note Only used for nodal schemes
985 : : // *****************************************************************************
986 : : {
987 : 360 : m_scheme[meshid].disc().vol();
988 : 360 : m_scheme[meshid].bcast< Scheme::lhs >();
989 : 360 : }
990 : :
991 : : void
992 : 108 : Transporter::startEsup( std::size_t meshid )
993 : : // *****************************************************************************
994 : : // Reduction target: all worker chares have generated their own esup
995 : : //! \param[in] meshid Mesh id
996 : : //! \note Only used for cell-centered schemes
997 : : // *****************************************************************************
998 : : {
999 : 108 : m_scheme[meshid].ghosts().nodeNeighSetup();
1000 : 108 : }
1001 : :
1002 : : void
1003 : 191 : Transporter::discinserted( std::size_t meshid )
1004 : : // *****************************************************************************
1005 : : // Reduction target: all Discretization chares have been inserted
1006 : : //! \param[in] meshid Mesh id
1007 : : // *****************************************************************************
1008 : : {
1009 : 191 : m_scheme[meshid].disc().doneInserting();
1010 : 191 : }
1011 : :
1012 : : void
1013 : 210 : Transporter::meshstat( const std::string& header ) const
1014 : : // *****************************************************************************
1015 : : // Print out mesh statistics
1016 : : //! \param[in] header Section header
1017 : : // *****************************************************************************
1018 : : {
1019 : 210 : auto print = printer();
1020 : :
1021 [ + - ]: 210 : print.section( header );
1022 : :
1023 [ + + ]: 210 : if (m_nelem.size() > 1) {
1024 [ + - ][ + - ]: 2 : print.item( "Number of tetrahedra (per mesh)",tk::parameters(m_nelem) );
[ + - ][ - + ]
1025 [ + - ][ + - ]: 2 : print.item( "Number of points (per mesh)", tk::parameters(m_npoin) );
[ + - ][ - + ]
1026 [ + - ][ + - ]: 2 : print.item( "Number of work units (per mesh)", tk::parameters(m_nchare) );
[ + - ][ - + ]
1027 : : }
1028 : :
1029 [ + - ]: 210 : print.item( "Total number of tetrahedra",
1030 [ + - ]: 420 : std::accumulate( begin(m_nelem), end(m_nelem), 0UL ) );
1031 [ + - ]: 210 : print.item( "Total number of points",
1032 [ + - ]: 420 : std::accumulate( begin(m_npoin), end(m_npoin), 0UL ) );
1033 [ + - ]: 210 : print.item( "Total number of work units",
1034 [ + - ][ + - ]: 420 : std::accumulate( begin(m_nchare), end(m_nchare), 0 ) );
1035 : :
1036 : : print.endsubsection();
1037 : 210 : }
1038 : :
1039 : : bool
1040 : 382 : Transporter::need_linearsolver() const
1041 : : // *****************************************************************************
1042 : : // Decide if we need a linear solver for ALE
1043 : : //! \return True if ALE will neeed a linear solver
1044 : : // *****************************************************************************
1045 : : {
1046 : 382 : auto smoother = g_inputdeck.get< tag::ale, tag::smoother >();
1047 : :
1048 [ + + ]: 382 : if ( g_inputdeck.get< tag::ale, tag::ale >() and
1049 [ + + ]: 20 : (smoother == ctr::MeshVelocitySmootherType::LAPLACE ||
1050 : : smoother == ctr::MeshVelocitySmootherType::HELMHOLTZ) )
1051 : : {
1052 : : return true;
1053 : : } else {
1054 : 370 : return false;
1055 : : }
1056 : : }
1057 : :
1058 : : void
1059 : 191 : Transporter::disccreated( std::size_t summeshid, std::size_t npoin )
1060 : : // *****************************************************************************
1061 : : // Reduction target: all Discretization constructors have been called
1062 : : //! \param[in] summeshid Mesh id (summed accross all chares)
1063 : : //! \param[in] npoin Total number of mesh points (summed across all chares)
1064 : : //! Note that as opposed to npoin in refined(), this npoin is not
1065 : : //! multi-counted, and thus should be correct in parallel.
1066 : : // *****************************************************************************
1067 : : {
1068 : 191 : auto meshid = tk::cref_find( m_meshid, summeshid );
1069 : : //std::cout << "Trans: " << meshid << " Transporter::disccreated()\n";
1070 : :
1071 : : // Update number of mesh points for mesh, since it may have been refined
1072 [ + + ]: 191 : if (g_inputdeck.get< tag::amr, tag::t0ref >()) m_npoin[meshid] = npoin;
1073 : :
1074 [ + + ]: 191 : if (++m_ndisc == m_nelem.size()) { // all Disc arrays have been created
1075 : 190 : m_ndisc = 0;
1076 : 190 : auto print = printer();
1077 [ + - ]: 190 : m_progMesh.end( print );
1078 [ + + ]: 190 : if (g_inputdeck.get< tag::amr, tag::t0ref >())
1079 [ + - ][ + - ]: 40 : meshstat( "Initially (t<0) refined mesh graph statistics" );
1080 : : }
1081 : :
1082 : 191 : m_refiner[meshid].sendProxy();
1083 : :
1084 [ + + ]: 191 : if (g_inputdeck.get< tag::ale, tag::ale >())
1085 : 10 : m_scheme[meshid].ale().doneInserting();
1086 : :
1087 [ + + ]: 191 : if (need_linearsolver())
1088 : 6 : m_scheme[meshid].conjugategradients().doneInserting();
1089 : :
1090 : 191 : m_scheme[meshid].disc().vol();
1091 : 191 : }
1092 : :
1093 : : void
1094 : 191 : Transporter::workinserted( std::size_t meshid )
1095 : : // *****************************************************************************
1096 : : // Reduction target: all worker (derived discretization) chares have been
1097 : : // inserted
1098 : : //! \param[in] meshid Mesh id
1099 : : // *****************************************************************************
1100 : : {
1101 : 191 : m_scheme[meshid].bcast< Scheme::doneInserting >();
1102 : 191 : }
1103 : :
1104 : : void
1105 : 190 : Transporter::diagHeader()
1106 : : // *****************************************************************************
1107 : : // Configure and write diagnostics file header
1108 : : // *****************************************************************************
1109 : : {
1110 [ + + ]: 381 : for (std::size_t m=0; m<m_input.size(); ++m) {
1111 : :
1112 : : // Output header for diagnostics output file
1113 [ + + ][ + - ]: 193 : auto mid = m_input.size() > 1 ? std::string( '.' + std::to_string(m) ) : "";
[ - + ][ + - ]
[ - - ]
1114 [ + + ][ - - ]: 191 : tk::DiagWriter dw( g_inputdeck.get< tag::cmd, tag::io, tag::diag >() + mid,
1115 : : g_inputdeck.get< tag::diagnostics, tag::format >(),
1116 [ + - ][ + - ]: 191 : g_inputdeck.get< tag::diagnostics, tag::precision >() );
1117 : :
1118 : : // Collect variables names for integral/diagnostics output
1119 : 191 : std::vector< std::string > var;
1120 : 191 : const auto scheme = g_inputdeck.get< tag::scheme >();
1121 [ + + ]: 191 : if ( scheme == ctr::SchemeType::ALECG ||
1122 : : scheme == ctr::SchemeType::OversetFE )
1123 [ + + ][ + - ]: 168 : for (const auto& eq : g_cgpde) varnames( eq, var );
1124 : 108 : else if ( scheme == ctr::SchemeType::DG ||
1125 : : scheme == ctr::SchemeType::P0P1 ||
1126 : : scheme == ctr::SchemeType::DGP1 ||
1127 [ + + ]: 108 : scheme == ctr::SchemeType::DGP2 ||
1128 : : scheme == ctr::SchemeType::PDG )
1129 [ + + ][ + - ]: 176 : for (const auto& eq : g_dgpde) varnames( eq, var );
1130 [ + - ]: 20 : else if (scheme == ctr::SchemeType::FV)
1131 [ + + ][ + - ]: 40 : for (const auto& eq : g_fvpde) varnames( eq, var );
1132 [ - - ][ - - ]: 0 : else Throw( "Diagnostics header not handled for discretization scheme" );
[ - - ][ - - ]
[ - - ][ - - ]
1133 : :
1134 [ + - ]: 191 : const tk::ctr::Error opt;
1135 : 191 : auto nv = var.size() / m_input.size();
1136 : 191 : std::vector< std::string > d;
1137 : :
1138 : : // Add 'L2(var)' for all variables as those are always computed
1139 : : const auto& l2name = opt.name( tk::ctr::ErrorType::L2 );
1140 [ + + ][ + - ]: 977 : for (std::size_t i=0; i<nv; ++i) d.push_back( l2name + '(' + var[i] + ')' );
[ + - ][ + - ]
[ - + ][ - + ]
[ - - ][ - - ]
1141 : :
1142 : : // Query user-requested diagnostics and augment diagnostics file header by
1143 : : // 'err(var)', where 'err' is the error type configured, and var is the
1144 : : // variable computed, for all variables and all error types configured.
1145 : : const auto& err = g_inputdeck.get< tag::diagnostics, tag::error >();
1146 : 191 : const auto& errname = opt.name( err );
1147 [ + + ]: 977 : for (std::size_t i=0; i<nv; ++i)
1148 [ + - ][ + - ]: 1572 : d.push_back( errname + '(' + var[i] + "-IC)" );
[ + - ][ - + ]
[ - + ][ - - ]
[ - - ]
1149 : :
1150 : : // Augment diagnostics variables by L2-norm of the residual and total energy
1151 : 191 : if ( scheme == ctr::SchemeType::ALECG ||
1152 : 191 : scheme == ctr::SchemeType::OversetFE ||
1153 [ + + ]: 191 : scheme == ctr::SchemeType::FV )
1154 : : {
1155 [ + + ][ + - ]: 544 : for (std::size_t i=0; i<nv; ++i) d.push_back( "L2(d" + var[i] + ')' );
[ + - ][ - + ]
[ - - ]
1156 : : }
1157 [ + - ]: 191 : d.push_back( "mE" );
1158 : :
1159 : : // Write diagnostics header
1160 [ + - ]: 191 : dw.header( d );
1161 : :
1162 : : }
1163 : 190 : }
1164 : :
1165 : : void
1166 : 108 : Transporter::doneInsertingGhosts(std::size_t meshid)
1167 : : // *****************************************************************************
1168 : : // Reduction target indicating all "ghosts" insertions are done
1169 : : //! \param[in] meshid Mesh id
1170 : : // *****************************************************************************
1171 : : {
1172 : 108 : m_scheme[meshid].ghosts().doneInserting();
1173 : 108 : m_scheme[meshid].ghosts().startCommSetup();
1174 : 108 : }
1175 : :
1176 : : void
1177 : 191 : Transporter::comfinal( std::size_t initial, std::size_t summeshid )
1178 : : // *****************************************************************************
1179 : : // Reduction target indicating that communication maps have been setup
1180 : : //! \param[in] initial Sum of contributions from all chares. If larger than
1181 : : //! zero, we are during time stepping and if zero we are during setup.
1182 : : //! \param[in] summeshid Mesh id (summed accross the distributed mesh)
1183 : : // *****************************************************************************
1184 : : // [Discretization-specific communication maps]
1185 : : {
1186 : 191 : auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
1187 : :
1188 [ + - ]: 191 : if (initial > 0) {
1189 : 191 : m_scheme[meshid].bcast< Scheme::setup >();
1190 : : // Turn on automatic load balancing
1191 [ + + ]: 191 : if (++m_ncom == m_nelem.size()) { // all worker arrays have finished
1192 : 190 : m_ncom = 0;
1193 : 190 : auto print = printer();
1194 [ + - ]: 190 : m_progWork.end( print );
1195 [ + - ]: 190 : tk::CProxy_LBSwitch::ckNew();
1196 [ + - ][ + - ]: 380 : print.diag( "Load balancing on (if enabled in Charm++)" );
1197 : : }
1198 : : } else {
1199 : 0 : m_scheme[meshid].bcast< Scheme::lhs >();
1200 : : }
1201 : 191 : }
1202 : : // [Discretization-specific communication maps]
1203 : :
1204 : : void
1205 : 551 : Transporter::totalvol( tk::real v, tk::real initial, tk::real summeshid )
1206 : : // *****************************************************************************
1207 : : // Reduction target summing total mesh volume across all workers
1208 : : //! \param[in] v Mesh volume summed across the distributed mesh
1209 : : //! \param[in] initial Sum of contributions from all chares. If larger than
1210 : : //! zero, we are during setup, if zero, during time stepping.
1211 : : //! \param[in] summeshid Mesh id (summed accross the distributed mesh)
1212 : : // *****************************************************************************
1213 : : {
1214 : 551 : auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
1215 : :
1216 [ + + ]: 551 : m_meshvol[meshid] = v;
1217 : :
1218 [ + + ]: 551 : if (initial > 0.0) // during initialization
1219 : 191 : m_scheme[meshid].disc().stat( v );
1220 : : else // during ALE or AMR
1221 : 360 : m_scheme[meshid].bcast< Scheme::resized >();
1222 : 551 : }
1223 : :
1224 : : void
1225 : 191 : Transporter::minstat( tk::real d0, tk::real d1, tk::real d2, tk::real rmeshid )
1226 : : // *****************************************************************************
1227 : : // Reduction target yielding minimum mesh statistcs across all workers
1228 : : //! \param[in] d0 Minimum mesh statistics collected over all chares
1229 : : //! \param[in] d1 Minimum mesh statistics collected over all chares
1230 : : //! \param[in] d2 Minimum mesh statistics collected over all chares
1231 : : //! \param[in] rmeshid Mesh id as a real
1232 : : // *****************************************************************************
1233 : : {
1234 : 191 : auto meshid = static_cast<std::size_t>(rmeshid);
1235 : :
1236 : 191 : m_minstat[meshid][0] = d0; // minimum edge length
1237 : 191 : m_minstat[meshid][1] = d1; // minimum cell volume cubic root
1238 : 191 : m_minstat[meshid][2] = d2; // minimum number of cells on chare
1239 : :
1240 : 191 : minstat_complete(meshid);
1241 : 191 : }
1242 : :
1243 : : void
1244 : 191 : Transporter::maxstat( tk::real d0, tk::real d1, tk::real d2, tk::real rmeshid )
1245 : : // *****************************************************************************
1246 : : // Reduction target yielding the maximum mesh statistics across all workers
1247 : : //! \param[in] d0 Maximum mesh statistics collected over all chares
1248 : : //! \param[in] d1 Maximum mesh statistics collected over all chares
1249 : : //! \param[in] d2 Maximum mesh statistics collected over all chares
1250 : : //! \param[in] rmeshid Mesh id as a real
1251 : : // *****************************************************************************
1252 : : {
1253 : 191 : auto meshid = static_cast<std::size_t>(rmeshid);
1254 : :
1255 : 191 : m_maxstat[meshid][0] = d0; // maximum edge length
1256 : 191 : m_maxstat[meshid][1] = d1; // maximum cell volume cubic root
1257 : 191 : m_maxstat[meshid][2] = d2; // maximum number of cells on chare
1258 : :
1259 : 191 : maxstat_complete(meshid);
1260 : 191 : }
1261 : :
1262 : : void
1263 : 191 : Transporter::sumstat( tk::real d0, tk::real d1, tk::real d2, tk::real d3,
1264 : : tk::real d4, tk::real d5, tk::real summeshid )
1265 : : // *****************************************************************************
1266 : : // Reduction target yielding the sum mesh statistics across all workers
1267 : : //! \param[in] d0 Sum mesh statistics collected over all chares
1268 : : //! \param[in] d1 Sum mesh statistics collected over all chares
1269 : : //! \param[in] d2 Sum mesh statistics collected over all chares
1270 : : //! \param[in] d3 Sum mesh statistics collected over all chares
1271 : : //! \param[in] d4 Sum mesh statistics collected over all chares
1272 : : //! \param[in] d5 Sum mesh statistics collected over all chares
1273 : : //! \param[in] summeshid Mesh id (summed accross the distributed mesh)
1274 : : // *****************************************************************************
1275 : : {
1276 : 191 : auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
1277 : :
1278 : 191 : m_avgstat[meshid][0] = d1 / d0; // average edge length
1279 : 191 : m_avgstat[meshid][1] = d3 / d2; // average cell volume cubic root
1280 : 191 : m_avgstat[meshid][2] = d5 / d4; // average number of cells per chare
1281 : :
1282 : 191 : sumstat_complete(meshid);
1283 : 191 : }
1284 : :
1285 : : void
1286 [ + - ]: 191 : Transporter::pdfstat( CkReductionMsg* msg )
1287 : : // *****************************************************************************
1288 : : // Reduction target yielding PDF of mesh statistics across all workers
1289 : : //! \param[in] msg Serialized PDF
1290 : : // *****************************************************************************
1291 : : {
1292 : : std::size_t meshid;
1293 : 191 : std::vector< tk::UniPDF > pdf;
1294 : :
1295 : : // Deserialize final PDF
1296 [ + - ]: 191 : PUP::fromMem creator( msg->getData() );
1297 : : creator | meshid;
1298 : : creator | pdf;
1299 : : delete msg;
1300 : :
1301 [ + - ]: 191 : auto id = std::to_string(meshid);
1302 : :
1303 : : // Create new PDF file (overwrite if exists)
1304 [ + - ][ + - ]: 382 : tk::PDFWriter pdfe( "mesh_edge_pdf." + id + ".txt" );
[ + - ][ - + ]
[ - - ][ - - ]
1305 : : // Output edgelength PDF
1306 : : // cppcheck-suppress containerOutOfBounds
1307 : 191 : pdfe.writeTxt( pdf[0],
1308 [ + - ][ + - ]: 573 : tk::ctr::PDFInfo{ {"PDF"}, {}, {"edgelength"}, 0, 0.0 } );
[ + - ][ + - ]
[ + + ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1309 : :
1310 : : // Create new PDF file (overwrite if exists)
1311 [ + - ][ + - ]: 382 : tk::PDFWriter pdfv( "mesh_vol_pdf." + id + ".txt" );
[ + - ][ - + ]
[ - - ]
1312 : : // Output cell volume cubic root PDF
1313 : 191 : pdfv.writeTxt( pdf[1],
1314 [ + - ][ + - ]: 573 : tk::ctr::PDFInfo{ {"PDF"}, {}, {"V^{1/3}"}, 0, 0.0 } );
[ + - ][ + - ]
[ + + ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1315 : :
1316 : : // Create new PDF file (overwrite if exists)
1317 [ + - ][ + - ]: 382 : tk::PDFWriter pdfn( "mesh_ntet_pdf." + id + ".txt" );
[ + - ][ - + ]
[ - - ]
1318 : : // Output number of cells PDF
1319 : 191 : pdfn.writeTxt( pdf[2],
1320 [ + - ][ + - ]: 573 : tk::ctr::PDFInfo{ {"PDF"}, {}, {"ntets"}, 0, 0.0 } );
[ + - ][ + - ]
[ + + ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1321 : :
1322 [ + - ]: 191 : pdfstat_complete(meshid);
1323 : 191 : }
1324 : :
1325 : : void
1326 : 191 : Transporter::stat()
1327 : : // *****************************************************************************
1328 : : // Echo diagnostics on mesh statistics
1329 : : // *****************************************************************************
1330 : : {
1331 : 191 : auto print = printer();
1332 : :
1333 [ + + ]: 191 : if (++m_nstat == m_nelem.size()) { // stats from all meshes have arrived
1334 : 190 : m_nstat = 0;
1335 [ + + ]: 381 : for (std::size_t i=0; i<m_nelem.size(); ++i) {
1336 [ + - ]: 191 : print.diag(
1337 [ + - ][ + - ]: 382 : "Mesh " + std::to_string(i) +
[ - + ][ - + ]
[ - + ][ - - ]
[ - - ][ - - ]
1338 [ + - ][ - + ]: 382 : " distribution statistics: min/max/avg(edgelength) = " +
[ - - ]
1339 [ + - ][ + - ]: 764 : std::to_string( m_minstat[i][0] ) + " / " +
[ + - ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1340 [ + - ][ + - ]: 764 : std::to_string( m_maxstat[i][0] ) + " / " +
[ + - ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1341 [ + - ][ + - ]: 764 : std::to_string( m_avgstat[i][0] ) + ", " +
[ + - ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1342 [ + - ][ - + ]: 382 : "min/max/avg(V^{1/3}) = " +
[ - - ]
1343 [ + - ][ + - ]: 764 : std::to_string( m_minstat[i][1] ) + " / " +
[ + - ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1344 [ + - ][ + - ]: 764 : std::to_string( m_maxstat[i][1] ) + " / " +
[ + - ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1345 [ + - ][ + - ]: 764 : std::to_string( m_avgstat[i][1] ) + ", " +
[ + - ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1346 [ + - ][ - + ]: 382 : "min/max/avg(ntets) = " +
[ - - ]
1347 [ + - ][ + - ]: 764 : std::to_string( static_cast<std::size_t>(m_minstat[i][2]) ) + " / " +
[ + - ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1348 [ + - ][ + - ]: 764 : std::to_string( static_cast<std::size_t>(m_maxstat[i][2]) ) + " / " +
[ + - ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
1349 [ + - ]: 382 : std::to_string( static_cast<std::size_t>(m_avgstat[i][2]) ) );
1350 : : }
1351 : :
1352 : : // Print out time integration header to screen
1353 [ + - ]: 190 : inthead( print );
1354 : :
1355 : 190 : m_progWork.start( print, "Preparing workers",
1356 [ + - ]: 190 : {{ m_nchare[0], m_nchare[0], m_nchare[0], m_nchare[0], m_nchare[0] }} );
1357 : :
1358 : : // Create "derived-class" workers
1359 [ + + ][ + - ]: 381 : for (std::size_t i=0; i<m_nelem.size(); ++i) m_sorter[i].createWorkers();
1360 : : }
1361 : 191 : }
1362 : :
1363 : : void
1364 : 191 : Transporter::boxvol( tk::real* meshdata, int n )
1365 : : // *****************************************************************************
1366 : : // Reduction target computing total volume of IC mesh blocks and box
1367 : : //! \param[in] meshdata Vector containing volumes of all IC mesh blocks,
1368 : : //! volume of IC box, and mesh id as a real summed across the distributed mesh
1369 : : //! \param[in] n Size of vector, automatically computed by Charm
1370 : : // *****************************************************************************
1371 : : {
1372 : : Assert(n>=2, "mesh data size incorrect");
1373 : :
1374 : : // extract summed mesh id from vector
1375 : 191 : tk::real summeshid = meshdata[n-1];
1376 : 191 : auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
1377 : :
1378 : : // extract summed box volume from vector
1379 : 191 : tk::real v = meshdata[n-2];
1380 [ + + ][ + - ]: 193 : if (v > 0.0) printer().diag( "Box IC volume: " + std::to_string(v) );
[ + - ][ + - ]
[ - + ][ - - ]
1381 : :
1382 : : // extract summed mesh block volumes from the vector
1383 : : std::vector< tk::real > blockvols;
1384 [ - + ]: 191 : for (std::size_t blid=0; blid<(static_cast<std::size_t>(n)-2); ++blid) {
1385 [ - - ]: 0 : blockvols.push_back(meshdata[blid]);
1386 [ - - ]: 0 : if (blockvols[blid] > 0.0)
1387 [ - - ][ - - ]: 0 : printer().diag( "Mesh block " + std::to_string(blid) +
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ]
1388 [ - - ][ - - ]: 0 : " discrete volume: " + std::to_string(blockvols[blid]) );
[ - - ][ - - ]
1389 : : }
1390 : :
1391 [ + - ]: 191 : m_scheme[meshid].bcast< Scheme::box >( v, blockvols );
1392 : 191 : }
1393 : :
1394 : : void
1395 : 8 : Transporter::solutionTransferred()
1396 : : // *****************************************************************************
1397 : : // Reduction target broadcasting to Schemes after mesh transfer
1398 : : // *****************************************************************************
1399 : : {
1400 [ + + ]: 8 : if (++m_ntrans == m_nelem.size()) { // all meshes have been loaded
1401 : 4 : m_ntrans = 0;
1402 [ + + ]: 12 : for (auto& m : m_scheme) m.bcast< Scheme::transferSol >();
1403 : : }
1404 : 8 : }
1405 : :
1406 : : void
1407 : 252 : Transporter::collectDtAndForces( CkReductionMsg* advMsg )
1408 : : // *****************************************************************************
1409 : : // \brief Reduction target that computes minimum timestep across all meshes and
1410 : : // sums up the forces on each mesh
1411 : : //! \param[in] advMsg Reduction msg containing minimum timestep and total
1412 : : //! surface force information
1413 : : // *****************************************************************************
1414 : : {
1415 : : // obtain results of reduction from reduction-msg
1416 : 252 : CkReduction::tupleElement* results = nullptr;
1417 : 252 : int num_reductions = 0;
1418 : 252 : advMsg->toTuple(&results, &num_reductions);
1419 : :
1420 : : // ignore the old-style-cast warning from clang for this code
1421 : : #if defined(__clang__)
1422 : : #pragma clang diagnostic push
1423 : : #pragma clang diagnostic ignored "-Wold-style-cast"
1424 : : #pragma clang diagnostic ignored "-Wcast-align"
1425 : : #endif
1426 : :
1427 : 252 : tk::real mindt = *(tk::real*)results[0].data;
1428 : : std::array< tk::real, 6 > F;
1429 : 252 : F[0] = *(tk::real*)results[1].data;
1430 : 252 : F[1] = *(tk::real*)results[2].data;
1431 : 252 : F[2] = *(tk::real*)results[3].data;
1432 : 252 : F[3] = *(tk::real*)results[4].data;
1433 : 252 : F[4] = *(tk::real*)results[5].data;
1434 : 252 : F[5] = *(tk::real*)results[6].data;
1435 : :
1436 : : #if defined(__clang__)
1437 : : #pragma clang diagnostic pop
1438 : : #endif
1439 : :
1440 : 252 : m_dtmsh.push_back(mindt);
1441 : :
1442 [ + + ]: 252 : if (++m_ndtmsh == m_nelem.size()) { // all meshes have been loaded
1443 : : Assert(m_dtmsh.size() == m_nelem.size(), "Incorrect size of dtmsh");
1444 : :
1445 : : // compute minimum dt across meshes
1446 : 251 : tk::real dt = std::numeric_limits< tk::real >::max();
1447 [ + + ][ + - ]: 503 : for (auto idt : m_dtmsh) dt = std::min(dt, idt);
1448 : :
1449 : : // clear dt-vector and counter
1450 : : m_dtmsh.clear();
1451 : 251 : m_ndtmsh = 0;
1452 : :
1453 : : // broadcast to advance time step
1454 [ + + ]: 503 : for (auto& m : m_scheme) {
1455 : : m.bcast< Scheme::advance >( dt, F );
1456 : : }
1457 : : }
1458 : 252 : }
1459 : :
1460 : : void
1461 : 192 : Transporter::inthead( const InciterPrint& print )
1462 : : // *****************************************************************************
1463 : : // Print out time integration header to screen
1464 : : //! \param[in] print Pretty printer object to use for printing
1465 : : // *****************************************************************************
1466 : : {
1467 : 192 : auto refined = g_inputdeck.get< tag::field_output, tag::refined >();
1468 : 192 : const auto scheme = g_inputdeck.get< tag::scheme >();
1469 [ - + ]: 192 : if (refined && scheme == ctr::SchemeType::DG) {
1470 : 0 : printer() << "\n>>> WARNING: Ignoring refined field output for DG(P0)\n\n";
1471 : : refined = false;
1472 : : }
1473 : :
1474 [ + - ][ + - ]: 768 : print.inthead( "Time integration", "Euler/Navier-Stokes solver",
[ + - ][ + - ]
[ + - ][ + - ]
1475 : : "Legend: it - iteration count\n"
1476 : : " t - physics time\n"
1477 : : " dt - physics time step size\n"
1478 : : " ETE - estimated wall-clock time elapsed (h:m:s)\n"
1479 : : " ETA - estimated wall-clock time for accomplishment (h:m:s)\n"
1480 : : " EGT - estimated grind wall-clock time (ms/timestep)\n"
1481 : : " flg - status flags, legend:\n"
1482 [ + + ][ + - ]: 573 : " f - " + std::string(refined ? "refined " : "")
[ + - ][ - + ]
[ + - ][ - - ]
1483 [ + - ][ - + ]: 384 : + "field (volume and surface)\n"
[ - - ]
1484 : : " d - diagnostics\n"
1485 : : " t - physics time history\n"
1486 : : " h - h-refinement\n"
1487 : : " l - load balancing\n"
1488 : : " r - checkpoint\n"
1489 : : " a - ALE mesh velocity linear solver did not converge\n",
1490 : : "\n it t dt ETE ETA EGT flg\n"
1491 : : " -------------------------------------------------------------------------\n" );
1492 : 192 : }
1493 : :
1494 : : void
1495 [ + - ]: 3226 : Transporter::diagnostics( CkReductionMsg* msg )
1496 : : // *****************************************************************************
1497 : : // Reduction target optionally collecting diagnostics, e.g., residuals
1498 : : //! \param[in] msg Serialized diagnostics vector aggregated across all PEs
1499 : : //! \note Only used for nodal schemes
1500 : : // *****************************************************************************
1501 : : {
1502 : : std::size_t meshid, ncomp;
1503 : 3226 : std::vector< std::vector< tk::real > > d;
1504 : :
1505 : : // Deserialize diagnostics vector
1506 [ + - ]: 3226 : PUP::fromMem creator( msg->getData() );
1507 : : creator | meshid;
1508 : : creator | ncomp;
1509 : : creator | d;
1510 : : delete msg;
1511 : :
1512 [ + - ]: 3226 : auto id = std::to_string(meshid);
1513 : :
1514 : : Assert( ncomp > 0, "Number of scalar components must be positive");
1515 : : Assert( d.size() == NUMDIAG, "Diagnostics vector size mismatch" );
1516 : :
1517 [ + + ]: 29034 : for (std::size_t i=0; i<d.size(); ++i)
1518 : : Assert( d[i].size() == ncomp, "Size mismatch at final stage of "
1519 : : "diagnostics aggregation for mesh " + id );
1520 : :
1521 : : // Allocate storage for those diagnostics that are always computed
1522 [ + - ][ - - ]: 3226 : std::vector< tk::real > diag( ncomp, 0.0 );
1523 : :
1524 : : // Finish computing diagnostics
1525 [ + + ]: 17563 : for (std::size_t i=0; i<d[L2SOL].size(); ++i)
1526 : 14337 : diag[i] = sqrt( d[L2SOL][i] / m_meshvol[meshid] );
1527 : :
1528 : : // Query user-requested error types to output
1529 : : const auto& error = g_inputdeck.get< tag::diagnostics, tag::error >();
1530 : :
1531 : : decltype(ncomp) n = 0;
1532 : : n += ncomp;
1533 [ + + ]: 3226 : if (error == tk::ctr::ErrorType::L2) {
1534 : : // Finish computing the L2 norm of the numerical - analytical solution
1535 [ + + ]: 17539 : for (std::size_t i=0; i<d[L2ERR].size(); ++i)
1536 [ + - ]: 14325 : diag.push_back( sqrt( d[L2ERR][i] / m_meshvol[meshid] ) );
1537 [ + - ]: 12 : } else if (error == tk::ctr::ErrorType::LINF) {
1538 : : // Finish computing the Linf norm of the numerical - analytical solution
1539 [ + + ]: 24 : for (std::size_t i=0; i<d[LINFERR].size(); ++i)
1540 [ + - ]: 12 : diag.push_back( d[LINFERR][i] );
1541 : : }
1542 : :
1543 : : // Finish computing the L2 norm of the residual and append
1544 : 3226 : const auto scheme = g_inputdeck.get< tag::scheme >();
1545 [ + - ][ - - ]: 3226 : std::vector< tk::real > l2res( d[L2RES].size(), 0.0 );
1546 [ + + ]: 3226 : if (scheme == ctr::SchemeType::ALECG || scheme == ctr::SchemeType::OversetFE) {
1547 [ + + ]: 5920 : for (std::size_t i=0; i<d[L2RES].size(); ++i) {
1548 : 4534 : l2res[i] = std::sqrt( d[L2RES][i] / m_meshvol[meshid] );
1549 [ + - ]: 4534 : diag.push_back( l2res[i] );
1550 : : }
1551 : : }
1552 [ + + ]: 1840 : else if (scheme == ctr::SchemeType::FV) {
1553 [ + + ]: 968 : for (std::size_t i=0; i<d[L2RES].size(); ++i) {
1554 : 882 : l2res[i] = std::sqrt( d[L2RES][i] );
1555 [ + - ]: 882 : diag.push_back( l2res[i] );
1556 : : }
1557 : : }
1558 : :
1559 : : // Append total energy
1560 [ + - ]: 3226 : diag.push_back( d[TOTALSOL][0] );
1561 : :
1562 : : // Append diagnostics file at selected times
1563 : : auto filename = g_inputdeck.get< tag::cmd, tag::io, tag::diag >();
1564 [ + + ][ + - ]: 3228 : if (m_nelem.size() > 1) filename += '.' + id;
[ - - ]
1565 : : tk::DiagWriter dw( filename,
1566 : : g_inputdeck.get< tag::diagnostics, tag::format >(),
1567 : : g_inputdeck.get< tag::diagnostics, tag::precision >(),
1568 [ + - ]: 3226 : std::ios_base::app );
1569 [ + - ]: 3226 : dw.diag( static_cast<uint64_t>(d[ITER][0]), d[TIME][0], d[DT][0], diag );
1570 : :
1571 : : // Continue time step
1572 [ + - ]: 3226 : m_scheme[meshid].bcast< Scheme::refine >( l2res );
1573 : 3226 : }
1574 : :
1575 : : void
1576 : 194 : Transporter::resume()
1577 : : // *****************************************************************************
1578 : : // Resume execution from checkpoint/restart files
1579 : : //! \details This is invoked by Charm++ after the checkpoint is done, as well as
1580 : : //! when the restart (returning from a checkpoint) is complete
1581 : : // *****************************************************************************
1582 : : {
1583 [ + + ]: 194 : if (std::any_of(begin(m_finished), end(m_finished), [](auto f){return !f;})) {
1584 : : // If just restarted from a checkpoint, Main( CkMigrateMessage* msg ) has
1585 : : // increased nrestart in g_inputdeck, but only on PE 0, so broadcast.
1586 : 2 : auto nrestart = g_inputdeck.get< tag::cmd, tag::io, tag::nrestart >();
1587 [ + + ]: 4 : for (std::size_t i=0; i<m_nelem.size(); ++i)
1588 : 2 : m_scheme[i].bcast< Scheme::evalLB >( nrestart );
1589 : : } else
1590 : 192 : mainProxy.finalize();
1591 : 194 : }
1592 : :
1593 : : void
1594 : 193 : Transporter::checkpoint( std::size_t finished, std::size_t meshid )
1595 : : // *****************************************************************************
1596 : : // Save checkpoint/restart files
1597 : : //! \param[in] finished Nonzero if finished with time stepping
1598 : : //! \param[in] meshid Mesh id
1599 : : // *****************************************************************************
1600 : : {
1601 [ + + ]: 193 : m_finished[meshid] = finished;
1602 : :
1603 [ + + ]: 193 : if (++m_nchk == m_nelem.size()) { // all worker arrays have checkpointed
1604 : 192 : m_nchk = 0;
1605 [ + + ]: 192 : if (not g_inputdeck.get< tag::cmd, tag::benchmark >()) {
1606 : : const auto& restart = g_inputdeck.get< tag::cmd, tag::io, tag::restart >();
1607 : 120 : CkCallback res( CkIndex_Transporter::resume(), thisProxy );
1608 [ + - ]: 120 : CkStartCheckpoint( restart.c_str(), res );
1609 : : } else {
1610 : 72 : resume();
1611 : : }
1612 : : }
1613 : 193 : }
1614 : :
1615 : : void
1616 : 193 : Transporter::finish( std::size_t meshid )
1617 : : // *****************************************************************************
1618 : : // Normal finish of time stepping
1619 : : //! \param[in] meshid Mesh id
1620 : : // *****************************************************************************
1621 : : {
1622 : 193 : checkpoint( /* finished = */ 1, meshid );
1623 : 193 : }
1624 : :
1625 : : #include "NoWarning/transporter.def.h"
|