@@ -478,7 +478,7 @@ void calculate_mobility_returns(Eigen::Ref<typename TimeSeries<FP>::Vector> mobi
478478 * detect a get_infections_relative function for the Model type.
479479 */
480480template <typename FP, class Sim >
481- using get_infections_relative_expr_t = decltype (get_infections_relative(
481+ using get_infections_relative_expr_t = decltype (get_infections_relative<FP> (
482482 std::declval<const Sim&>(), std::declval<FP>(), std::declval<const Eigen::Ref<const Eigen::VectorX<FP>>&>()));
483483
484484/* *
@@ -490,26 +490,25 @@ using get_infections_relative_expr_t = decltype(get_infections_relative(
490490 * @param y the current value of the simulation.
491491 * @param t the current simulation time
492492 */
493- template <typename FP, class Sim ,
494- std::enable_if_t <!is_expression_valid<get_infections_relative_expr_t , Sim>::value, void *> = nullptr >
495- FP get_infections_relative (const SimulationNode<FP, Sim>& /* node*/ , FP /* t*/ ,
496- const Eigen::Ref<const Eigen::VectorX<FP>>& /* y*/ )
497- {
498- assert (false && " Overload get_infections_relative for your own model/simulation if you want to use dynamic NPIs." );
499- return 0 ;
500- }
501- template <typename FP, class Sim ,
502- std::enable_if_t <is_expression_valid<get_infections_relative_expr_t , Sim>::value, void *> = nullptr >
493+ template <typename FP, class Sim >
503494FP get_infections_relative (const SimulationNode<FP, Sim>& node, FP t, const Eigen::Ref<const Eigen::VectorX<FP>>& y)
504495{
505- return get_infections_relative<FP, Sim>(node.get_simulation (), t, y);
496+ if constexpr (is_expression_valid<get_infections_relative_expr_t , FP, Sim>::value) {
497+ return get_infections_relative<FP>(node.get_simulation (), t, y);
498+ }
499+ else {
500+ mio::unused (node, t, y);
501+ mio::log_debug (" get_infections_relative called without specialization for this simulation type. "
502+ " Implement an overload in your model if you intend to use dynamic NPIs." );
503+ return FP{0 };
504+ }
506505}
507506
508507/* *
509508 * detect a get_mobility_factors function for the Model type.
510509 */
511510template <typename FP, class Sim >
512- using get_mobility_factors_expr_t = decltype (get_mobility_factors(
511+ using get_mobility_factors_expr_t = decltype (get_mobility_factors<FP> (
513512 std::declval<const Sim&>(), std::declval<FP>(), std::declval<const Eigen::Ref<const Eigen::VectorX<FP>>&>()));
514513
515514/* *
@@ -523,26 +522,26 @@ using get_mobility_factors_expr_t = decltype(get_mobility_factors(
523522 * @param t the current simulation time
524523 * @return a vector expression, same size as y, with the factor for each compartment.
525524 */
526- template <typename FP, class Sim ,
527- std::enable_if_t <!is_expression_valid<get_mobility_factors_expr_t , Sim>::value, void *> = nullptr >
528- auto get_mobility_factors (const SimulationNode<FP, Sim>& /* node*/ , FP /* t*/ ,
529- const Eigen::Ref<const Eigen::VectorX<FP>>& y)
530- {
531- return Eigen::VectorX<FP>::Ones (y.rows ());
532- }
533- template <typename FP, class Sim ,
534- std::enable_if_t <is_expression_valid<get_mobility_factors_expr_t , Sim>::value, void *> = nullptr >
525+ template <typename FP, class Sim >
535526auto get_mobility_factors (const SimulationNode<FP, Sim>& node, FP t, const Eigen::Ref<const Eigen::VectorX<FP>>& y)
536527{
537- return get_mobility_factors<FP, Sim>(node.get_simulation (), t, y);
528+ if constexpr (is_expression_valid<get_mobility_factors_expr_t , FP, Sim>::value) {
529+ return get_mobility_factors<FP>(node.get_simulation (), t, y);
530+ }
531+ else {
532+ mio::unused (node, t);
533+ mio::log_debug (" get_mobility_factors called without specialization for this simulation type. "
534+ " Using default mobility factor (1.0) for all compartments." );
535+ return Eigen::VectorX<FP>::Ones (y.rows ());
536+ }
538537}
539538
540539/* *
541540 * detect a get_mobility_factors function for the Model type.
542541 */
543542template <typename FP, class Sim >
544- using test_commuters_expr_t = decltype (test_commuters(
545- std::declval<Sim&>(), std::declval<Eigen::Ref<const Eigen::VectorX<FP>>& >(), std::declval<FP>()));
543+ using test_commuters_expr_t = decltype (test_commuters<FP> (
544+ std::declval<Sim&>(), std::declval<Eigen::Ref<Eigen::VectorX<FP>>>(), std::declval<FP>()));
546545
547546/* *
548547 * Test persons when moving from their source node.
@@ -554,17 +553,17 @@ using test_commuters_expr_t = decltype(test_commuters(
554553 * @param mobile_population mutable reference to vector of persons per compartment that change nodes.
555554 * @param t the current simulation time.
556555 */
557- template <typename FP, class Sim ,
558- std::enable_if_t <!is_expression_valid<test_commuters_expr_t , Sim>::value, void *> = nullptr >
559- void test_commuters (SimulationNode<FP, Sim>& /* node*/ , Eigen::Ref<Eigen::VectorX<FP>> /* mobile_population*/ ,
560- FP /* time*/ )
561- {
562- }
563- template <typename FP, class Sim ,
564- std::enable_if_t <is_expression_valid<test_commuters_expr_t , Sim>::value, void *> = nullptr >
556+ template <typename FP, class Sim >
565557void test_commuters (SimulationNode<FP, Sim>& node, Eigen::Ref<Eigen::VectorX<FP>> mobile_population, FP time)
566558{
567- return test_commuters<FP, Sim>(node.get_simulation (), mobile_population, time);
559+ if constexpr (is_expression_valid<test_commuters_expr_t , FP, Sim>::value) {
560+ test_commuters<FP>(node.get_simulation (), mobile_population, time);
561+ }
562+ else {
563+ mio::unused (node, mobile_population, time);
564+ mio::log_debug (" test_commuters called without specialization for this simulation type. "
565+ " Implement an overload in your model if you intend to use commuter testing." );
566+ }
568567}
569568
570569template <typename FP>
@@ -581,7 +580,7 @@ void mio::MobilityEdge<FP>::apply_mobility(FP t, FP dt, SimulationNode<FP, Sim>&
581580 if (dyn_npis.get_thresholds ().size () > 0 &&
582581 floating_point_greater_equal<FP>(t, m_t_last_dynamic_npi_check + dyn_npis.get_interval ().get ())) {
583582 auto inf_rel =
584- get_infections_relative<FP, Sim >(node_from, t, node_from.get_last_state ()) * dyn_npis.get_base_value ();
583+ get_infections_relative<FP>(node_from, t, node_from.get_last_state ()) * dyn_npis.get_base_value ();
585584 auto exceeded_threshold = dyn_npis.get_max_exceeded_threshold (inf_rel);
586585 if (exceeded_threshold != dyn_npis.get_thresholds ().end () &&
587586 (exceeded_threshold->first > m_dynamic_npi.first ||
@@ -602,8 +601,8 @@ void mio::MobilityEdge<FP>::apply_mobility(FP t, FP dt, SimulationNode<FP, Sim>&
602601 if (m_return_times.get_time (i) <= t) {
603602 auto v0 = find_value_reverse<FP>(node_to.get_result (), m_mobile_population.get_time (i), 1e-10 , 1e-10 );
604603 assert (v0 != node_to.get_result ().rend () && " unexpected error." );
605- calculate_mobility_returns<FP, Sim >(m_mobile_population[i], node_to.get_simulation (), *v0,
606- m_mobile_population.get_time (i), dt);
604+ calculate_mobility_returns<FP>(m_mobile_population[i], node_to.get_simulation (), *v0,
605+ m_mobile_population.get_time (i), dt);
607606
608607 // the lower-order return calculation may in rare cases produce negative compartments,
609608 // especially at the beginning of the simulation.
0 commit comments