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()
    }
示例#3
0
    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;
    }