OGS
ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl Struct Reference

Detailed Description

Data shared among all copied CompareJacobiansJacobianAssembler instances.

Definition at line 172 of file CompareJacobiansJacobianAssembler.cpp.

Public Member Functions

 CompareJacobiansJacobianAssemblerImpl (std::unique_ptr< AbstractJacobianAssembler > &&asm1, std::unique_ptr< AbstractJacobianAssembler > &&asm2, double abs_tol_Jac, double rel_tol_Jac, double abs_tol_res, double rel_tol_res, bool fail_on_error, std::string const &log_file_path)
void assembleWithJacobian (std::size_t const mesh_item_id, LocalAssemblerInterface &local_assembler, double const t, double const dt, std::vector< double > const &local_x, std::vector< double > const &local_x_prev, std::vector< double > &local_b_data, std::vector< double > &local_Jac_data)

Private Attributes

std::unique_ptr< AbstractJacobianAssemblerasm1_
std::unique_ptr< AbstractJacobianAssemblerasm2_
double const abs_tol_Jac_
double const rel_tol_Jac_
double const abs_tol_res_
double const rel_tol_res_
bool const fail_on_error_
 Whether to abort if the tolerances are exceeded.
std::ofstream log_file_
std::ptrdiff_t counter_ = -1
unsigned iter_ = 0

Friends

class ProcessLib::CompareJacobiansJacobianAssembler

Constructor & Destructor Documentation

◆ CompareJacobiansJacobianAssemblerImpl()

ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::CompareJacobiansJacobianAssemblerImpl ( std::unique_ptr< AbstractJacobianAssembler > && asm1,
std::unique_ptr< AbstractJacobianAssembler > && asm2,
double abs_tol_Jac,
double rel_tol_Jac,
double abs_tol_res,
double rel_tol_res,
bool fail_on_error,
std::string const & log_file_path )
inline

Definition at line 176 of file CompareJacobiansJacobianAssembler.cpp.

185 : asm1_{std::move(asm1)},
186 asm2_{std::move(asm2)},
187 abs_tol_Jac_{abs_tol_Jac},
188 rel_tol_Jac_{rel_tol_Jac},
189 abs_tol_res_{abs_tol_res},
190 rel_tol_res_{rel_tol_res},
191 fail_on_error_{fail_on_error},
192 log_file_{log_file_path}
193 {
194 log_file_.precision(std::numeric_limits<double>::max_digits10);
195 log_file_ << "#!/usr/bin/env python\n"
196 "import numpy as np\n"
197 "from numpy import nan\n"
198 << std::endl;
199 }
bool const fail_on_error_
Whether to abort if the tolerances are exceeded.

References abs_tol_Jac_, abs_tol_res_, asm1_, asm2_, fail_on_error_, log_file_, rel_tol_Jac_, and rel_tol_res_.

Member Function Documentation

◆ assembleWithJacobian()

void ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::assembleWithJacobian ( std::size_t const mesh_item_id,
LocalAssemblerInterface & local_assembler,
double const t,
double const dt,
std::vector< double > const & local_x,
std::vector< double > const & local_x_prev,
std::vector< double > & local_b_data,
std::vector< double > & local_Jac_data )

Definition at line 234 of file CompareJacobiansJacobianAssembler.cpp.

