void StandardInterventionDistributionEventCoordinator::formatInterventionClassNames( std::ostringstream& intervention_name, json::QuickInterpreter* actual_intervention_config) { if ( actual_intervention_config->Exist("Actual_Intervention_Config") ) { // find actual_intervention_config if it exists actual_intervention_config = &( (*actual_intervention_config)["Actual_Intervention_Config"] ); // append class name to intervention name intervention_name << " -> " << std::string( (*actual_intervention_config)["class"].As<json::String>() ); // keep looking recursively for more actual_intervention_config layers formatInterventionClassNames( intervention_name, actual_intervention_config ); } else if ( actual_intervention_config->Exist("Actual_Intervention_Configs") ) { // maybe it was an array of actual interventions const json::Array& actual_interventions_array = (*actual_intervention_config)["Actual_Intervention_Configs"].As<json::Array>(); // loop over array intervention_name << " -> "; int array_size = actual_interventions_array.Size(); for( int idx = 0; idx < array_size; idx++ ) { if( idx == 0 && array_size > 1 ) intervention_name << "[ "; else if ( idx > 0 ) intervention_name << ", "; // accumulate individual class names const json::Object& actual_intervention = json_cast<const json::Object&>( actual_interventions_array[idx] ); actual_intervention_config = &json::QuickInterpreter(actual_intervention); intervention_name << std::string( (*actual_intervention_config)["class"].As<json::String>() ); // recursively search for each for more layers! formatInterventionClassNames( intervention_name, actual_intervention_config ); } if( array_size > 1 ) intervention_name << " ]"; } else if ( actual_intervention_config->Exist("Positive_Diagnosis_Config") ) { // maybe it was a diagnostic with positive_diagnosis_config if it exists (TODO: can this part be merged with the acutal_intervention_config block?) actual_intervention_config = &( (*actual_intervention_config)["Positive_Diagnosis_Config"] ); // append class name to intervention name intervention_name << " -> " << std::string( (*actual_intervention_config)["class"].As<json::String>() ); // keep looking recursively for more actual_intervention_config layers formatInterventionClassNames( intervention_name, actual_intervention_config ); } else { // end of recursive call } }
void StandardInterventionDistributionEventCoordinator::UpdateNodes( float dt ) { // Only call VisitNodes on first call and if countdown == 0 if( tsteps_since_last != tsteps_between_reps ) { return; } int limitPerNode = -1; // intervention class names for informative logging std::ostringstream intervention_name; intervention_name << std::string( json::QuickInterpreter(intervention_config._json)["class"].As<json::String>() ); auto qi_as_config = Configuration::CopyFromElement( (intervention_config._json) ); _di = InterventionFactory::getInstance()->CreateIntervention(qi_as_config); // including deeper information for "distributing" interventions (e.g. calendars) formatInterventionClassNames( intervention_name, &json::QuickInterpreter(intervention_config._json) ); // Only visit individuals if this is NOT an NTI. Check... // Check to see if intervention is an INodeDistributable... INodeDistributableIntervention *ndi = InterventionFactory::getInstance()->CreateNDIIntervention(qi_as_config); INodeDistributableIntervention *ndi2 = nullptr; //LOG_DEBUG_F("[UpdateNodes] limitPerNode = %d\n", limitPerNode); LOG_DEBUG_F("[UpdateNodes] visiting %d nodes per NodeSet\n", cached_nodes.size()); for (auto event_context : cached_nodes) { if( ndi ) { ndi2 = InterventionFactory::getInstance()->CreateNDIIntervention(qi_as_config); if(ndi2) { if( ndi2->Distribute( event_context, this ) ) { LOG_INFO_F("UpdateNodes() distributed '%s' intervention to node %d\n", intervention_name.str().c_str(), event_context->GetId().data ); } ndi2->Release(); } } else { preDistribute(); // For now, distribute evenly across nodes. int totalIndivGivenIntervention = event_context->VisitIndividuals( this, limitPerNode ); // Create log message std::stringstream ss; ss << "UpdateNodes() gave out " << totalIndivGivenIntervention << " '" << intervention_name.str().c_str() << "' interventions "; std::string restriction_str = demographic_restrictions.GetPropertyRestrictionsAsString(); if( !restriction_str.empty() ) { ss << " with property restriction(s) " << restriction_str << " " ; } ss << "at node " << event_context->GetId().data << "\n" ; LOG_INFO( ss.str().c_str() ); } } delete qi_as_config; qi_as_config = nullptr; if(ndi) { ndi->Release(); } tsteps_since_last = 0; num_repetitions--; if( num_repetitions == 0 ) { distribution_complete = true; // we're done, signal disposal ok } //distribution_complete = true; // we're done, signal disposal ok // this signals each process individually that its ok to clean up, in general if the completion times might be different on different nodes // we'd want to coordinate the cleanup signal in Update() }
void CalendarEventCoordinator::UpdateNodes( float dt ) { // Now issue events as they come up, including anything currently in the past or present while( parent->GetSimulationTime().time >= times_and_coverages.begin()->first) { int grandTotal = 0; int limitPerNode = -1; // intervention class names for informative logging std::ostringstream intervention_name; intervention_name << std::string( json::QuickInterpreter(intervention_config._json)["class"].As<json::String>() ); auto qi_as_config = Configuration::CopyFromElement( (intervention_config._json), "campaign" ); _di = InterventionFactory::getInstance()->CreateIntervention(qi_as_config); // including deeper information for "distributing" interventions (e.g. calendars) formatInterventionClassNames( intervention_name, &json::QuickInterpreter(intervention_config._json) ); // Only visit individuals if this is NOT an NTI. Check... // Check to see if intervention is an INodeDistributable... INodeDistributableIntervention *ndi = InterventionFactory::getInstance()->CreateNDIIntervention(qi_as_config); INodeDistributableIntervention *ndi2 = nullptr; LOG_DEBUG_F("[UpdateNodes] limitPerNode = %d\n", limitPerNode); for (auto nec : cached_nodes) { if (ndi) { throw NotYetImplementedException( __FILE__, __LINE__, __FUNCTION__ ); #if 0 ndi2 = InterventionFactory::getInstance()->CreateNDIIntervention( qi_as_config ); if(ndi2) { float duration = -1; if (times_and_coverages.size() > 1) { auto iter = times_and_coverages.end(); //A node-targeted intervention issued through the calender coordinator lasts until the next NDI. //Is there an overlap of one day here? Should there be a -1? duration = (float)(prev(iter,2)->first - prev(iter, 1)->first); } INodeDistributableInterventionParameterSetterInterface* pNDIPSI = nullptr; if (s_OK == ndi2->QueryInterface(GET_IID(INodeDistributableInterventionParameterSetterInterface), (void**)&pNDIPSI) ) { pNDIPSI->SetDemographicCoverage(times_and_coverages.begin()->second); pNDIPSI->SetMaxDuration(duration); } if (!ndi2->Distribute( nec, this ) ) { LOG_INFO_F("UpdateNodes() distributed '%s' intervention to node %d\n", intervention_name.str().c_str(), nec->GetId().data ); } ndi2->Release(); } #endif } else { try { // For now, distribute evenly across nodes. int totalIndivGivenIntervention = nec->VisitIndividuals( this, limitPerNode ); grandTotal += totalIndivGivenIntervention; LOG_INFO_F( "UpdateNodes() gave out %d interventions at node %d\n", totalIndivGivenIntervention, nec->GetId().data ); } catch( const json::Exception &e ) { throw GeneralConfigurationException( __FILE__, __LINE__, __FUNCTION__, e.what() ); } } } delete qi_as_config; qi_as_config = nullptr; times_and_coverages.erase(times_and_coverages.begin()); LOG_DEBUG_F("%d Distributions remaining from CalendarEventCoordinator\n", times_and_coverages.size()); if( times_and_coverages.empty() ) { LOG_DEBUG_F("Signaling for disposal of CalendarEventCoordinator\n"); distribution_complete = true; // we're done, signal disposal ok break; } } return; }