122 std::vector<double>
const& local_x, std::vector<double>
const& local_x_prev,
123 std::vector<double>& local_b_data, std::vector<double>& local_Jac_data)
127 auto const num_dof = local_x.size();
131 _asm1->assembleWithJacobian(local_assembler, t, dt, local_x, local_x_prev,
132 local_b_data, local_Jac_data);
136 std::vector<double> local_b_data2;
137 std::vector<double> local_Jac_data2;
140 _asm2->assembleWithJacobian(local_assembler, t, dt, local_x, local_x_prev,
141 local_b_data2, local_Jac_data2);
146 auto const local_Jac2 =
149 auto const abs_diff = (local_Jac2 - local_Jac1).array().eval();
150 auto const rel_diff =
154 (local_Jac1.cwiseAbs() + local_Jac2.cwiseAbs()).array())
157 auto const abs_diff_mask =
159 .select(
decltype(abs_diff)::Zero(abs_diff.rows(), abs_diff.cols()),
160 decltype(abs_diff)::Ones(abs_diff.rows(), abs_diff.cols()))
162 auto const rel_diff_mask =
164 .select(
decltype(rel_diff)::Zero(rel_diff.rows(), rel_diff.cols()),
165 decltype(rel_diff)::Ones(rel_diff.rows(), rel_diff.cols()))
168 auto const abs_diff_OK = !abs_diff_mask.any();
169 auto const rel_diff_OK = !rel_diff_mask.any();
171 std::ostringstream msg_tolerance;
172 bool tol_exceeded =
true;
173 bool fatal_error =
false;
177 tol_exceeded =
false;
181 msg_tolerance <<
"absolute tolerance of " <<
_abs_tol <<
" exceeded";
186 tol_exceeded =
false;
190 if (!msg_tolerance.str().empty())
192 msg_tolerance <<
" and ";
195 msg_tolerance <<
"relative tolerance of " <<
_rel_tol <<
" exceeded";
199 auto check_equality = [&fatal_error](
auto mat_or_vec1,
auto mat_or_vec2)
201 if (mat_or_vec1.size() == 0 || mat_or_vec2.size() == 0)
205 if (mat_or_vec1.rows() != mat_or_vec2.rows() ||
206 mat_or_vec1.cols() != mat_or_vec2.cols())
210 else if (((mat_or_vec1 - mat_or_vec2).array().cwiseAbs() >
211 std::numeric_limits<double>::epsilon())
218 check_equality(local_b1, local_b2);
220 Eigen::VectorXd res1 = Eigen::VectorXd::Zero(num_dof);
223 if (local_b1.size() != 0)
225 res1.noalias() -= local_b1;
228 Eigen::VectorXd res2 = Eigen::VectorXd::Zero(num_dof);
229 if (local_b2.size() != 0)
231 res2.noalias() -= local_b2;
234 check_equality(res1, res2);
238 WARN(
"Compare Jacobians: {:s}", msg_tolerance.str());
241 bool const output = tol_exceeded || fatal_error;
252 <<
"#######################################################\n"
253 <<
"# FATAL ERROR: " << msg_fatal <<
'\n'
254 <<
"# You cannot expect any meaningful insights "
255 "from the Jacobian data printed below!\n"
256 <<
"# The reason for the mentioned differences "
258 <<
"# (a) that the assembly routine has side "
260 <<
"# (b) that the assembly routines for b "
261 "themselves differ.\n"
262 <<
"#######################################################\n"
268 _log_file <<
"# " << msg_tolerance.str() <<
"\n\n";
281 dump_py(
_log_file,
"local_x_prev", local_x_prev);
286 dump_py(
_log_file,
"Jacobian_1", local_Jac1);
287 dump_py(
_log_file,
"Jacobian_2", local_Jac2);
291 _log_file <<
"# Jacobian_2 - Jacobian_1\n";
292 dump_py(
_log_file,
"abs_diff", abs_diff);
293 _log_file <<
"# Componentwise: 2 * abs_diff / (|Jacobian_1| + "
295 dump_py(
_log_file,
"rel_diff", rel_diff);
299 _log_file <<
"# Masks: 0 ... tolerance met, 1 ... tolerance exceeded\n";
300 dump_py(
_log_file,
"abs_diff_mask", abs_diff_mask);
301 dump_py(
_log_file,
"rel_diff_mask", rel_diff_mask);
306 dump_py(
_log_file,
"b_2", local_b_data2);
307 if (fatal_error && local_b1.size() == local_b2.size())
309 dump_py(
_log_file,
"delta_b", local_b2 - local_b1);
317 dump_py(
_log_file,
"delta_res", res2 - res1);
335 "OGS failed, because the two Jacobian implementations returned "
336 "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