diff --git a/src/ode_solver/bdf.rs b/src/ode_solver/bdf.rs index c36f3d5..53fe8f3 100644 --- a/src/ode_solver/bdf.rs +++ b/src/ode_solver/bdf.rs @@ -1250,7 +1250,6 @@ mod test { let (problem, soln) = exponential_decay_problem::(false); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 11 number_of_steps: 47 number_of_error_test_failures: 0 @@ -1258,7 +1257,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 84 number_of_jac_muls: 2 number_of_matrix_evals: 1 @@ -1288,7 +1286,6 @@ mod test { let (problem, soln) = exponential_decay_problem::(false); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 11 number_of_steps: 47 number_of_error_test_failures: 0 @@ -1296,7 +1293,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 84 number_of_jac_muls: 2 number_of_matrix_evals: 1 @@ -1310,7 +1306,6 @@ mod test { let (problem, soln) = exponential_decay_problem_sens::(false); test_ode_solver(&mut s, &problem, soln, None, false, true); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 11 number_of_steps: 44 number_of_error_test_failures: 0 @@ -1318,7 +1313,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 87 number_of_jac_muls: 136 number_of_matrix_evals: 1 @@ -1332,14 +1326,12 @@ mod test { let (problem, soln) = exponential_decay_problem_adjoint::(); let adjoint_solver = test_ode_solver_adjoint(s, &problem, soln); insta::assert_yaml_snapshot!(problem.eqn.rhs().statistics(), @r###" - --- number_of_calls: 84 number_of_jac_muls: 6 number_of_matrix_evals: 3 number_of_jac_adj_muls: 492 "###); insta::assert_yaml_snapshot!(adjoint_solver.get_statistics(), @r###" - --- number_of_linear_solver_setups: 24 number_of_steps: 86 number_of_error_test_failures: 12 @@ -1354,14 +1346,12 @@ mod test { let (problem, soln) = exponential_decay_with_algebraic_adjoint_problem::(); let adjoint_solver = test_ode_solver_adjoint(s, &problem, soln); insta::assert_yaml_snapshot!(problem.eqn.rhs().statistics(), @r###" - --- number_of_calls: 190 number_of_jac_muls: 24 number_of_matrix_evals: 8 number_of_jac_adj_muls: 278 "###); insta::assert_yaml_snapshot!(adjoint_solver.get_statistics(), @r###" - --- number_of_linear_solver_setups: 32 number_of_steps: 74 number_of_error_test_failures: 15 @@ -1376,7 +1366,6 @@ mod test { let (problem, soln) = exponential_decay_with_algebraic_problem::(false); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 20 number_of_steps: 41 number_of_error_test_failures: 4 @@ -1384,7 +1373,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 83 number_of_jac_muls: 6 number_of_matrix_evals: 2 @@ -1407,7 +1395,6 @@ mod test { let (problem, soln) = exponential_decay_with_algebraic_problem_sens::(); test_ode_solver(&mut s, &problem, soln, None, false, true); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 18 number_of_steps: 43 number_of_error_test_failures: 3 @@ -1415,7 +1402,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 71 number_of_jac_muls: 100 number_of_matrix_evals: 3 @@ -1429,7 +1415,6 @@ mod test { let (problem, soln) = robertson::(false); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 77 number_of_steps: 316 number_of_error_test_failures: 3 @@ -1437,7 +1422,6 @@ mod test { number_of_nonlinear_solver_fails: 19 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 725 number_of_jac_muls: 60 number_of_matrix_evals: 20 @@ -1481,7 +1465,6 @@ mod test { let (problem, soln) = robertson_sens::(); test_ode_solver(&mut s, &problem, soln, None, false, true); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 160 number_of_steps: 410 number_of_error_test_failures: 4 @@ -1489,7 +1472,6 @@ mod test { number_of_nonlinear_solver_fails: 81 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 996 number_of_jac_muls: 2495 number_of_matrix_evals: 71 @@ -1503,7 +1485,6 @@ mod test { let (problem, soln) = robertson::(true); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 77 number_of_steps: 316 number_of_error_test_failures: 3 @@ -1511,7 +1492,6 @@ mod test { number_of_nonlinear_solver_fails: 19 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 725 number_of_jac_muls: 63 number_of_matrix_evals: 20 @@ -1525,7 +1505,6 @@ mod test { let (problem, soln) = robertson_ode::(false, 3); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 86 number_of_steps: 416 number_of_error_test_failures: 1 @@ -1533,7 +1512,6 @@ mod test { number_of_nonlinear_solver_fails: 15 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 913 number_of_jac_muls: 162 number_of_matrix_evals: 18 @@ -1547,7 +1525,6 @@ mod test { let (problem, soln) = robertson_ode_with_sens::(false); test_ode_solver(&mut s, &problem, soln, None, false, true); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 112 number_of_steps: 467 number_of_error_test_failures: 2 @@ -1555,7 +1532,6 @@ mod test { number_of_nonlinear_solver_fails: 49 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 1041 number_of_jac_muls: 2672 number_of_matrix_evals: 45 @@ -1569,7 +1545,6 @@ mod test { let (problem, soln) = dydt_y2_problem::(false, 10); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 27 number_of_steps: 161 number_of_error_test_failures: 0 @@ -1577,7 +1552,6 @@ mod test { number_of_nonlinear_solver_fails: 3 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 357 number_of_jac_muls: 50 number_of_matrix_evals: 5 @@ -1591,7 +1565,6 @@ mod test { let (problem, soln) = dydt_y2_problem::(true, 10); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 27 number_of_steps: 161 number_of_error_test_failures: 0 @@ -1599,7 +1572,6 @@ mod test { number_of_nonlinear_solver_fails: 3 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 357 number_of_jac_muls: 15 number_of_matrix_evals: 5 @@ -1613,7 +1585,6 @@ mod test { let (problem, soln) = gaussian_decay_problem::(false, 10); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 14 number_of_steps: 66 number_of_error_test_failures: 1 @@ -1621,7 +1592,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 132 number_of_jac_muls: 20 number_of_matrix_evals: 2 @@ -1637,7 +1607,6 @@ mod test { let (problem, soln) = head2d_problem::, 10>(); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 21 number_of_steps: 167 number_of_error_test_failures: 0 @@ -1645,7 +1614,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 333 number_of_jac_muls: 128 number_of_matrix_evals: 4 @@ -1674,7 +1642,6 @@ mod test { let (problem, soln) = foodweb_problem::, 10>(); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 45 number_of_steps: 161 number_of_error_test_failures: 2 diff --git a/src/ode_solver/builder.rs b/src/ode_solver/builder.rs index 79ad134..f677bc1 100644 --- a/src/ode_solver/builder.rs +++ b/src/ode_solver/builder.rs @@ -721,7 +721,7 @@ impl OdeBuilder { } /// Build an ODE problem from a set of equations - pub fn build_from_eqn(self, eqn: Rc) -> Result, DiffsolError> + pub fn build_from_eqn(self, mut eqn: Eqn) -> Result, DiffsolError> where Eqn: OdeEquations, { @@ -737,8 +737,10 @@ impl OdeBuilder { nout, nparams, )?; + let p = Rc::new(Self::build_p(self.p)); + eqn.set_params(p); OdeSolverProblem::new( - eqn, + Rc::new(eqn), Eqn::T::from(self.rtol), atol, self.sens_rtol.map(Eqn::T::from), diff --git a/src/ode_solver/diffsl.rs b/src/ode_solver/diffsl.rs index 0fdaa7b..1342d4d 100644 --- a/src/ode_solver/diffsl.rs +++ b/src/ode_solver/diffsl.rs @@ -21,7 +21,7 @@ pub type T = f64; /// # Example /// /// ```rust -/// use diffsol::{OdeBuilder, Bdf, OdeSolverState, OdeSolverMethod, DiffSlContext, diffsl::LlvmModule}; +/// use diffsol::{OdeBuilder, Bdf, OdeSolverState, OdeSolverMethod, DiffSlContext, DiffSl, diffsl::LlvmModule}; /// /// // dy/dt = -ay /// // y(0) = 1 @@ -32,10 +32,11 @@ pub type T = f64; /// F { -a*u } /// out { u } /// ").unwrap(); +/// let eqn = DiffSl::from_context(context); /// let problem = OdeBuilder::new() /// .rtol(1e-6) /// .p([0.1]) -/// .build_diffsl(&context).unwrap(); +/// .build_from_eqn(eqn).unwrap(); /// let mut solver = Bdf::default(); /// let t = 0.4; /// let state = OdeSolverState::new(&problem, &solver).unwrap(); @@ -136,14 +137,15 @@ impl, CG: CodegenModule> DiffSl { ret.rhs_coloring = Some(coloring); ret.rhs_sparsity = Some(sparsity); - let op = ret.mass().unwrap(); - let non_zeros = find_matrix_non_zeros(&op, t0); - let sparsity = - M::Sparsity::try_from_indices(op.nout(), op.nstates(), non_zeros.clone()) - .expect("invalid sparsity pattern"); - let coloring = JacobianColoring::new(&sparsity, &non_zeros); - ret.mass_coloring = Some(coloring); - ret.mass_sparsity = Some(sparsity); + if let Some(op) = ret.mass() { + let non_zeros = find_matrix_non_zeros(&op, t0); + let sparsity = + M::Sparsity::try_from_indices(op.nout(), op.nstates(), non_zeros.clone()) + .expect("invalid sparsity pattern"); + let coloring = JacobianColoring::new(&sparsity, &non_zeros); + ret.mass_coloring = Some(coloring); + ret.mass_sparsity = Some(sparsity); + } } ret } @@ -395,7 +397,7 @@ impl, CG: CodegenModule> OdeEquations for DiffSl { } fn mass(&self) -> Option> { - Some(DiffSlMass(self)) + self.context.compiler.has_mass().then_some(DiffSlMass(self)) } fn root(&self) -> Option> { @@ -466,8 +468,8 @@ mod tests { let k = 1.0; let r = 1.0; let context = DiffSlContext::, CG>::new(text).unwrap(); - let mut eqn = DiffSl::from_context(context); let p = DVector::from_vec(vec![r, k]); + let mut eqn = DiffSl::from_context(context); eqn.set_params(Rc::new(p)); // test that the initial values look ok @@ -489,10 +491,7 @@ mod tests { mass_y.assert_eq_st(&mass_y_expect, 1e-10); // solver a bit and check the state and output - let problem = OdeBuilder::new() - .p([r, k]) - .build_from_eqn(Rc::new(eqn)) - .unwrap(); + let problem = OdeBuilder::new().p([r, k]).build_from_eqn(eqn).unwrap(); let mut solver = Bdf::default(); let t = 1.0; let state = OdeSolverState::new(&problem, &solver).unwrap(); diff --git a/src/ode_solver/equations.rs b/src/ode_solver/equations.rs index 418d37c..2b762a0 100644 --- a/src/ode_solver/equations.rs +++ b/src/ode_solver/equations.rs @@ -332,7 +332,7 @@ impl OdeEquationsAdjoint for T where /// let p = Rc::new(V::from_vec(vec![])); /// let eqn = OdeSolverEquations::new(rhs, mass, root, init, out, p); /// -/// let problem = OdeBuilder::new().build_from_eqn(Rc::new(eqn)).unwrap(); +/// let problem = OdeBuilder::new().build_from_eqn(eqn).unwrap(); /// /// let mut solver = Bdf::default(); /// let t = 0.4; diff --git a/src/ode_solver/sdirk.rs b/src/ode_solver/sdirk.rs index 7fd9f2b..38d56e9 100644 --- a/src/ode_solver/sdirk.rs +++ b/src/ode_solver/sdirk.rs @@ -1127,7 +1127,6 @@ mod test { let (problem, soln) = exponential_decay_problem::(false); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 4 number_of_steps: 29 number_of_error_test_failures: 0 @@ -1135,7 +1134,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 118 number_of_jac_muls: 2 number_of_matrix_evals: 1 @@ -1149,7 +1147,6 @@ mod test { let (problem, soln) = exponential_decay_problem_sens::(false); test_ode_solver(&mut s, &problem, soln, None, false, true); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 7 number_of_steps: 52 number_of_error_test_failures: 0 @@ -1157,7 +1154,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 210 number_of_jac_muls: 318 number_of_matrix_evals: 2 @@ -1171,7 +1167,6 @@ mod test { let (problem, soln) = exponential_decay_problem::(false); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 3 number_of_steps: 13 number_of_error_test_failures: 0 @@ -1179,7 +1174,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 86 number_of_jac_muls: 2 number_of_matrix_evals: 1 @@ -1193,7 +1187,6 @@ mod test { let (problem, soln) = exponential_decay_problem_sens::(false); test_ode_solver(&mut s, &problem, soln, None, false, true); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 5 number_of_steps: 20 number_of_error_test_failures: 0 @@ -1201,7 +1194,6 @@ mod test { number_of_nonlinear_solver_fails: 0 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 122 number_of_jac_muls: 201 number_of_matrix_evals: 1 @@ -1215,14 +1207,12 @@ mod test { let (problem, soln) = exponential_decay_problem_adjoint::(); let adjoint_solver = test_ode_solver_adjoint(s, &problem, soln); insta::assert_yaml_snapshot!(problem.eqn.rhs().statistics(), @r###" - --- number_of_calls: 196 number_of_jac_muls: 6 number_of_matrix_evals: 3 number_of_jac_adj_muls: 599 "###); insta::assert_yaml_snapshot!(adjoint_solver.get_statistics(), @r###" - --- number_of_linear_solver_setups: 18 number_of_steps: 29 number_of_error_test_failures: 10 @@ -1237,14 +1227,12 @@ mod test { let (problem, soln) = exponential_decay_with_algebraic_adjoint_problem::(); let adjoint_solver = test_ode_solver_adjoint(s, &problem, soln); insta::assert_yaml_snapshot!(problem.eqn.rhs().statistics(), @r###" - --- number_of_calls: 171 number_of_jac_muls: 12 number_of_matrix_evals: 4 number_of_jac_adj_muls: 287 "###); insta::assert_yaml_snapshot!(adjoint_solver.get_statistics(), @r###" - --- number_of_linear_solver_setups: 18 number_of_steps: 20 number_of_error_test_failures: 11 @@ -1259,7 +1247,6 @@ mod test { let (problem, soln) = robertson::(false); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 97 number_of_steps: 232 number_of_error_test_failures: 0 @@ -1267,7 +1254,6 @@ mod test { number_of_nonlinear_solver_fails: 18 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 1924 number_of_jac_muls: 36 number_of_matrix_evals: 12 @@ -1281,7 +1267,6 @@ mod test { let (problem, soln) = robertson_sens::(); test_ode_solver(&mut s, &problem, soln, None, false, true); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 112 number_of_steps: 216 number_of_error_test_failures: 0 @@ -1289,7 +1274,6 @@ mod test { number_of_nonlinear_solver_fails: 37 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 1420 number_of_jac_muls: 3277 number_of_matrix_evals: 27 @@ -1303,7 +1287,6 @@ mod test { let (problem, soln) = robertson::(false); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 100 number_of_steps: 141 number_of_error_test_failures: 0 @@ -1311,7 +1294,6 @@ mod test { number_of_nonlinear_solver_fails: 24 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 1796 number_of_jac_muls: 54 number_of_matrix_evals: 18 @@ -1325,7 +1307,6 @@ mod test { let (problem, soln) = robertson_sens::(); test_ode_solver(&mut s, &problem, soln, None, false, true); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 114 number_of_steps: 131 number_of_error_test_failures: 0 @@ -1333,7 +1314,6 @@ mod test { number_of_nonlinear_solver_fails: 44 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 1492 number_of_jac_muls: 3136 number_of_matrix_evals: 33 @@ -1347,7 +1327,6 @@ mod test { let (problem, soln) = robertson_ode::(false, 1); test_ode_solver_no_sens(&mut s, &problem, soln, None, false); insta::assert_yaml_snapshot!(s.get_statistics(), @r###" - --- number_of_linear_solver_setups: 113 number_of_steps: 304 number_of_error_test_failures: 1 @@ -1355,7 +1334,6 @@ mod test { number_of_nonlinear_solver_fails: 15 "###); insta::assert_yaml_snapshot!(problem.eqn.as_ref().rhs().statistics(), @r###" - --- number_of_calls: 2603 number_of_jac_muls: 39 number_of_matrix_evals: 13 diff --git a/src/ode_solver/test_models/foodweb.rs b/src/ode_solver/test_models/foodweb.rs index 0486294..51feb11 100644 --- a/src/ode_solver/test_models/foodweb.rs +++ b/src/ode_solver/test_models/foodweb.rs @@ -141,7 +141,7 @@ where let problem = OdeBuilder::new() .rtol(1e-5) .atol([1e-5]) - .build_from_eqn(Rc::new(eqn)) + .build_from_eqn(eqn) .unwrap(); let soln = soln::(); (problem, soln) diff --git a/src/ode_solver/test_models/heat2d.rs b/src/ode_solver/test_models/heat2d.rs index 5b9f010..3306f74 100644 --- a/src/ode_solver/test_models/heat2d.rs +++ b/src/ode_solver/test_models/heat2d.rs @@ -95,7 +95,7 @@ pub fn heat2d_diffsl_problem< let problem = OdeBuilder::new() .rtol(1e-7) .atol([1e-7]) - .build_from_eqn(std::rc::Rc::new(eqn)) + .build_from_eqn(eqn) .unwrap(); let soln = soln::(); (problem, soln) diff --git a/src/ode_solver/test_models/robertson.rs b/src/ode_solver/test_models/robertson.rs index 00deb57..b3ee42e 100644 --- a/src/ode_solver/test_models/robertson.rs +++ b/src/ode_solver/test_models/robertson.rs @@ -56,7 +56,7 @@ pub fn robertson_diffsl_problem< .p([0.04, 1.0e4, 3.0e7]) .rtol(1e-4) .atol([1.0e-8, 1.0e-6, 1.0e-6]) - .build_from_eqn(Rc::new(eqn)) + .build_from_eqn(eqn) .unwrap(); let mut soln = soln::(); soln.rtol = problem.rtol;