Skip to content

Commit a1bf9c5

Browse files
authored
better boris crash log (#1077)
better boris crash log
1 parent 3015cb7 commit a1bf9c5

File tree

7 files changed

+261
-51
lines changed

7 files changed

+261
-51
lines changed

pyphare/pyphare/simulator/simulator.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from . import monitoring as mon
1414

1515

16+
exit_on_exception = True
1617
life_cycles = {}
1718
SIM_MONITOR = os.getenv("PHARE_SIM_MON", "False").lower() in ("true", "1", "t")
1819
SCOPE_TIMING = os.getenv("PHARE_SCOPE_TIMING", "False").lower() in ("true", "1", "t")
@@ -164,7 +165,10 @@ def initialize(self):
164165

165166
def _throw(self, e):
166167
print_rank0(e)
167-
sys.exit(1)
168+
if exit_on_exception:
169+
sys.exit(1)
170+
# or reraise
171+
raise RuntimeError(e)
168172

169173
def advance(self, dt=None):
170174
self._check_init()

src/amr/solvers/solver_ppc.hpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,10 +569,19 @@ void SolverPPC<HybridModel, AMR_Types>::moveIons_(level_t& level, ModelViews_t&
569569
fromCoarser.fillIonPopMomentGhosts(views.model().state.ions, level, newTime);
570570
fromCoarser.fillIonGhostParticles(views.model().state.ions, level, newTime);
571571

572-
for (auto& state : views)
573-
ionUpdater_.updateIons(state.ions);
574-
// no need to update time, since it has been done before
572+
try
573+
{
574+
for (auto& state : views)
575+
ionUpdater_.updateIons(state.ions);
576+
}
577+
catch (core::DictionaryException const& ex)
578+
{
579+
PHARE_LOG_ERROR(ex());
580+
}
581+
if (core::mpi::any(core::Errors::instance().any()))
582+
throw core::DictionaryException{}("ID", "Updater::updatePopulations");
575583

584+
// no need to update time, since it has been done before
576585
// now Ni and Vi are calculated we can fill pure ghost nodes
577586
// these were not completed by the deposition of patch and levelghost particles
578587
// fromCoarser.fillIonMomentGhosts(views.model().state.ions, level, newTime);

src/core/errors.hpp

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,53 @@
22
#define PHARE_CORE_ERRORS_HPP
33

44
#include "core/def.hpp"
5-
#include <vector>
6-
#include <unordered_map>
5+
76
#include <string>
7+
#include <sstream>
88
#include <iostream>
9+
#include <unordered_map>
10+
11+
12+
#include "cppdict/include/dict.hpp"
913

1014

1115
namespace PHARE::core
1216
{
17+
class DictionaryException : public std::exception
18+
{
19+
public:
20+
DictionaryException() = default;
21+
DictionaryException(auto const& k, auto const& v) { (*this)(k, v); }
22+
23+
using Dict_t = cppdict::Dict<std::string>;
24+
25+
auto& operator[](std::string const& key) { return dict_[key]; }
26+
auto& operator[](std::string const& key) const { return dict_[key]; }
27+
auto& operator()(std::string const key, std::string const val)
28+
{
29+
dict_[key] = val;
30+
return *this;
31+
}
32+
33+
std::string operator()() const
34+
{
35+
std::stringstream ss;
36+
dict_.visit(
37+
[&](std::string const& key, auto const& val) { ss << key << " " << val << std::endl; });
38+
return ss.str();
39+
}
40+
41+
char const* what() const noexcept override
42+
{
43+
static thread_local std::string msg;
44+
return (msg = (*this)()).c_str();
45+
}
46+
47+
private:
48+
Dict_t dict_;
49+
};
50+
51+
1352
class Errors
1453
{
1554
public:

src/core/numerics/pusher/boris.hpp

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
#ifndef PHARE_CORE_PUSHER_BORIS_HPP
22
#define PHARE_CORE_PUSHER_BORIS_HPP
33

4+
5+
#include "core/errors.hpp"
6+
#include "core/logger.hpp"
7+
#include "core/numerics/pusher/pusher.hpp"
8+
9+
410
#include <array>
511
#include <cmath>
612
#include <cstddef>
7-
#include <algorithm>
13+
#include <sstream>
814
#include <iterator>
9-
#include <stdexcept>
10-
#include "core/numerics/pusher/pusher.hpp"
11-
#include "core/utilities/range/range.hpp"
12-
#include "core/errors.hpp"
13-
#include "core/logger.hpp"
14-
#include "core/data/particles/particle.hpp"
15+
#include <algorithm>
16+
#include <exception>
1517

1618
namespace PHARE::core
1719
{
@@ -22,6 +24,18 @@ template<std::size_t dim, typename ParticleRange, typename Electromag, typename
2224
class BorisPusher
2325
: public Pusher<dim, ParticleRange, Electromag, Interpolator, BoundaryCondition, GridLayout>
2426
{
27+
struct MoveTwoCellException : std::exception
28+
{
29+
MoveTwoCellException(double const d, double const v)
30+
: delta{d}
31+
, vel{v}
32+
{
33+
}
34+
35+
double delta, vel;
36+
};
37+
38+
2539
public:
2640
using Super
2741
= Pusher<dim, ParticleRange, Electromag, Interpolator, BoundaryCondition, GridLayout>;
@@ -91,19 +105,33 @@ class BorisPusher
91105

92106
rangeOut = firstSelector(rangeOut);
93107

94-
95108
double const dto2m = 0.5 * dt_ / mass;
96109
for (auto idx = rangeOut.ibegin(); idx < rangeOut.iend(); ++idx)
97110
{
98111
auto& currPart = rangeOut.array()[idx];
99112

100113
// get electromagnetic fields interpolated on the particles of rangeOut stop at newEnd.
101114
// get the particle velocity from t=n to t=n+1
102-
accelerate_(currPart, interpolator(currPart, emFields, layout), dto2m);
115+
auto const& local_em = interpolator(currPart, emFields, layout);
116+
accelerate_(currPart, local_em, dto2m);
103117

104118
// now advance the particles from t=n+1/2 to t=n+1 using v_{n+1} just calculated
105119
// and get a pointer to the first leaving particle
106-
postPushStep_(rangeOut, idx);
120+
try
121+
{
122+
postPushStep_(rangeOut, idx);
123+
}
124+
catch (DictionaryException const& bex)
125+
{
126+
auto ex = bex;
127+
auto const& [e, b] = local_em;
128+
for (std::uint16_t i = 0; i < 3; ++i)
129+
ex("E_" + std::to_string(i), std::to_string(e[i]));
130+
for (std::uint16_t i = 0; i < 3; ++i)
131+
ex("B_" + std::to_string(i), std::to_string(b[i]));
132+
ex("level", std::to_string(layout.levelNumber()));
133+
throw ex;
134+
}
107135
}
108136

109137
return secondSelector(rangeOut);
@@ -130,22 +158,20 @@ class BorisPusher
130158
std::array<int, dim> newCell;
131159
for (std::size_t iDim = 0; iDim < dim; ++iDim)
132160
{
133-
double delta
161+
double const delta
134162
= partIn.delta[iDim] + static_cast<double>(halfDtOverDl_[iDim] * partIn.v[iDim]);
135163

136-
double iCell = std::floor(delta);
137164
if (std::abs(delta) > 2)
138-
{
139-
PHARE_LOG_ERROR("Error, particle moves more than 1 cell, delta >2");
140-
}
165+
throw MoveTwoCellException{delta, partIn.v[iDim]};
166+
167+
auto const iCell = static_cast<int>(std::floor(delta));
141168
partOut.delta[iDim] = delta - iCell;
142-
newCell[iDim] = static_cast<int>(iCell + partIn.iCell[iDim]);
169+
newCell[iDim] = iCell + partIn.iCell[iDim];
143170
}
144171
return newCell;
145172
}
146173

147174

148-
149175
/** advance the particles in rangeIn of half a time step and store them
150176
* in rangeOut.
151177
* @return the function returns and iterator on the first leaving particle, as
@@ -172,18 +198,39 @@ class BorisPusher
172198
outParticles[outIdx].weight = inParticles[inIdx].weight;
173199
outParticles[outIdx].v = inParticles[inIdx].v;
174200

175-
auto newCell = advancePosition_(inParticles[inIdx], outParticles[outIdx]);
176-
if (newCell != inParticles[inIdx].iCell)
177-
outParticles.change_icell(newCell, outIdx);
201+
try
202+
{
203+
auto newCell = advancePosition_(inParticles[inIdx], outParticles[outIdx]);
204+
if (newCell != inParticles[inIdx].iCell)
205+
outParticles.change_icell(newCell, outIdx);
206+
}
207+
catch (MoveTwoCellException const& e)
208+
{
209+
std::stringstream ss;
210+
ss << "PrePush Particle moved 2 cells with delta/vel: ";
211+
ss << e.delta << "/" << e.vel << std::endl;
212+
DictionaryException ex{"cause", ss.str()};
213+
throw ex;
214+
}
178215
}
179216
}
180217

181218
void postPushStep_(ParticleRange& range, std::size_t idx)
182219
{
183-
auto& particles = range.array();
184-
auto newCell = advancePosition_(particles[idx], particles[idx]);
185-
if (newCell != particles[idx].iCell)
186-
particles.change_icell(newCell, idx);
220+
try
221+
{
222+
auto& particles = range.array();
223+
auto newCell = advancePosition_(particles[idx], particles[idx]);
224+
if (newCell != particles[idx].iCell)
225+
particles.change_icell(newCell, idx);
226+
}
227+
catch (MoveTwoCellException const& e)
228+
{
229+
std::stringstream ss;
230+
ss << "PostPush Particle moved 2 cells with delta/vel: ";
231+
ss << e.delta << "/" << e.vel << std::endl;
232+
throw DictionaryException{}("cause", ss.str());
233+
}
187234
}
188235

189236

src/simulator/simulator.hpp

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#ifndef PHARE_SIMULATOR_SIMULATOR_HPP
22
#define PHARE_SIMULATOR_SIMULATOR_HPP
33

4+
45
#include "phare_core.hpp"
56
#include "phare_types.hpp"
67

78
#include "core/def.hpp"
9+
#include "core/errors.hpp"
810
#include "core/logger.hpp"
911
#include "core/utilities/types.hpp"
1012
#include "core/utilities/mpi_utils.hpp"
@@ -373,30 +375,34 @@ void Simulator<opts>::initialize()
373375
{
374376
PHARE_LOG_SCOPE(1, "Simulator::initialize");
375377

378+
std::optional<std::string> error = std::nullopt;
379+
376380
try
377381
{
378382
if (isInitialized)
379-
std::runtime_error("cannot initialize - simulator already isInitialized");
383+
throw std::runtime_error("cannot initialize - simulator already isInitialized");
380384

381-
if (integrator_ != nullptr)
382-
integrator_->initialize();
383-
else
385+
if (integrator_ == nullptr)
384386
throw std::runtime_error("Error - Simulator has no integrator");
387+
388+
integrator_->initialize();
385389
}
386-
catch (std::runtime_error const& e)
390+
catch (std::exception const& e)
387391
{
388-
std::cerr << "EXCEPTION CAUGHT: " << e.what() << std::endl;
389-
std::rethrow_exception(std::current_exception());
392+
error = std::string{"EXCEPTION CAUGHT: "} + e.what();
393+
PHARE_LOG_ERROR(*error);
390394
}
391395
catch (...)
392396
{
393-
std::cerr << "UNKNOWN EXCEPTION CAUGHT" << std::endl;
394-
std::rethrow_exception(std::current_exception());
397+
error = "UNKNOWN EXCEPTION CAUGHT";
398+
PHARE_LOG_ERROR(*error);
395399
}
396400

397401
if (core::mpi::any(core::Errors::instance().any()))
398402
{
399-
this->dMan.release(); // closes/flushes hdf5 files
403+
this->dMan.reset(); // closes/flushes hdf5 files
404+
if (error)
405+
throw std::runtime_error(*error);
400406
throw std::runtime_error("forcing error");
401407
}
402408

@@ -413,30 +419,34 @@ template<auto opts>
413419
double Simulator<opts>::advance(double dt)
414420
{
415421
PHARE_LOG_SCOPE(1, "Simulator::advance");
416-
double dt_new = 0;
417422

418-
if (!integrator_)
419-
throw std::runtime_error("Error - no valid integrator in the simulator");
423+
double dt_new = 0;
424+
std::optional<std::string> error = std::nullopt;
420425

421426
try
422427
{
428+
if (!integrator_)
429+
throw std::runtime_error("Error - no valid integrator in the simulator");
430+
423431
dt_new = integrator_->advance(dt);
424432
currentTime_ = startTime_ + ((*timeStamper) += dt);
425433
}
426-
catch (std::runtime_error const& e)
434+
catch (std::exception const& e)
427435
{
428-
std::cerr << "EXCEPTION CAUGHT: " << e.what() << std::endl;
429-
std::rethrow_exception(std::current_exception());
436+
error = std::string{"EXCEPTION CAUGHT: "} + e.what();
437+
PHARE_LOG_ERROR(*error);
430438
}
431439
catch (...)
432440
{
433-
std::cerr << "UNKNOWN EXCEPTION CAUGHT" << std::endl;
434-
std::rethrow_exception(std::current_exception());
441+
error = "UNKNOWN EXCEPTION CAUGHT";
442+
PHARE_LOG_ERROR(*error);
435443
}
436444

437445
if (core::mpi::any(core::Errors::instance().any()))
438446
{
439-
this->dMan.release(); // closes/flushes hdf5 files
447+
this->dMan.reset(); // closes/flushes hdf5 files
448+
if (error)
449+
throw std::runtime_error(*error);
440450
throw std::runtime_error("forcing error");
441451
}
442452

tests/core/numerics/pusher/test_pusher.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ struct DummyLayout
120120
std::array<unsigned int, dimension> nbrCells_;
121121
auto nbrCells() const { return nbrCells_; }
122122
auto AMRBox() const { return PHARE::core::emptyBox<int, dimension>(); }
123+
auto levelNumber() const { return 0; }
123124
};
124125

125126
template<std::size_t dim>
@@ -252,8 +253,8 @@ class APusherWithLeavingParticles : public ::testing::Test
252253
public:
253254
APusherWithLeavingParticles()
254255
: pusher{std::make_unique<
255-
BorisPusher<1, IndexRange<ParticleArray<1>>, Electromag, Interpolator,
256-
BoundaryCondition<1, 1>, DummyLayout<1>>>()}
256+
BorisPusher<1, IndexRange<ParticleArray<1>>, Electromag, Interpolator,
257+
BoundaryCondition<1, 1>, DummyLayout<1>>>()}
257258
, mass{1}
258259
, dt{0.001}
259260
, tstart{0}

0 commit comments

Comments
 (0)