239{
240 ++counter_;
241
242 auto const num_dof = local_x.size();
243
244 // First assembly -- the one whose results will be added to the global
245 // equation system finally.
246 asm1_->assembleWithJacobian(mesh_item_id, local_assembler, t, dt, local_x,
247 local_x_prev, local_b_data, local_Jac_data);
248
249 auto const local_b1 = MathLib::toVector(local_b_data);
250
251 std::vector<double> local_b_data2;
252 std::vector<double> local_Jac_data2;
253
254 // Second assembly -- used for checking only.
255 asm2_->assembleWithJacobian(mesh_item_id, local_assembler, t, dt, local_x,
256 local_x_prev, local_b_data2, local_Jac_data2);
257
258 auto const local_b2 = MathLib::toVector(local_b_data2);
259
260 auto const local_Jac1 = MathLib::toMatrix(local_Jac_data, num_dof, num_dof);
261 auto const local_Jac2 =
262 MathLib::toMatrix(local_Jac_data2, num_dof, num_dof);
263
264 auto const [abs_diff, rel_diff] =
265 signedAbsDiffRelDiff(local_Jac1, local_Jac2);
266
267 auto const abs_diff_mask =
269 auto const rel_diff_mask =
271
272 auto const abs_diff_OK = !abs_diff_mask.any();
273 auto const rel_diff_OK = !rel_diff_mask.any();
274
275 std::ostringstream msg_tolerance;
276 bool tol_exceeded = true;
277 bool fatal_error = false;
278
279 if (abs_diff_OK)
280 {
281 tol_exceeded = false;
282 }
283 else
284 {
285 msg_tolerance << "absolute tolerance of " << abs_tol_Jac_
286 << " exceeded";
287 }
288
289 if (rel_diff_OK)
290 {
291 tol_exceeded = false;
292 }
293 else
294 {
295 if (!msg_tolerance.str().empty())
296 {
297 msg_tolerance << " and ";
298 }
299
300 msg_tolerance << "relative tolerance of " << rel_tol_Jac_
301 << " exceeded";
302 }
303
304 fatal_error |= !isSimilar(local_b1, local_b2, abs_tol_res_, rel_tol_res_);
305
306 Eigen::VectorXd res1 = Eigen::VectorXd::Zero(num_dof);
307 auto const x = MathLib::toVector(local_x);
308 auto const x_dot = ((x - MathLib::toVector(local_x_prev)) / dt).eval();
309 if (local_b1.size() != 0)
310 {
311 res1.noalias() -= local_b1;
312 }
313
314 Eigen::VectorXd res2 = Eigen::VectorXd::Zero(num_dof);
315 if (local_b2.size() != 0)
316 {
317 res2.noalias() -= local_b2;
318 }
319
320 fatal_error |= !isSimilar(res1, res2, abs_tol_res_, rel_tol_res_);
321
322 if (tol_exceeded)
323 {
324 WARN("Compare Jacobians: {:s}", msg_tolerance.str());
325 }
326
327 bool const output = tol_exceeded || fatal_error;
328
329 if (output)
330 {
331 log_file_ << "\n### counter: " << std::to_string(counter_)
332 << ", t: " << t << ", element_id: " << mesh_item_id
333 << " (begin)\n";
334 }
335
336 if (fatal_error)
337 {
338 log_file_ << '\n'
339 << "#######################################################\n"
340 << "# FATAL ERROR: " << msg_fatal << '\n'
341 << "# You cannot expect any meaningful insights "
342 "from the Jacobian data printed below!\n"
343 << "# The reason for the mentioned differences "
344 "might be\n"
345 << "# (a) that the assembly routine has side "
346 "effects or\n"
347 << "# (b) that the assembly routines for b "
348 "themselves differ.\n"
349 << "#######################################################\n"
350 << '\n';
351 }
352
353 if (tol_exceeded)
354 {
355 log_file_ << "# " << msg_tolerance.str() << "\n\n";
356 }
357
358 if (output)
359 {
360 dump_py(log_file_, "counter", counter_);
361 dump_py(log_file_, "nonlinear_iteration", iter_);
362 dump_py(log_file_, "t", t);
363 dump_py(log_file_, "dt", dt);
364 dump_py(log_file_, "element_id", mesh_item_id);
365
366 log_file_ << '\n';
367
368 dump_py(log_file_, "num_dof", num_dof);
369 dump_py(log_file_, "abs_tol", abs_tol_Jac_);
370 dump_py(log_file_, "rel_tol", rel_tol_Jac_);
371
372 log_file_ << '\n';
373
374 dump_py(log_file_, "local_x", local_x);
375 dump_py(log_file_, "local_x_prev", local_x_prev);
376
377 log_file_ << '\n';
378
379 dump_py(log_file_, "Jacobian_1", local_Jac1);
380 dump_py(log_file_, "Jacobian_2", local_Jac2);
381
382 log_file_ << '\n';
383
384 log_file_ << "# Jacobian_2 - Jacobian_1\n";
385 dump_py(log_file_, "abs_diff", abs_diff);
386 log_file_ << "# max(|abs_diff|) = " << abs_diff.abs().maxCoeff()
387 << '\n';
388 log_file_ << "# Componentwise: 2 * abs_diff / (|Jacobian_1| + "
389 "|Jacobian_2|)\n";
390 dump_py(log_file_, "rel_diff", rel_diff);
391 log_file_ << "# max(|rel_diff|) = " << rel_diff.abs().maxCoeff()
392 << '\n';
393
394 log_file_ << '\n';
395
396 log_file_ << "# Masks: 0 ... tolerance met, 1 ... tolerance exceeded\n";
397 dump_py(log_file_, "abs_diff_mask", abs_diff_mask);
398 dump_py(log_file_, "rel_diff_mask", rel_diff_mask);
399
400 log_file_ << '\n';
401
402 dump_py(log_file_, "b_1", local_b_data);
403 dump_py(log_file_, "b_2", local_b_data2);
404 if (fatal_error && local_b1.size() == local_b2.size())
405 {
406 dump_py(log_file_, "delta_b", local_b2 - local_b1);
407 log_file_ << '\n';
408 }
409
410 dump_py(log_file_, "res_1", res1);
411 dump_py(log_file_, "res_2", res2);
412 if (fatal_error)
413 {
414 dump_py(log_file_, "delta_res", res2 - res1);
415 }
416
417 log_file_ << '\n';
418
419 log_file_ << "### counter: " << std::to_string(counter_) << " (end)\n";
420 }
421
422 if (fatal_error)
423 {
424 log_file_ << std::flush;
425 OGS_FATAL("{:s}", msg_fatal);
426 }
427
428 if (tol_exceeded && fail_on_error_)
429 {
430 log_file_ << std::flush;
431 OGS_FATAL(
432 "OGS failed, because the two Jacobian implementations returned "
433 "different results.");
434 }
435}
#define OGS_FATAL(...)
Definition Error.h:10
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
Eigen::Map< const Vector > toVector(std::vector< double > const &data, Eigen::VectorXd::Index size)
Creates an Eigen mapped vector from the given data vector.
Eigen::Map< const Matrix > toMatrix(std::vector< double > const &data, Eigen::MatrixXd::Index rows, Eigen::MatrixXd::Index cols)
auto eval(Function &f, Tuples &... ts) -> typename detail::GetFunctionReturnType< decltype(&Function::eval)>::type
Definition Apply.h:270
bool isSimilar(auto const &mat_or_vec1, auto const &mat_or_vec2, double const abs_tol, double const rel_tol)
auto signedAbsDiffRelDiff(auto const &mat_or_vec1, auto const &mat_or_vec2)
(Signed) absolute and (symmetric) relative difference as Eigen::Array
auto oneIfAboveThresholdElseZero(MatOrVec &&mat_or_vec, double const threshold)
void dump_py(std::ostream &fh, std::string const &var, T const val)
Dumps a numeric value as a Python script snippet.
const std::string msg_fatal
Will be printed if some consistency error is detected.

