129 std::vector<double>
const& local_x, std::vector<double>
const& local_x_prev,
130 std::vector<double>& local_b_data, std::vector<double>& local_Jac_data)
134 auto const num_dof = local_x.size();
138 _asm1->assembleWithJacobian(local_assembler, t, dt, local_x, local_x_prev,
139 local_b_data, local_Jac_data);
143 std::vector<double> local_b_data2;
144 std::vector<double> local_Jac_data2;
147 _asm2->assembleWithJacobian(local_assembler, t, dt, local_x, local_x_prev,
148 local_b_data2, local_Jac_data2);
153 auto const local_Jac2 =
156 auto const abs_diff = (local_Jac2 - local_Jac1).array().eval();
157 auto const rel_diff =
161 (local_Jac1.cwiseAbs() + local_Jac2.cwiseAbs()).array())
164 auto const abs_diff_mask =
166 .select(
decltype(abs_diff)::Zero(abs_diff.rows(), abs_diff.cols()),
167 decltype(abs_diff)::Ones(abs_diff.rows(), abs_diff.cols()))
169 auto const rel_diff_mask =
171 .select(
decltype(rel_diff)::Zero(rel_diff.rows(), rel_diff.cols()),
172 decltype(rel_diff)::Ones(rel_diff.rows(), rel_diff.cols()))
175 auto const abs_diff_OK = !abs_diff_mask.any();
176 auto const rel_diff_OK = !rel_diff_mask.any();
178 std::ostringstream msg_tolerance;
179 bool tol_exceeded =
true;
180 bool fatal_error =
false;
184 tol_exceeded =
false;
188 msg_tolerance <<
"absolute tolerance of " <<
_abs_tol <<
" exceeded";
193 tol_exceeded =
false;
197 if (!msg_tolerance.str().empty())
199 msg_tolerance <<
" and ";
202 msg_tolerance <<
"relative tolerance of " <<
_rel_tol <<
" exceeded";
206 auto check_equality = [&fatal_error](
auto mat_or_vec1,
auto mat_or_vec2)
208 if (mat_or_vec1.size() == 0 || mat_or_vec2.size() == 0)
212 if (mat_or_vec1.rows() != mat_or_vec2.rows() ||
213 mat_or_vec1.cols() != mat_or_vec2.cols())
217 else if (((mat_or_vec1 - mat_or_vec2).array().cwiseAbs() >
218 std::numeric_limits<double>::epsilon())
225 check_equality(local_b1, local_b2);
227 Eigen::VectorXd res1 = Eigen::VectorXd::Zero(num_dof);
230 if (local_b1.size() != 0)
232 res1.noalias() -= local_b1;
235 Eigen::VectorXd res2 = Eigen::VectorXd::Zero(num_dof);
236 if (local_b2.size() != 0)
238 res2.noalias() -= local_b2;
241 check_equality(res1, res2);
245 WARN(
"Compare Jacobians: {:s}", msg_tolerance.str());
248 bool const output = tol_exceeded || fatal_error;
259 <<
"#######################################################\n"
260 <<
"# FATAL ERROR: " << msg_fatal <<
'\n'
261 <<
"# You cannot expect any meaningful insights "
262 "from the Jacobian data printed below!\n"
263 <<
"# The reason for the mentioned differences "
265 <<
"# (a) that the assembly routine has side "
267 <<
"# (b) that the assembly routines for b "
268 "themselves differ.\n"
269 <<
"#######################################################\n"
275 _log_file <<
"# " << msg_tolerance.str() <<
"\n\n";
288 dump_py(
_log_file,
"local_x_prev", local_x_prev);
293 dump_py(
_log_file,
"Jacobian_1", local_Jac1);
294 dump_py(
_log_file,
"Jacobian_2", local_Jac2);
298 _log_file <<
"# Jacobian_2 - Jacobian_1\n";
299 dump_py(
_log_file,
"abs_diff", abs_diff);
300 _log_file <<
"# Componentwise: 2 * abs_diff / (|Jacobian_1| + "
302 dump_py(
_log_file,
"rel_diff", rel_diff);
306 _log_file <<
"# Masks: 0 ... tolerance met, 1 ... tolerance exceeded\n";
307 dump_py(
_log_file,
"abs_diff_mask", abs_diff_mask);
308 dump_py(
_log_file,
"rel_diff_mask", rel_diff_mask);
313 dump_py(
_log_file,
"b_2", local_b_data2);
314 if (fatal_error && local_b1.size() == local_b2.size())
316 dump_py(
_log_file,
"delta_b", local_b2 - local_b1);
324 dump_py(
_log_file,
"delta_res", res2 - res1);
342 "OGS failed, because the two Jacobian implementations returned "
343 "different results.");
void assembleWithJacobian(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) override