Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Walker/Distributor.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 Distributor drives the time integration of differential equations
9 : : \details Distributor drives the time integration of differential 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/Walker/distributor.ci.
15 : : */
16 : : // *****************************************************************************
17 : :
18 : : #include <list>
19 : : #include <string>
20 : : #include <algorithm>
21 : : #include <functional>
22 : : #include <iomanip>
23 : : #include <iostream>
24 : : #include <iterator>
25 : : #include <limits>
26 : : #include <cmath>
27 : : #include <cstddef>
28 : :
29 : : #include "NoWarning/format.hpp"
30 : :
31 : : #include "Macro.hpp"
32 : : #include "Print.hpp"
33 : : #include "Tags.hpp"
34 : : #include "StatCtr.hpp"
35 : : #include "Exception.hpp"
36 : : #include "Particles.hpp"
37 : : #include "LoadDistributor.hpp"
38 : : #include "Distributor.hpp"
39 : : #include "Integrator.hpp"
40 : : #include "DiffEqStack.hpp"
41 : : #include "TxtStatWriter.hpp"
42 : : #include "PDFReducer.hpp"
43 : : #include "PDFWriter.hpp"
44 : : #include "Options/PDFFile.hpp"
45 : : #include "Options/PDFPolicy.hpp"
46 : : #include "Walker/InputDeck/InputDeck.hpp"
47 : : #include "NoWarning/walker.decl.h"
48 : :
49 : : extern CProxy_Main mainProxy;
50 : :
51 : : using walker::Distributor;
52 : :
53 : 93 : Distributor::Distributor() :
54 : : m_output( { false, false } ),
55 : : m_it( 0 ),
56 : : m_npar( 0 ),
57 : : m_t( 0.0 ),
58 [ + - ]: 93 : m_dt( computedt() ),
59 : : m_intproxy(),
60 : : m_timer(),
61 [ + - ][ - - ]: 93 : m_nameOrdinary( g_inputdeck.momentNames( tk::ctr::ordinary ) ),
62 : 93 : m_nameCentral( g_inputdeck.momentNames( tk::ctr::central ) ),
63 [ + - ]: 93 : m_ordinary( m_nameOrdinary.size(), 0.0 ),
64 [ + - ][ - - ]: 93 : m_central( m_nameCentral.size(), 0.0 ),
65 : : m_ordupdf(),
66 : : m_ordbpdf(),
67 : : m_ordtpdf(),
68 : : m_cenupdf(),
69 : : m_cenbpdf(),
70 : : m_centpdf(),
71 : : m_tables(),
72 [ + - ][ + - ]: 279 : m_moments()
[ + - ][ + - ]
[ + - ][ + - ]
73 : : // *****************************************************************************
74 : : // Constructor
75 : : // *****************************************************************************
76 : : {
77 : : // Get command line object reference
78 : : const auto& cmd = g_inputdeck.get< tag::cmd >();
79 : :
80 : : // Compute load distribution given total work (= number of particles) and
81 : : // user-specified virtualization
82 [ + - ]: 93 : uint64_t chunksize = 0, remainder = 0;
83 [ + - ]: 93 : auto nchare = tk::linearLoadDistributor(
84 : : cmd.get< tag::virtualization >(),
85 : : g_inputdeck.get< tag::discr, tag::npar >(),
86 : : CkNumPes(),
87 : : chunksize,
88 : : remainder );
89 : : Assert( chunksize != 0, "Chunksize must not be zero" );
90 : :
91 : : // Compute total number of particles distributed over all workers. Note that
92 : : // this number will not necessarily be the same as given by the user, coming
93 : : // from g_inputdeck.get< tag::discr, tag::npar >(), since each Charm++ chare
94 : : // array element constructor takes this chunksize argument, which equals the
95 : : // number of particles the array element (worker) will work on.
96 : 93 : m_npar = static_cast< tk::real >( nchare * chunksize );
97 : :
98 [ + - ]: 93 : auto print = printer();
99 : :
100 : : // Print out info on what will be done and how
101 [ + - ]: 93 : info( print, chunksize, nchare );
102 : :
103 : : // Output header for statistics output file
104 [ + + ][ - + ]: 93 : tk::TxtStatWriter sw( !m_nameOrdinary.empty() || !m_nameCentral.empty() ?
105 : : cmd.get< tag::io, tag::stat >() :
106 : : std::string(),
107 : : g_inputdeck.get< tag::flformat, tag::stat >(),
108 [ + + ][ + - ]: 186 : g_inputdeck.get< tag::prec, tag::stat >() );
109 [ + - ]: 93 : sw.header( m_nameOrdinary, m_nameCentral, m_tables.first );
110 : :
111 : : // Print out time integration header
112 : : print.endsubsection();
113 [ + - ][ + - ]: 186 : print.diag( "Starting time stepping ..." );
[ + - ]
114 [ + - ]: 93 : header( print );
115 : :
116 : : // Start timer measuring total integration time
117 [ + - ]: 93 : m_timer.emplace_back();
118 : :
119 : : // Construct and initialize map of statistical moments
120 [ + + ]: 1434 : for (const auto& product : g_inputdeck.get< tag::stat >())
121 [ + - ]: 1341 : m_moments[ product ] = 0.0;
122 : :
123 : : // Activate SDAG-wait for estimation of ordinary statistics
124 [ + - ]: 93 : thisProxy.wait4ord();
125 : : // Activate SDAG-wait for estimation of PDFs at select times
126 [ + - ]: 93 : thisProxy.wait4pdf();
127 : :
128 : : // Create statistics merger chare group collecting chare contributions
129 [ + - ]: 93 : CProxy_Collector collproxy = CProxy_Collector::ckNew( thisProxy );
130 : :
131 : : // Create partcle writer Charm++ chare nodegroup
132 : : tk::CProxy_ParticleWriter particlewriter =
133 [ + - ]: 93 : tk::CProxy_ParticleWriter::ckNew( cmd.get< tag::io, tag::particles >() );
134 : :
135 : : // Fire up asynchronous differential equation integrators
136 : : m_intproxy =
137 : 93 : CProxy_Integrator::ckNew( thisProxy, collproxy, particlewriter, chunksize,
138 [ + - ][ - + ]: 186 : static_cast<int>( nchare ) );
[ - - ]
139 : 93 : }
140 : :
141 : : void
142 : 93 : Distributor::info( const WalkerPrint& print,
143 : : uint64_t chunksize,
144 : : std::size_t nchare )
145 : : // *****************************************************************************
146 : : // Print information at startup
147 : : //! \param[in] print Pretty printer object to use for printing
148 : : //! \param[in] chunksize Chunk size, see Base/LoadDistribution.h
149 : : //! \param[in] nchare Total number of Charem++ Integrator chares doing work
150 : : // *****************************************************************************
151 : : {
152 : : // Get command line object reference
153 : : const auto& cmd = g_inputdeck.get< tag::cmd >();
154 : :
155 [ + - ]: 186 : print.part( "Factory" );
156 : :
157 : : // Print out info data layout
158 [ + - ]: 93 : print.list( "Particle properties data layout (CMake: PARTICLE_DATA_LAYOUT)",
159 [ + - ][ + - ]: 279 : std::list< std::string >{ tk::Particles::layout() } );
[ + + ][ - + ]
[ - - ][ - - ]
160 : :
161 : : // Re-create differential equations stack for output
162 : 93 : DiffEqStack stack;
163 : :
164 : : // Print out information on factory
165 [ + - ]: 93 : print.eqlist( "Registered differential equations",
166 [ + - ][ + - ]: 186 : stack.factory(), stack.ntypes() );
167 : : print.endpart();
168 : :
169 : : // Instantiate tables to sample and output to statistics file
170 [ + - ]: 93 : m_tables = stack.tables();
171 : :
172 : : // Print out information on problem
173 [ + - ][ + - ]: 186 : print.part( "Problem" );
[ + - ]
174 : :
175 : : // Print out info on problem title
176 [ + - ]: 93 : if ( !g_inputdeck.get< tag::title >().empty() )
177 [ + - ]: 93 : print.title( g_inputdeck.get< tag::title >() );
178 : :
179 : : // Print out info on settings of selected differential equations
180 [ + - ][ + - ]: 186 : print.diffeqs( "Differential equations integrated", stack.info() );
[ + - ]
181 : :
182 : : // Print out info on RNGs selected
183 : : // ...
184 : :
185 : : // Print I/O filenames
186 [ + - ][ + - ]: 186 : print.section( "Output filenames" );
[ + + ]
187 [ + + ]: 93 : if (!g_inputdeck.get< tag::stat >().empty())
188 [ + - ][ + - ]: 180 : print.item( "Statistics", cmd.get< tag::io, tag::stat >() );
189 [ + + ]: 93 : if (!g_inputdeck.get< tag::pdf >().empty())
190 [ + - ][ + - ]: 32 : print.item( "PDF", cmd.get< tag::io, tag::pdf >() );
191 [ + + ]: 93 : if (!g_inputdeck.get< tag::param, tag::position, tag::depvar >().empty())
192 [ + - ][ + - ]: 12 : print.item( "Particle positions", cmd.get< tag::io, tag::particles >() );
193 : :
194 : : // Print discretization parameters
195 [ + - ][ + - ]: 186 : print.section( "Discretization parameters" );
[ + - ]
196 [ + - ]: 93 : print.item( "Number of time steps",
197 [ + - ][ + - ]: 186 : g_inputdeck.get< tag::discr, tag::nstep >() );
198 [ + - ]: 93 : print.item( "Terminate time",
199 [ + - ][ + - ]: 186 : g_inputdeck.get< tag::discr, tag::term >() );
200 [ + - ]: 93 : print.item( "Initial time step size",
201 [ + - ][ + - ]: 186 : g_inputdeck.get< tag::discr, tag::dt >() );
202 : :
203 : : // Print output intervals
204 [ + - ][ + - ]: 186 : print.section( "Output intervals" );
[ + - ]
205 : : const auto& interval = g_inputdeck.get< tag::output, tag::iter >();
206 [ + - ][ + - ]: 186 : print.item( "TTY", interval.get< tag::tty >() );
[ + + ]
207 [ + + ]: 93 : if (!g_inputdeck.get< tag::stat >().empty())
208 [ + - ][ + - ]: 180 : print.item( "Statistics", interval.get< tag::stat >() );
209 [ + + ]: 93 : if (!g_inputdeck.get< tag::pdf >().empty())
210 [ + - ][ + - ]: 32 : print.item( "PDF", interval.get< tag::pdf >() );
211 [ + + ]: 93 : if (!g_inputdeck.get< tag::param, tag::position, tag::depvar >().empty())
212 [ + - ][ + - ]: 12 : print.item( "Particles", interval.get< tag::particles >() );
213 : :
214 : : // Print out statistics estimated
215 [ + - ][ + - ]: 186 : print.statistics( "Statistical moments and distributions" );
[ + - ]
216 : :
217 : : // Print out info on load distirubtion
218 [ + - ][ + - ]: 186 : print.section( "Load distribution" );
[ + - ]
219 [ + - ]: 93 : print.item( "Virtualization [0.0...1.0]",
220 [ + - ][ + - ]: 186 : g_inputdeck.get< tag::cmd, tag::virtualization >() );
221 [ + - ][ + - ]: 186 : print.item( "Number of work units", nchare );
[ + - ]
222 [ + - ]: 93 : print.item( "User load (# of particles)",
223 [ + - ][ + - ]: 186 : g_inputdeck.get< tag::discr, tag::npar >() );
224 [ + - ][ + - ]: 186 : print.item( "Chunksize (load per work unit)", chunksize );
[ + - ]
225 [ + - ]: 93 : print.item( "Actual load (# of particles)",
226 [ + - ][ - + ]: 186 : std::to_string( nchare * chunksize ) +
[ - + ][ - - ]
[ - - ]
227 [ + - ][ - + ]: 186 : " (=" +
[ - - ]
228 [ + - ][ + - ]: 372 : std::to_string( nchare ) + "*" +
[ + - ][ - + ]
[ - + ][ - + ]
[ - - ][ - - ]
[ - - ]
229 [ + - ][ + - ]: 394 : std::to_string( chunksize ) + ")" );
[ + - ][ + - ]
[ + + ][ - + ]
[ - - ][ - - ]
230 : 93 : }
231 : :
232 : : tk::real
233 : 520624 : Distributor::computedt()
234 : : // *****************************************************************************
235 : : // Compute size of next time step
236 : : //! \return Size of dt for the next time step
237 : : // *****************************************************************************
238 : : {
239 : : // Simply return a constant user-defined dt for now
240 : 520624 : return g_inputdeck.get< tag::discr, tag::dt >();
241 : : }
242 : :
243 : : void
244 : 520531 : Distributor::estimateOrd( tk::real* ord, [[maybe_unused]] int n )
245 : : // *****************************************************************************
246 : : // Estimate ordinary moments
247 : : //! \param[in] ord Ordinary moments (sum) collected over all chares
248 : : //! \param[in] n Number of ordinary moments in array ord
249 : : // *****************************************************************************
250 : : {
251 : : Assert( static_cast<std::size_t>(n) == m_ordinary.size(),
252 : : "Number of ordinary moments contributed not equal to expected" );
253 : :
254 : : // Add contribution from PE to total sums, i.e., u[i] += v[i] for all i
255 [ + + ]: 3003634 : for (std::size_t i=0; i<m_ordinary.size(); ++i) m_ordinary[i] += ord[i];
256 : :
257 : : // Finish computing moments, i.e., divide sums by the number of samples
258 : : // cppcheck-suppress useStlAlgorithm
259 [ + + ]: 3003634 : for (auto& m : m_ordinary) m /= m_npar;
260 : :
261 : : // Activate SDAG trigger signaling that ordinary moments have been estimated
262 : 520531 : estimateOrdDone();
263 : 520531 : }
264 : :
265 : : void
266 : 520531 : Distributor::estimateCen( tk::real* cen, [[maybe_unused]] int n )
267 : : // *****************************************************************************
268 : : // Estimate ordinary moments
269 : : //! \param[in] cen Central moments (sum) collected over all chares
270 : : //! \param[in] n Number of central moments in array cen
271 : : // *****************************************************************************
272 : : {
273 : : Assert( static_cast<std::size_t>(n) == m_central.size(),
274 : : "Number of central moments contributed not equal to expected" );
275 : :
276 : : // Add contribution from PE to total sums, i.e., u[i] += v[i] for all i
277 [ + + ]: 5309645 : for (std::size_t i=0; i<m_central.size(); ++i) m_central[i] += cen[i];
278 : :
279 : : // Finish computing moments, i.e., divide sums by the number of samples
280 : : // cppcheck-suppress useStlAlgorithm
281 [ + + ]: 5309645 : for (auto& m : m_central) m /= m_npar;
282 : :
283 : : // Activate SDAG trigger signaling that central moments have been estimated
284 : 520531 : estimateCenDone();
285 : 520531 : }
286 : :
287 : : void
288 [ + - ]: 520531 : Distributor::estimateOrdPDF( CkReductionMsg* msg )
289 : : // *****************************************************************************
290 : : // Estimate ordinary PDFs
291 : : //! \param[in] msg Serialized vectors of uni-, bi-, and tri-variate PDFs
292 : : // *****************************************************************************
293 : : {
294 : : // Deserialize final PDFs
295 : : PUP::fromMem creator( msg->getData() );
296 [ + - ]: 520531 : creator | m_ordupdf;
297 [ + - ]: 520531 : creator | m_ordbpdf;
298 [ + - ]: 520531 : creator | m_ordtpdf;
299 : :
300 : : delete msg;
301 : :
302 : : // Activate SDAG trigger signaling that ordinary PDFs have been estimated
303 [ + - ]: 520531 : estimateOrdPDFDone();
304 : 520531 : }
305 : :
306 : : void
307 [ + - ]: 520531 : Distributor::estimateCenPDF( CkReductionMsg* msg )
308 : : // *****************************************************************************
309 : : // Estimate central PDFs
310 : : //! \param[in] msg Serialized vectors of uni-, bi-, and tri-variate PDFs
311 : : // *****************************************************************************
312 : : {
313 : : // Deserialize final PDFs
314 : : PUP::fromMem creator( msg->getData() );
315 [ + - ]: 520531 : creator | m_cenupdf;
316 [ + - ]: 520531 : creator | m_cenbpdf;
317 [ + - ]: 520531 : creator | m_centpdf;
318 : :
319 : : delete msg;
320 : :
321 : : // Activate SDAG trigger signaling that central PDFs have been estimated
322 [ + - ]: 520531 : estimateCenPDFDone();
323 : 520531 : }
324 : :
325 : : void
326 : 520531 : Distributor::outStat()
327 : : // *****************************************************************************
328 : : // Output statistics to file
329 : : // *****************************************************************************
330 : : {
331 : : // lambda to sample tables to write to statistics file
332 : 398499 : auto extra = [this]() -> std::vector< tk::real > {
333 : 398499 : std::vector< tk::real > x( m_tables.second.size() );
334 : : std::size_t j = 0;
335 [ + + ]: 398599 : for (const auto& t : m_tables.second) x[ j++ ] = tk::sample<1>(m_t,t)[0];
336 : 398499 : return x;
337 : 520531 : };
338 : :
339 : : // Append statistics file at selected times
340 [ + + ]: 520531 : if (!((m_it+1) % g_inputdeck.get< tag::output, tag::iter, tag::stat >())) {
341 [ + + ][ - + ]: 398499 : tk::TxtStatWriter sw( !m_nameOrdinary.empty() || !m_nameCentral.empty() ?
342 : : g_inputdeck.get< tag::cmd, tag::io, tag::stat >() :
343 : : std::string(),
344 : : g_inputdeck.get< tag::flformat, tag::stat >(),
345 : : g_inputdeck.get< tag::prec, tag::stat >(),
346 [ + + ][ + - ]: 796998 : std::ios_base::app );
347 [ + - ][ + - ]: 796998 : if (sw.stat( m_it, m_t, m_ordinary, m_central, extra() ))
[ + + ]
348 : 368496 : m_output.get< tag::stat >() = true;
349 : : }
350 : 520531 : }
351 : :
352 : : void
353 : 520531 : Distributor::outPDF()
354 : : // *****************************************************************************
355 : : // Output PDFs to file
356 : : // *****************************************************************************
357 : : {
358 : 520531 : const auto term = g_inputdeck.get< tag::discr, tag::term >();
359 : : const auto eps = std::numeric_limits< tk::real >::epsilon();
360 : 520531 : const auto nstep = g_inputdeck.get< tag::discr, tag::nstep >();
361 : 520531 : const auto pdffreq = g_inputdeck.get< tag::output, tag::iter, tag::pdf >();
362 : :
363 : : // output PDFs at t=0 (regardless of whether it was requested), or at
364 : : // selected times, or in the last time step (regardless of whether it was
365 : : // requested
366 [ + + ]: 520531 : if ( m_it == 0 ||
367 [ + + ]: 520438 : !((m_it+1) % pdffreq) ||
368 [ + - ][ + + ]: 63383 : (std::fabs(m_t+m_dt-term) < eps || (m_it+1) >= nstep) )
369 : : {
370 : : // Generate iteration count and physical time for PDF output. In the first
371 : : // iteration, the particles are NOT advanced, see Integration::advance(),
372 : : // and we write it=0 and time=0.0 into the PDF files. For the rest of the
373 : : // iterations we write the iteration count and the physical time
374 : : // corresponding to the iteration just completed.
375 [ + + ]: 457154 : auto it = m_it == 0 ? m_it : m_it + 1;
376 [ + + ]: 457154 : auto t = m_it == 0 ? m_t : m_t + m_dt;
377 : :
378 : 457154 : outUniPDF( it, t ); // Output univariate PDFs to file(s)
379 : 457154 : outBiPDF( it, t ); // Output bivariate PDFs to file(s)
380 : 457154 : outTriPDF( it, t ); // Output trivariate PDFs to file(s)
381 : 457154 : m_output.get< tag::pdf >() = true; // Signal that PDFs were written
382 : : }
383 : 520531 : }
384 : :
385 : : void
386 : 34 : Distributor::writeUniPDF( std::uint64_t it,
387 : : tk::real t,
388 : : const tk::UniPDF& p,
389 : : tk::ctr::Moment m,
390 : : std::size_t idx )
391 : : // *****************************************************************************
392 : : // Write univariate PDF to file
393 : : //! \param[in] it Iteration count to write in output file
394 : : //! \param[in] t Physical time to write in output file
395 : : //! \param[in] p Univariate PDF to output
396 : : //! \param[in] m ORDINARY or CENTRAL PDF we are writing
397 : : //! \param[in] idx Index of the PDF of all ordinary or central PDFs requested
398 : : // *****************************************************************************
399 : : {
400 : : // Get PDF metadata
401 : : const auto nfo =
402 : : tk::ctr::pdfInfo< 1 >( g_inputdeck.get< tag::discr, tag::binsize >(),
403 : : g_inputdeck.get< tag::cmd, tag::io, tag::pdfnames >(),
404 : : g_inputdeck.get< tag::discr, tag::extent >(),
405 : : g_inputdeck.get< tag::pdf >(),
406 : : m,
407 : : idx,
408 : : it,
409 : 34 : t );
410 : :
411 : : // Construct PDF file name: base name + '_' + pdf name
412 : : std::string filename =
413 [ + - ][ + - ]: 34 : g_inputdeck.get< tag::cmd, tag::io, tag::pdf >() + '_' + nfo.name;
414 : :
415 : : // Augment PDF filename by time stamp if PDF output file policy is multiple
416 [ - + ]: 34 : if (g_inputdeck.get< tag::selected, tag::pdfpolicy >() ==
417 : : tk::ctr::PDFPolicyType::MULTIPLE)
418 [ - - ][ - - ]: 0 : filename += '_' + std::to_string( m_t );
[ - - ][ - - ]
[ - - ]
419 : :
420 : : // Augment PDF filename by '.txt' extension
421 : : filename += ".txt";
422 : :
423 : : // Create new PDF file (overwrite if exists)
424 : : tk::PDFWriter pdfw( filename,
425 : : g_inputdeck.get< tag::flformat, tag::pdf >(),
426 [ + - ]: 34 : g_inputdeck.get< tag::prec, tag::pdf >() );
427 : :
428 : : // Output PDF
429 [ + - ]: 34 : pdfw.writeTxt( p, nfo );
430 : 34 : }
431 : :
432 : : void
433 : 12 : Distributor::writeBiPDF( std::uint64_t it,
434 : : tk::real t,
435 : : const tk::BiPDF& p,
436 : : tk::ctr::Moment m,
437 : : std::size_t idx )
438 : : // *****************************************************************************
439 : : // Write bivariate PDF to file
440 : : //! \param[in] it Iteration count to write in output file
441 : : //! \param[in] t Physical time to write in output file
442 : : //! \param[in] p Bivariate PDF to output
443 : : //! \param[in] m ORDINARY or CENTRAL PDF we are writing
444 : : //! \param[in] idx Index of the PDF of all ordinary or central PDFs requested
445 : : // *****************************************************************************
446 : : {
447 : : // Get PDF metadata
448 : : const auto nfo =
449 : : tk::ctr::pdfInfo< 2 >( g_inputdeck.get< tag::discr, tag::binsize >(),
450 : : g_inputdeck.get< tag::cmd, tag::io, tag::pdfnames >(),
451 : : g_inputdeck.get< tag::discr, tag::extent >(),
452 : : g_inputdeck.get< tag::pdf >(),
453 : : m,
454 : : idx,
455 : : it,
456 : 12 : t );
457 : :
458 : : // Construct PDF file name: base name + '_' + pdf name
459 : : std::string filename =
460 [ + - ][ + - ]: 12 : g_inputdeck.get< tag::cmd, tag::io, tag::pdf >() + '_' + nfo.name;
461 : :
462 : : // Augment PDF filename by time stamp if PDF output file policy is multiple
463 [ - + ]: 12 : if (g_inputdeck.get< tag::selected, tag::pdfpolicy >() ==
464 : : tk::ctr::PDFPolicyType::MULTIPLE)
465 [ - - ][ - - ]: 0 : filename += '_' + std::to_string( m_t );
[ - - ][ - - ]
[ - - ]
466 : :
467 : : const auto& filetype = g_inputdeck.get< tag::selected, tag::filetype >();
468 : :
469 : : // Augment PDF filename by the appropriate extension
470 [ + + ]: 12 : if (filetype == tk::ctr::PDFFileType::TXT)
471 : : filename += ".txt";
472 [ - + ]: 2 : else if (filetype == tk::ctr::PDFFileType::GMSHTXT ||
473 : : filetype == tk::ctr::PDFFileType::GMSHBIN )
474 : : filename += ".gmsh";
475 [ + - ]: 2 : else if (filetype == tk::ctr::PDFFileType::EXODUSII)
476 : : filename += ".exo";
477 [ - - ][ - - ]: 0 : else Throw( "Unkown PDF file type attempting to output bivariate PDF" );
[ - - ][ - - ]
[ - - ][ - - ]
478 : :
479 : : // Create new PDF file (overwrite if exists)
480 : : tk::PDFWriter pdfw( filename,
481 : : g_inputdeck.get< tag::flformat, tag::pdf >(),
482 [ + - ]: 12 : g_inputdeck.get< tag::prec, tag::pdf >() );
483 : :
484 : : // Output PDF
485 [ + + ]: 12 : if (filetype == tk::ctr::PDFFileType::TXT)
486 [ + - ]: 10 : pdfw.writeTxt( p, nfo );
487 [ - + ]: 2 : else if (filetype == tk::ctr::PDFFileType::GMSHTXT)
488 [ - - ]: 0 : pdfw.writeGmshTxt( p, nfo,
489 : : g_inputdeck.get< tag::selected, tag::pdfctr >() );
490 [ - + ]: 2 : else if (filetype == tk::ctr::PDFFileType::GMSHBIN)
491 [ - - ]: 0 : pdfw.writeGmshBin( p, nfo,
492 : : g_inputdeck.get< tag::selected, tag::pdfctr >() );
493 [ + - ]: 2 : else if (filetype == tk::ctr::PDFFileType::EXODUSII)
494 [ + - ]: 2 : pdfw.writeExodusII( p, nfo,
495 : : g_inputdeck.get< tag::selected, tag::pdfctr >() );
496 : 12 : }
497 : :
498 : : void
499 : 12 : Distributor::writeTriPDF( std::uint64_t it,
500 : : tk::real t,
501 : : const tk::TriPDF& p,
502 : : tk::ctr::Moment m,
503 : : std::size_t idx )
504 : : // *****************************************************************************
505 : : // Write trivariate PDF to file
506 : : //! \param[in] it Iteration count to write in output file
507 : : //! \param[in] t Physical time to write in output file
508 : : //! \param[in] p Trivariate PDF to output
509 : : //! \param[in] m ORDINARY or CENTRAL PDF we are writing
510 : : //! \param[in] idx Index of the PDF of all ordinary or central PDFs requested
511 : : // *****************************************************************************
512 : : {
513 : : // Get PDF metadata
514 : : const auto nfo =
515 : : tk::ctr::pdfInfo< 3 >( g_inputdeck.get< tag::discr, tag::binsize >(),
516 : : g_inputdeck.get< tag::cmd, tag::io, tag::pdfnames >(),
517 : : g_inputdeck.get< tag::discr, tag::extent >(),
518 : : g_inputdeck.get< tag::pdf >(),
519 : : m,
520 : : idx,
521 : : it,
522 : 12 : t );
523 : :
524 : : // Construct PDF file name: base name + '_' + pdf name
525 : : std::string filename =
526 [ + - ][ + - ]: 12 : g_inputdeck.get< tag::cmd, tag::io, tag::pdf >() + '_' + nfo.name;
527 : :
528 : : // Augment PDF filename by time stamp if PDF output file policy is multiple
529 [ - + ]: 12 : if (g_inputdeck.get< tag::selected, tag::pdfpolicy >() ==
530 : : tk::ctr::PDFPolicyType::MULTIPLE)
531 [ - - ][ - - ]: 0 : filename += '_' + std::to_string( m_t );
[ - - ][ - - ]
[ - - ]
532 : :
533 : : const auto& filetype = g_inputdeck.get< tag::selected, tag::filetype >();
534 : :
535 : : // Augment PDF filename by the appropriate extension
536 [ + + ]: 12 : if (filetype == tk::ctr::PDFFileType::TXT)
537 : : filename += ".txt";
538 [ - + ]: 4 : else if (filetype == tk::ctr::PDFFileType::GMSHTXT ||
539 : : filetype == tk::ctr::PDFFileType::GMSHBIN )
540 : : filename += ".gmsh";
541 [ + - ]: 4 : else if (filetype == tk::ctr::PDFFileType::EXODUSII)
542 : : filename += ".exo";
543 [ - - ][ - - ]: 0 : else Throw( "Unkown PDF file type attempting to output trivariate PDF" );
[ - - ][ - - ]
[ - - ][ - - ]
544 : :
545 : : // Create new PDF file (overwrite if exists)
546 : : tk::PDFWriter pdfw( filename,
547 : : g_inputdeck.get< tag::flformat, tag::pdf >(),
548 [ + - ]: 12 : g_inputdeck.get< tag::prec, tag::pdf >() );
549 : :
550 : : // Output PDF
551 [ + + ]: 12 : if (filetype == tk::ctr::PDFFileType::TXT)
552 [ + - ]: 8 : pdfw.writeTxt( p, nfo );
553 [ - + ]: 4 : else if (filetype == tk::ctr::PDFFileType::GMSHTXT)
554 [ - - ]: 0 : pdfw.writeGmshTxt( p, nfo,
555 : : g_inputdeck.get< tag::selected, tag::pdfctr >() );
556 [ - + ]: 4 : else if (filetype == tk::ctr::PDFFileType::GMSHBIN)
557 [ - - ]: 0 : pdfw.writeGmshBin( p, nfo,
558 : : g_inputdeck.get< tag::selected, tag::pdfctr >() );
559 [ + - ]: 4 : else if (filetype == tk::ctr::PDFFileType::EXODUSII)
560 [ + - ]: 4 : pdfw.writeExodusII( p, nfo,
561 : : g_inputdeck.get< tag::selected, tag::pdfctr >() );
562 : 12 : }
563 : :
564 : : void
565 : 457154 : Distributor::outUniPDF( std::uint64_t it, tk::real t )
566 : : // *****************************************************************************
567 : : // Output all requested univariate PDFs to file(s)
568 : : //! \param[in] it Iteration count to write in output file
569 : : //! \param[in] t Physical time to write in output file
570 : : // *****************************************************************************
571 : : {
572 : : std::size_t idx = 0;
573 [ + + ]: 457178 : for (const auto& p : m_ordupdf)
574 : 24 : writeUniPDF( it, t, p, tk::ctr::Moment::ORDINARY, idx++ );
575 : : idx = 0;
576 [ + + ]: 457164 : for (const auto& p : m_cenupdf)
577 : 10 : writeUniPDF( it, t, p, tk::ctr::Moment::CENTRAL, idx++ );
578 : 457154 : }
579 : :
580 : : void
581 : 457154 : Distributor::outBiPDF( std::uint64_t it, tk::real t )
582 : : // *****************************************************************************
583 : : // Output all requested bivariate PDFs to file(s)
584 : : //! \param[in] it Iteration count to write in output file
585 : : //! \param[in] t Physical time to write in output file
586 : : //! \return Number of PDFs written
587 : : // *****************************************************************************
588 : : {
589 : : std::size_t idx = 0;
590 [ + + ]: 457160 : for (const auto& p : m_ordbpdf)
591 : 6 : writeBiPDF( it, t, p, tk::ctr::Moment::ORDINARY, idx++ );
592 : : idx = 0;
593 [ + + ]: 457160 : for (const auto& p : m_cenbpdf) {
594 : 6 : writeBiPDF( it, t, p, tk::ctr::Moment::CENTRAL, idx++ );
595 : : }
596 : 457154 : }
597 : :
598 : : void
599 : 457154 : Distributor::outTriPDF( std::uint64_t it, tk::real t )
600 : : // *****************************************************************************
601 : : // Output all requested trivariate PDFs to file(s)
602 : : //! \param[in] it Iteration count to write in output file
603 : : //! \param[in] t Physical time to write in output file
604 : : //! \return Number of PDFs written
605 : : // *****************************************************************************
606 : : {
607 : : std::size_t idx = 0;
608 [ + + ]: 457160 : for (const auto& p : m_ordtpdf) {
609 : 6 : writeTriPDF( it, t, p, tk::ctr::Moment::ORDINARY, idx++ );
610 : : }
611 : : idx = 0;
612 [ + + ]: 457160 : for (const auto& p : m_centpdf) {
613 : 6 : writeTriPDF( it, t, p, tk::ctr::Moment::CENTRAL, idx++ );
614 : : }
615 : 457154 : }
616 : :
617 : : void
618 : 520531 : Distributor::evaluateTime()
619 : : // *****************************************************************************
620 : : // Evaluate time step, compute new time step size, decide if it is time to quit
621 : : // *****************************************************************************
622 : : {
623 : 520531 : const auto term = g_inputdeck.get< tag::discr, tag::term >();
624 : : const auto eps = std::numeric_limits< tk::real >::epsilon();
625 : 520531 : const auto nstep = g_inputdeck.get< tag::discr, tag::nstep >();
626 : :
627 : : // Increase number of iterations taken
628 : 520531 : ++m_it;
629 : : // Advance physical time
630 : 520531 : m_t += m_dt;
631 : : // Truncate the size of last time step
632 [ + + ]: 520531 : if (m_t > term) m_t = term;
633 : : // Compute size of next time step
634 : 520531 : m_dt = computedt();
635 : : // Echo one-liner info on time step
636 : 520531 : report();
637 : :
638 : : // Finish if either max iterations or max time reached
639 [ + + ][ + + ]: 520531 : if ( std::fabs(m_t-term) > eps && m_it < nstep ) {
640 : :
641 : : if (g_inputdeck.stat()) {
642 : : // Update map of statistical moments
643 : : std::size_t ord = 0;
644 : : std::size_t cen = 0;
645 [ + + ]: 7791314 : for (const auto& product : g_inputdeck.get< tag::stat >())
646 [ + + ]: 7270876 : if (tk::ctr::ordinary( product ))
647 : 2482549 : m_moments[ product ] = m_ordinary[ ord++ ];
648 : : else
649 : 4788327 : m_moments[ product ] = m_central[ cen++ ];
650 : :
651 : : // Zero statistics counters and accumulators
652 : : std::fill( begin(m_ordinary), end(m_ordinary), 0.0 );
653 : : std::fill( begin(m_central), end(m_central), 0.0 );
654 : :
655 : : // Re-activate SDAG-wait for estimation of ordinary stats for next step
656 : 520438 : thisProxy.wait4ord();
657 : : // Re-activate SDAG-wait for estimation of PDFs for next step
658 : 520438 : thisProxy.wait4pdf();
659 : : }
660 : :
661 : : // Continue with next time step with all integrators
662 : 520438 : m_intproxy.advance( m_dt, m_t, m_it, m_moments );
663 : :
664 : 93 : } else finish();
665 : 520531 : }
666 : :
667 : : void
668 : 93 : Distributor::finish()
669 : : // *****************************************************************************
670 : : // Normal finish of time stepping
671 : : // *****************************************************************************
672 : : {
673 : : // Print out reason for stopping
674 : 93 : const auto term = g_inputdeck.get< tag::discr, tag::term >();
675 : 93 : const auto nstep = g_inputdeck.get< tag::discr, tag::nstep >();
676 : :
677 : 93 : auto print = printer();
678 : :
679 : : print.endsubsection();
680 [ + + ]: 93 : if (m_it >= g_inputdeck.get< tag::discr, tag::nstep >())
681 [ + - ][ - + ]: 18 : print.note( "Normal finish, maximum number of iterations reached: " +
[ - - ]
682 [ + - ][ + - ]: 18 : std::to_string( nstep ) );
683 : : else
684 [ + - ][ - + ]: 168 : print.note( "Normal finish, maximum time reached: " +
[ - - ]
685 [ + - ]: 168 : std::to_string( term ) );
686 : :
687 : : // Quit
688 [ + - ]: 93 : mainProxy.finalize();
689 : 93 : }
690 : :
691 : : void
692 : 0 : Distributor::nostat()
693 : : // *****************************************************************************
694 : : // Charm++ reduction target enabling shortcutting sync points if no stats
695 : : //! \details This reduction target is called if there are no statistics nor PDFs
696 : : //! to be estimated and thus some synchronization points can be skipped. Upon
697 : : //! this call we simply finish up the time step as usual.
698 : : // *****************************************************************************
699 : : {
700 : 0 : evaluateTime();
701 : 0 : }
702 : :
703 : : void
704 : 93 : Distributor::header( const WalkerPrint& print ) const
705 : : // *****************************************************************************
706 : : // Print out time integration header
707 : : //! \param[in] print Pretty printer object to use for printing
708 : : // *****************************************************************************
709 : : {
710 [ + - ]: 93 : print.inthead( "Time integration", "Differential equations testbed",
711 : : "Legend: it - iteration count\n"
712 : : " t - time\n"
713 : : " dt - time step size\n"
714 : : " ETE - estimated time elapsed (h:m:s)\n"
715 : : " ETA - estimated time for accomplishment (h:m:s)\n"
716 : : " out - status flags, legend:\n"
717 : : " s - statistics output\n"
718 : : " p - PDFs output\n"
719 : : " x - particle positions output\n",
720 : : "\n it t dt ETE ETA out\n"
721 [ + - ][ + - ]: 465 : " ---------------------------------------------------------------\n" );
[ + - ][ + - ]
[ + - ][ + - ]
[ - - ][ - - ]
[ - - ]
722 : 93 : }
723 : :
724 : : void
725 : 520531 : Distributor::report()
726 : : // *****************************************************************************
727 : : // Print out one-liner report on time step
728 : : // *****************************************************************************
729 : : {
730 [ + + ]: 520531 : if (!(m_it % g_inputdeck.get< tag::output, tag::iter, tag::tty >())) {
731 : :
732 : : const auto parfreq =
733 : 1699 : g_inputdeck.get< tag::output, tag::iter, tag::particles >();
734 : : const auto poseq =
735 : : !g_inputdeck.get< tag::param, tag::position, tag::depvar >().empty();
736 : :
737 : : // estimated time elapsed and for accomplishment
738 : : tk::Timer::Watch ete, eta;
739 : 1699 : m_timer[0].eta( g_inputdeck.get< tag::discr, tag::term >(), m_t,
740 : : g_inputdeck.get< tag::discr, tag::nstep >(), m_it,
741 : : ete, eta );
742 : :
743 : 1699 : auto print = printer();
744 : :
745 : : // Output one-liner
746 : : print << std::setfill(' ') << std::setw(8) << m_it << " "
747 : : << std::scientific << std::setprecision(6)
748 : : << std::setw(12) << m_t << " "
749 : : << m_dt << " "
750 : : << std::setfill('0')
751 : : << std::setw(3) << ete.hrs.count() << ":"
752 : : << std::setw(2) << ete.min.count() << ":"
753 : : << std::setw(2) << ete.sec.count() << " "
754 : : << std::setw(3) << eta.hrs.count() << ":"
755 : : << std::setw(2) << eta.min.count() << ":"
756 : : << std::setw(2) << eta.sec.count() << " ";
757 : :
758 : : // Augment one-liner with output indicators
759 [ + + ]: 1699 : if (m_output.get< tag::stat >()) print << 's';
760 [ + + ]: 1699 : if (m_output.get< tag::pdf >()) print << 'p';
761 [ + + ][ - + ]: 1699 : if (poseq && !(m_it % parfreq)) print << 'x';
762 : :
763 : : // Reset output indicators
764 : 1699 : m_output.get< tag::stat >() = false;
765 [ + - ]: 1699 : m_output.get< tag::pdf >() = false;
766 : :
767 : : print << std::endl;
768 : : }
769 : 520531 : }
770 : :
771 : : #include "NoWarning/distributor.def.h"
|