#include "intervention.h" bool executeInterventions(InterventionsInfo& iif, UserVarsInfo& uvif, double &totPopSize, double ¤tTime, const fitnessEffectsAll& fitnessEffects, std::vector<Genotype> Genotypes, std::vector<spParamsP>& popParams){ // Now we add all the info needed for the symbol table so exprtk can operate symbol_table_t symbol_table; for(auto& iterator : uvif.userVars) { symbol_table.add_variable(iterator.first, iterator.second); } for(auto& iterator : iif.mapGenoToPop) { symbol_table.add_variable(iterator.first, iterator.second); } double N = totPopSize; if(N == 0){ throw std::invalid_argument("Total Population = 0. There is nothing to intervene.\n"); } double T = currentTime; symbol_table.add_constant("N", N);//We reserve N to total population size symbol_table.add_constant("T", T); //Pass current time to exprtk symbol_table.add_constants(); expression_t expression; expression.register_symbol_table(symbol_table); bool interventionDone = false; //we iterate over the user-specified interventions for(auto& intervention: iif.interventions){ parser_t parser_trigger; //if parser fails to compile, throws exception if (!parser_trigger.compile(intervention.trigger, expression)){ // error control, just in case the parsing it's not correct Rcpp::Rcout << "\nexprtk parser error: \n" << std::endl; for (std::size_t i = 0; i < parser_trigger.error_count(); ++i){ typedef exprtk::parser_error::type error_t; error_t error = parser_trigger.get_error(i); // FIXMEmaybe: Use warning or error to capture it easily in tests? REprintf("Error[%02zu] Position: %02zu Type: [%14s] Msg: %s Expression: %s\n", i, error.token.position, exprtk::parser_error::to_str(error.mode).c_str(), error.diagnostic.c_str(), intervention.trigger.c_str()); } std::string errorMessage = "The expression was imposible to parse."; throw std::invalid_argument(errorMessage); } else { //a trigger is just a TRUE/FALSE condition if(expression.value() == 1){ parser_t parser_wh; if(intervention.repetitions >= 0 && intervention.periodicity == NOT_PERIODICITY){ // case where interventions are based only in repetitions //if parser fails to compile, throws exception if (!parser_wh.compile(intervention.what_happens, expression)){ // error control, just in case the parsing it's not correct Rcpp::Rcout << "\nexprtk parser error: \n" << std::endl; for (std::size_t i = 0; i < parser_wh.error_count(); ++i){ typedef exprtk::parser_error::type error_t; error_t error = parser_wh.get_error(i); // FIXMEmaybe: Use warning or error to capture it easily in tests? REprintf("Error[%02zu] Position: %02zu Type: [%14s] Msg: %s Expression: %s\n", i, error.token.position, exprtk::parser_error::to_str(error.mode).c_str(), error.diagnostic.c_str(), intervention.what_happens.c_str()); } std::string errorMessage = "The expression was imposible to parse."; throw std::invalid_argument(errorMessage); } else parseWhatHappens(iif, uvif, intervention, N, T); // we reduce by one the number of interventions intervention.repetitions--; // we update the last time it was executed (debugging purposes) intervention.lastTimeExecuted = T; // we update interventionDone flag interventionDone = true; } else if(intervention.repetitions >= 0 && intervention.periodicity > 0) { // case there is periodicity but also repetitions if((T - intervention.lastTimeExecuted) >= intervention.periodicity){ // with condition satisfied we execute the intervention if (!parser_wh.compile(intervention.what_happens, expression)){ Rcpp::Rcout << "\nexprtk parser error: \n" << std::endl; for (std::size_t i = 0; i < parser_wh.error_count(); ++i){ typedef exprtk::parser_error::type error_t; error_t error = parser_wh.get_error(i); // FIXMEmaybe: Use warning or error to capture it easily in tests? REprintf("Error[%02zu] Position: %02zu Type: [%14s] Msg: %s Expression: %s\n", i, error.token.position, exprtk::parser_error::to_str(error.mode).c_str(), error.diagnostic.c_str(), intervention.what_happens.c_str()); } std::string errorMessage = "The expression was imposible to parse."; throw std::invalid_argument(errorMessage); } else parseWhatHappens(iif, uvif, intervention, N, T); // update new lastTimeExecuted intervention.lastTimeExecuted = T; // update amount of repetitions intervention.repetitions--; // we update interventionDone flag interventionDone = true; } } else if (intervention.periodicity > 0 && intervention.repetitions == NOT_REPS) { // case where only periodicty is specified if((T - intervention.lastTimeExecuted) >= intervention.periodicity){ if (!parser_wh.compile(intervention.what_happens, expression)){ Rcpp::Rcout << "\nexprtk parser error: \n" << std::endl; for (std::size_t i = 0; i < parser_wh.error_count(); ++i){ typedef exprtk::parser_error::type error_t; error_t error = parser_wh.get_error(i); // FIXMEmaybe: Use warning or error to capture it easily in tests? REprintf("Error[%02zu] Position: %02zu Type: [%14s] Msg: %s Expression: %s\n", i, error.token.position, exprtk::parser_error::to_str(error.mode).c_str(), error.diagnostic.c_str(), intervention.what_happens.c_str()); } std::string errorMessage = "The expression was imposible to parse."; throw std::invalid_argument(errorMessage); } else parseWhatHappens(iif, uvif, intervention, N, T); // update new lastTimeExecuted intervention.lastTimeExecuted = T; // we update interventionDone flag interventionDone = true; } } } } } // Now with the structure storing all the changes, we need to store the data in their own // original structures where the data was sourced from // once the structure is updated, we update the structures that store the info while the simulation is running if(interventionDone){ if(!updatePopulations(iif, fitnessEffects, Genotypes, popParams)){ throw std::runtime_error("There was an issue updating the populations while intervening.\n"); } return true; } return false; }