void HIVDelayedIntervention::Update(float dt) { if( !DelayedIntervention::UpdateIndividualsInterventionStatus() ) { return; } days_remaining -= dt; if( days_remaining < 0 ) { expired = true; INodeTriggeredInterventionConsumer* broadcaster = nullptr; if (s_OK != parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&broadcaster)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } if( !broadcast_on_expiration_event.IsUninitialized() ) { broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), broadcast_on_expiration_event ); } LOG_DEBUG_F("broadcast on expiration event\n"); LOG_DEBUG_F("expiring before delay-triggered intervention\n"); return; } remaining_delay_days.Decrement( dt ); }
void DiagnosticTreatNeg::onPatientDefault() { LOG_DEBUG_F( "Individual %d got the test but defaulted, receiving Defaulters intervention without waiting for days_to_diagnosis (actually means days_to_intervention) \n", parent->GetSuid().data ); // Important: Use the instance method to obtain the intervention factory obj instead of static method to cross the DLL boundary IGlobalContext *pGC = nullptr; const IInterventionFactory* ifobj = nullptr; if (s_OK == parent->QueryInterface(GET_IID(IGlobalContext), (void**)&pGC)) { ifobj = pGC->GetInterventionFactory(); } if (!ifobj) { throw NullPointerException( __FILE__, __LINE__, __FUNCTION__, "parent->GetInterventionFactoryObj()" ); } if( !defaulters_event.IsUninitialized() ) { if( defaulters_event != NO_TRIGGER_STR ) { INodeTriggeredInterventionConsumer* broadcaster = nullptr; if (s_OK != parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&broadcaster)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } broadcaster->TriggerNodeEventObserversByString( parent->GetEventContext(), defaulters_event ); } } else if( defaulters_config._json.Type() != ElementType::NULL_ELEMENT ) { auto tmp_config = Configuration::CopyFromElement(defaulters_config._json); // Distribute the defaulters intervention, right away (do not use the days_to_diagnosis IDistributableIntervention *di = const_cast<IInterventionFactory*>(ifobj)->CreateIntervention( tmp_config ); delete tmp_config; tmp_config = nullptr; ICampaignCostObserver* pICCO; // Now make sure cost of the test-positive intervention is reported back to node if (s_OK == parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(ICampaignCostObserver), (void**)&pICCO) ) { di->Distribute( parent->GetInterventionsContext(), pICCO ); pICCO->notifyCampaignEventOccurred( (IBaseIntervention*)di, (IBaseIntervention*)this, parent ); } else { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "ICampaignCostObserver", "INodeEventContext" ); } } else { throw GeneralConfigurationException( __FILE__, __LINE__, __FUNCTION__, "neither event or config defined" ); } }
void HIVInterventionsContainer::OnTestForHIV(bool test_result) { if( test_result && !ever_tested_HIV_positive) { INodeTriggeredInterventionConsumer* broadcaster = nullptr; if (s_OK != parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&broadcaster)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), EventTrigger::HIVNewlyDiagnosed ); } ever_tested = true; if (test_result) { ever_tested_HIV_positive = true; } float t = parent->GetEventContext()->GetNodeEventContext()->GetTime().time; time_of_most_recent_test = t; time_last_seen_by_healthcare = t; }
bool HIVSimpleDiagnostic::AbortDueToCurrentCascadeState() { IHIVCascadeOfCare *ihcc = nullptr; if ( s_OK != parent->GetInterventionsContext()->QueryInterface(GET_IID(IHIVCascadeOfCare), (void **)&ihcc) ) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetInterventionsContext()", "IHIVCascadeOfCare", "IIndividualHumanInterventionsContext" ); } std::string currentState = ihcc->getCascadeState(); if ( abortStates.find(currentState) != abortStates.end() ) { // Duplicated from SimpleDiagnostic::positiveTestDistribute INodeTriggeredInterventionConsumer* broadcaster = nullptr; if (s_OK != parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&broadcaster)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), IndividualEventTriggerType::CascadeStateAborted ); LOG_DEBUG_F("The current cascade state \"%s\" is one of the Abort_States. Expiring the diagnostic for individual %d.\n", currentState.c_str(), parent->GetSuid().data ); expired = true; return true; } return false; }
bool NodeLevelHealthTriggeredIV::Distribute( INodeEventContext *pNodeEventContext, IEventCoordinator2 *pEC ) { bool was_distributed = BaseNodeIntervention::Distribute(pNodeEventContext, pEC); if (was_distributed) { LOG_DEBUG_F("Distributed Nodelevel health-triggered intervention to NODE: %d\n", pNodeEventContext->GetId().data); // QI to register ourself as a NodeLevelHealthTriggeredIV observer INodeTriggeredInterventionConsumer * pNTIC = nullptr; if (s_OK != pNodeEventContext->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&pNTIC)) { throw QueryInterfaceException(__FILE__, __LINE__, __FUNCTION__, "pNodeEventContext", "INodeTriggeredInterventionConsumer", "INodeEventContext"); } release_assert(pNTIC); for (auto &trigger : m_trigger_conditions) { pNTIC->RegisterNodeEventObserver((IIndividualEventObserver*)this, trigger); } } return was_distributed; }
void CommunityHealthWorkerEventCoordinator::UnregisterForEvents( INodeEventContext* pNEC ) { INodeTriggeredInterventionConsumer* pNTIC = GetNodeTriggeredConsumer( pNEC ); for( auto& trigger : m_TriggerConditionList ) { pNTIC->UnregisterNodeEventObserver( this, trigger ); } }
void DiagnosticTreatNeg::negativeTestDistribute() { LOG_DEBUG_F( "Individual %d tested 'negative', receiving negative intervention.\n", parent->GetSuid().data ); // Important: Use the instance method to obtain the intervention factory obj instead of static method to cross the DLL boundary IGlobalContext *pGC = nullptr; const IInterventionFactory* ifobj = nullptr; if (s_OK == parent->QueryInterface(GET_IID(IGlobalContext), (void**)&pGC)) { ifobj = pGC->GetInterventionFactory(); } if (!ifobj) { throw NullPointerException( __FILE__, __LINE__, __FUNCTION__, "parent->GetInterventionFactoryObj()" ); } if( use_event_or_config == EventOrConfig::Event ) { INodeTriggeredInterventionConsumer* broadcaster = nullptr; if (s_OK != parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&broadcaster)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), negative_diagnosis_event ); } else if( negative_diagnosis_config._json.Type() != ElementType::NULL_ELEMENT ) { auto tmp_config = Configuration::CopyFromElement( negative_diagnosis_config._json, "campaign" ); // Distribute the test-negative intervention IDistributableIntervention *di = const_cast<IInterventionFactory*>(ifobj)->CreateIntervention( tmp_config ); delete tmp_config; tmp_config = nullptr; ICampaignCostObserver* pICCO; // Now make sure cost of the test-positive intervention is reported back to node if (s_OK == parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(ICampaignCostObserver), (void**)&pICCO) ) { di->Distribute( parent->GetInterventionsContext(), pICCO ); pICCO->notifyCampaignEventOccurred( (IBaseIntervention*)di, (IBaseIntervention*)this, parent ); } else { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "ICampaignCostObserver", "INodeEventContext" ); } } else { throw GeneralConfigurationException( __FILE__, __LINE__, __FUNCTION__, "neither event or config defined" ); } expired = true; }
void PropertyValueChanger::Update( float dt ) { release_assert( expired == false ); release_assert( ibc ); std::string current_prop_value = ""; if( reversion_timer > 0 ) { reversion_timer -= dt; if( reversion_timer <= 0 ) { LOG_DEBUG_F( "Time to revert PropertyValueChanger.\n" ); probability = 1.0; } } if( probability == 1.0 || action_timer < 0 ) { if( revert ) { // Need to ask individual (parent's parent) for current value of this property // TBD: use QI not static cast auto props = static_cast<InterventionsContainer*>(ibc)->GetParent()->GetEventContext()->GetProperties(); current_prop_value = props->find( (std::string) target_property_key )->second; } ibc->ChangeProperty( target_property_key.c_str(), target_property_value.c_str() ); //broadcast that the individual changed properties INodeTriggeredInterventionConsumer* broadcaster = nullptr; if (s_OK != parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&broadcaster)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } LOG_DEBUG_F( "Individual %d changed property, broadcasting PropertyChange \n", parent->GetSuid().data ); broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), IndividualEventTriggerType::PropertyChange ); if( revert ) { target_property_value = current_prop_value; probability = 0.0; // keep it simple for now, reversion is guaranteed reversion_timer = revert; action_timer= FLT_MAX; LOG_DEBUG_F( "Initializing reversion timer to %f\n", reversion_timer ); revert = 0; // no more reversion from reversion } else { expired = true; } } action_timer -= dt; }
void AbstractBednet::BroadcastEvent( const EventTrigger& trigger ) const { if( !trigger.IsUninitialized() ) { INodeTriggeredInterventionConsumer* broadcaster = nullptr; if( s_OK != parent->GetEventContext()->GetNodeEventContext()->QueryInterface( GET_IID( INodeTriggeredInterventionConsumer ), (void**)&broadcaster ) ) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), trigger ); } }
void NodeLevelHealthTriggeredIV::Unregister() { // unregister ourself as a node level health triggered observer INodeTriggeredInterventionConsumer * pNTIC = nullptr; if (s_OK != parent->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&pNTIC)) { throw QueryInterfaceException(__FILE__, __LINE__, __FUNCTION__, "parent", "INodeTriggeredInterventionConsumer", "INodeEventContext"); } release_assert(pNTIC); for (auto &trigger : m_trigger_conditions) { pNTIC->UnregisterNodeEventObserver( this, trigger ); } SetExpired( true ); }
void HIVInterventionsContainer::BroadcastNewHIVInfection() { //function called when we externally put in HIV infections through AcquireInfectionHIV //first get the pointer to the person, parent is the generic individual release_assert(parent); IIndividualHumanEventContext * HIVEventContext = NULL; if (s_OK != parent->QueryInterface(GET_IID(IIndividualHumanEventContext), (void**)&HIVEventContext)) { throw QueryInterfaceException(__FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext"); } INodeTriggeredInterventionConsumer* broadcaster = nullptr; if (s_OK != HIVEventContext->GetNodeEventContext()->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&broadcaster)) { throw QueryInterfaceException(__FILE__, __LINE__, __FUNCTION__, "HIVEventContext-->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext"); } broadcaster->TriggerNodeEventObservers(parent->GetEventContext(), EventTrigger::NewExternalHIVInfection); }
void HIVDelayedIntervention::Callback( float dt ) { if( expired || broadcast_event.IsUninitialized() ) { LOG_DEBUG_F("expired or event is unitialized\n"); return; } // Duplicated from SimpleDiagnostic::positiveTestDistribute INodeTriggeredInterventionConsumer* broadcaster = nullptr; if (s_OK != parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&broadcaster)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), broadcast_event ); LOG_DEBUG_F("broadcast actual event\n"); expired = true; return; }
void HIVInterventionsContainer::GoOffART() { release_assert( hiv_parent ); release_assert( hiv_parent->GetHIVSusceptibility() ); if( hiv_parent->GetHIVInfection() == nullptr ) { LOG_WARN_F( "Individual %d coming off ART without infection!!!\n", parent->GetSuid().data ); return; } release_assert( hiv_parent->GetHIVInfection() ); if( OnArtQuery() == false ) { LOG_DEBUG_F( "Individual %d is not on ART, cannot dropout.\n", parent->GetSuid().data ); return; } LOG_DEBUG_F( "EEL: Individual %d dropping off ART now\n", parent->GetSuid().data ); ART_status = ARTStatus::OFF_BY_DROPOUT; full_suppression_timer = INACTIVE_DURATION; days_since_most_recent_ART_start = INACTIVE_DURATION; hiv_parent->GetHIVInfection()->ApplySuppressionDropout(); // Make sure ART dropouts do no return to ON_BUT_FAILING m_suppression_failure_timer = INACTIVE_DURATION; INodeTriggeredInterventionConsumer* broadcaster = nullptr; if (s_OK != parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&broadcaster)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), EventTrigger::StoppedART ); }
void HIVInterventionsContainer::GoOnART( bool viral_suppression, float daysToAchieveSuppression ) { INodeTriggeredInterventionConsumer* broadcaster = nullptr; if (s_OK != parent->GetEventContext()->GetNodeEventContext()->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&broadcaster)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent->GetEventContext()->GetNodeEventContext()", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } // NOTE: Should determine where GoOnART was called from by listening to other broadcast messages if( OnPreART() ) { // broadcast HIVPreARTToART broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), EventTrigger::HIVPreARTToART ); } else { // broadcast HIVPreARTToART broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), EventTrigger::HIVNonPreARTToART ); } release_assert( hiv_parent ); release_assert( hiv_parent->GetHIVSusceptibility() ); if( hiv_parent->GetHIVInfection() == nullptr ) { LOG_DEBUG_F( "GoOnART called for *uninfected* individual %d. Not distributing ART!\n", parent->GetSuid().data ); return; } release_assert( hiv_parent->GetHIVInfection() ); if( OnArtQuery() == true ) { // Don't got on ART if already on ART! LOG_DEBUG_F( "Individual %d is already on ART.\n", parent->GetSuid().data ); return; } if( OnPreART() ) { OnEndPreART(); LOG_DEBUG_F( "Individual %d appears to be in pre-ART while starting ART, changing preART status indicator to false.\n", parent->GetSuid().data ); } OnBeginART(); if( viral_suppression ) { hiv_parent->GetHIVSusceptibility()->ApplyARTOnset(); hiv_parent->GetHIVInfection()->SetupSuppressedDiseaseTimers(); ART_status = ARTStatus::ON_ART_BUT_NOT_VL_SUPPRESSED; full_suppression_timer = daysToAchieveSuppression; days_to_achieve_suppression = daysToAchieveSuppression; } else { ART_status = ARTStatus::ON_BUT_ADHERENCE_POOR; } days_since_most_recent_ART_start = 0.0f; broadcaster->TriggerNodeEventObservers( parent->GetEventContext(), EventTrigger::StartedART ); LOG_DEBUG_F( "Individual %d is now on ART.\n", parent->GetSuid().data ); // If not going to achieve viral suppression, stop here so as to 1) avoid computing failure and 2) skip maternal transmission mod if( !viral_suppression ) return; float prog = hiv_parent->GetHIVInfection()->GetPrognosis(); // Simple case (prog>11.9 months): // |--early(183d)--x----suppression(yrs)----x--failing(9m)--| // Shorter case (prog=11.9m): // |--early--x---failing---| ... straight from ramp-up to failing, suppression first to go // Even Shorter case (prog>183d && <11.9m): // |-early-x---failing---| ... straight from ramp-up to failing, ramp-up gets trimmed // Shortest case (prog<=9m): // |--failing--| ... straight to failing float failing_duration = min( (InfectionHIVConfig::AIDS_duration_in_months*DAYSPERYEAR)/MONTHSPERYEAR, prog ); NO_LESS_THAN( failing_duration, 0.0f); // not really necessary float early_duration = min( days_to_achieve_suppression, prog - failing_duration ); float suppression_duration = max( prog - early_duration - failing_duration, 0.0f ); // set up a timer for ART failure LOG_DEBUG_F( "Individual %d getting suppression_duration (time to ART failure) of %f based on prognosis of %f (early = %f, failing = %f).\n", parent->GetSuid().data, suppression_duration, prog, early_duration, failing_duration ); m_suppression_failure_timer = suppression_duration + early_duration; }
//returns false if didn't get the intervention bool NodeLevelHealthTriggeredIV::notifyOnEvent( IIndividualHumanEventContext *pIndiv, const EventTrigger& trigger ) { // ---------------------------------------------------------------------- // --- Ignore events for nodes that don't qualify due to their properties // ---------------------------------------------------------------------- if( !node_property_restrictions.Qualifies( parent->GetNodeContext()->GetNodeProperties() ) ) { return false; } IIndividualHuman *p_human = nullptr; if (s_OK != pIndiv->QueryInterface(GET_IID(IIndividualHuman), (void**)&p_human)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "pIndiv", "IIndividualHuman", "IIndividualHumanEventContext" ); } bool missed_intervention = false ; if( distribute_on_return_home && (trigger == EventTrigger::Emigrating) ) { if( p_human->AtHome() ) { // ------------------------------------------------------------------------------------------------ // --- If the individual is leaving his node of residence, then we want to keep track that he left // --- so that when he returns we can give him the interventions that he missed. // ------------------------------------------------------------------------------------------------ release_assert( event_occurred_while_resident_away.count( pIndiv->GetSuid() ) == 0 ); event_occurred_while_resident_away.insert( make_pair( pIndiv->GetSuid(), false ) ); } return false ; } else if( distribute_on_return_home && (trigger == EventTrigger::Immigrating) ) { if( p_human->AtHome() ) { // ------------------------------------------------------------------------------ // --- If the individual has returned home and they missed the intervention, then // --- we want them to get it, assuming they qualify. // ------------------------------------------------------------------------------ release_assert( event_occurred_while_resident_away.count( pIndiv->GetSuid() ) > 0 ); missed_intervention = event_occurred_while_resident_away[ pIndiv->GetSuid() ] ; event_occurred_while_resident_away.erase( pIndiv->GetSuid() ); if( missed_intervention ) { LOG_DEBUG_F( "Resident %d came home and intervention was distributed while away.\n", pIndiv->GetSuid().data ); } } if( !missed_intervention ) { return false ; } } else // the trigger event { // -------------------------------------------------------------------------------------------- // --- If this is one of the non-migrating events that they intervention is listening for // --- and this is not a blackout period, then record that the residents that are away missed // --- the intervention. // -------------------------------------------------------------------------------------------- if( blackout_time_remaining <= 0.0f ) { for( auto& rEntry : event_occurred_while_resident_away ) { rEntry.second = true ; } } } if( !blackout_event_trigger.IsUninitialized() && (blackout_period > 0.0) ) { if( (event_occured_list[ trigger.GetIndex() ].count( pIndiv->GetSuid().data ) > 0) || (!missed_intervention && (blackout_time_remaining > 0.0f)) ) { INodeTriggeredInterventionConsumer * pNTIC = NULL; if (s_OK != parent->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&pNTIC) ) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } pNTIC->TriggerNodeEventObservers( pIndiv, blackout_event_trigger ); return false; } } LOG_DEBUG_F("Individual %d experienced event %s, check to see if they pass the conditions before distributing actual_intervention \n", pIndiv->GetInterventionsContext()->GetParent()->GetSuid().data, trigger.c_str() ); assert( parent ); assert( parent->GetRng() ); bool distributed = false; if( _di != nullptr ) { //initialize this flag by individual (not by node) m_disqualified_by_coverage_only = false; if( qualifiesToGetIntervention( pIndiv ) == false ) { LOG_DEBUG_F("Individual failed to qualify for intervention, m_disqualified_by_coverage_only is %d \n", m_disqualified_by_coverage_only); if (m_disqualified_by_coverage_only == true) { onDisqualifiedByCoverage( pIndiv ); } return false; } // Query for campaign cost observer interface from INodeEventContext *parent ICampaignCostObserver *iCCO; if (s_OK != parent->QueryInterface(GET_IID(ICampaignCostObserver), (void**)&iCCO)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent", "ICampaignCostObserver", "INodeEventContext" ); } // Huge performance win by cloning instead of configuring. IDistributableIntervention *di = _di->Clone(); release_assert( di ); di->AddRef(); distributed = di->Distribute( pIndiv->GetInterventionsContext(), iCCO ); if( distributed ) { std::string classname = GetInterventionClassName(); LOG_DEBUG_F("A Node level health-triggered intervention (%s) was successfully distributed to individual %d\n", classname.c_str(), pIndiv->GetInterventionsContext()->GetParent()->GetSuid().data ); } else { LOG_DEBUG_F( "Intervention not distributed?\n" ); } di->Release(); } else { release_assert( _ndi ); // Huge performance win by cloning instead of configuring. INodeDistributableIntervention *ndi = _ndi->Clone(); release_assert( ndi ); ndi->AddRef(); distributed = ndi->Distribute( parent, nullptr ); if( distributed ) { std::string classname = GetInterventionClassName(); LOG_INFO_F("Distributed '%s' intervention to node %d\n", classname.c_str(), parent->GetExternalId() ); } ndi->Release(); } if( distributed ) { if( blackout_on_first_occurrence ) { blackout_time_remaining = blackout_period ; } else { notification_occured = true ; } event_occured_list[ trigger.GetIndex() ].insert( pIndiv->GetSuid().data ); } return distributed; }