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