References abs_tol_Jac_, abs_tol_res_, asm1_, asm2_, counter_, fail_on_error_, iter_, log_file_, OGS_FATAL, rel_tol_Jac_, rel_tol_res_, MathLib::toMatrix(), MathLib::toVector(), and WARN().

◆ ProcessLib::CompareJacobiansJacobianAssembler

Member Data Documentation

◆ abs_tol_Jac_

double const ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::abs_tol_Jac_
private

◆ abs_tol_res_

double const ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::abs_tol_res_
private

◆ asm1_

std::unique_ptr<AbstractJacobianAssembler> ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::asm1_
private

◆ asm2_

std::unique_ptr<AbstractJacobianAssembler> ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::asm2_
private

◆ counter_

std::ptrdiff_t ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::counter_ = -1
private

Counter used for identifying blocks in the log_file_. It is incremented upon each call of the assembly routine, i.e., for each element in each iteration etc.

Definition at line 229 of file CompareJacobiansJacobianAssembler.cpp.

Referenced by assembleWithJacobian().

◆ fail_on_error_

bool const ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::fail_on_error_
private

Whether to abort if the tolerances are exceeded.

Definition at line 219 of file CompareJacobiansJacobianAssembler.cpp.

Referenced by CompareJacobiansJacobianAssemblerImpl(), and assembleWithJacobian().

◆ iter_

unsigned ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::iter_ = 0
private

Definition at line 231 of file CompareJacobiansJacobianAssembler.cpp.

Referenced by assembleWithJacobian().

◆ log_file_

std::ofstream ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::log_file_
private

Path where a Python script will be placed, which contains information about exceeded tolerances and assembled local matrices.

Definition at line 224 of file CompareJacobiansJacobianAssembler.cpp.

Referenced by CompareJacobiansJacobianAssemblerImpl(), and assembleWithJacobian().

◆ rel_tol_Jac_

double const ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::rel_tol_Jac_
private

◆ rel_tol_res_

double const ProcessLib::detail::CompareJacobiansJacobianAssemblerImpl::rel_tol_res_
private

The documentation for this struct was generated from the following file: