Skip to content

Commit

Permalink
make the detection of imported case dynamic
Browse files Browse the repository at this point in the history
  • Loading branch information
acavelan committed Jan 16, 2025
1 parent d170b71 commit 74e9554
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 77 deletions.
2 changes: 1 addition & 1 deletion model/Clinical/CMDecisionTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class CMDTInfectionOrigin : public CMDecisionTree {
}

virtual CMDTOut exec( CMHostData hostData ) const{
WithinHost::InfectionOrigin InfectionOrigin = hostData.withinHost().getInfectionType();
WithinHost::InfectionOrigin InfectionOrigin = hostData.withinHost().getInfectionOrigin();
if(InfectionOrigin == WithinHost::InfectionOrigin::Imported)
return imported.exec( hostData );
else if (InfectionOrigin == WithinHost::InfectionOrigin::Introduced)
Expand Down
2 changes: 1 addition & 1 deletion model/Clinical/Episode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void Episode::update (const Host::Human& human, Episode::State newState)
toReport = true;

if(toReport) {
infectionType = human.withinHostModel->getInfectionType();
infectionType = human.withinHostModel->getInfectionOrigin();

report ();

Expand Down
22 changes: 6 additions & 16 deletions model/Host/WithinHost/CommonWithinHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,30 +260,14 @@ void CommonWithinHost::update(Host::Human &human, LocalRng& rng, int &nNewInfs_i
m_y_lag_l[y_lag_i * Genotypes::N() + g] = 0.0;
}

int nImported = 0, nIntroduced = 0, nIndigenous = 0;
for( auto inf = infections.begin(); inf != infections.end(); ++inf )
{
if((*inf)->origin() == InfectionOrigin::Imported)
m_y_lag_i[y_lag_i * Genotypes::N() + (*inf)->genotype()] += (*inf)->getDensity();
else
m_y_lag_l[y_lag_i * Genotypes::N() + (*inf)->genotype()] += (*inf)->getDensity();

if((*inf)->origin() == InfectionOrigin::Indigenous) nIndigenous++;
else if((*inf)->origin() == InfectionOrigin::Introduced) nIntroduced++;
else nImported++;
}

/* The rules are:
- Imported only if all infections are imported
- Introduced if at least one Introduced
- Indigenous otherwise (Imported + Indigenous or just Indigenous infections) */
if(nIntroduced > 0)
infectionType = InfectionOrigin::Introduced;
else if(nIndigenous > 0)
infectionType = InfectionOrigin::Indigenous;
else
infectionType = InfectionOrigin::Imported;

// This is a bug, we keep it this way to be consistent with old simulations
if(nNewInfsIgnored > 0)
nNewInfs_l += nNewInfsIgnored;
Expand All @@ -294,6 +278,10 @@ void CommonWithinHost::addProphylacticEffects(const vector<double>& pClearanceBy
throw util::unimplemented_exception( "prophylactic effects on 1-day time step" );
}

InfectionOrigin CommonWithinHost::getInfectionOrigin()const
{
return get_infection_origin(infections);
}

// ----- Summarize -----

Expand All @@ -309,6 +297,8 @@ bool CommonWithinHost::summarize( Host::Human& human )const{
pathogenesisModel->summarize( human );
pkpdModel.summarize( human );

InfectionOrigin infectionType = get_infection_origin(infections);

// If the number of infections is 0 and parasite density is positive we default to Indigenous
if( infections.size() > 0 ){
mon::reportStatMHI( mon::MHR_INFECTED_HOSTS, human, 1 );
Expand Down
2 changes: 2 additions & 0 deletions model/Host/WithinHost/CommonWithinHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class CommonWithinHost : public WHFalciparum
static CommonInfection* (* createInfection) (LocalRng& rng, uint32_t protID, int origin);
static CommonInfection* (* checkpointedInfection) (istream& stream);
//@}

virtual InfectionOrigin getInfectionOrigin() const;

virtual bool summarize( Host::Human& human )const;

Expand Down
93 changes: 46 additions & 47 deletions model/Host/WithinHost/DescriptiveWithinHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "util/ModelOptions.h"
#include "util/StreamValidator.h"
#include "util/errors.h"

#include <cassert>

using namespace std;
Expand All @@ -50,21 +51,27 @@ DescriptiveWithinHostModel::DescriptiveWithinHostModel( LocalRng& rng, double co
opt_vaccine_genotype = util::ModelOptions::option (util::VACCINE_GENOTYPE);
}

DescriptiveWithinHostModel::~DescriptiveWithinHostModel() {}
DescriptiveWithinHostModel::~DescriptiveWithinHostModel() {
for( auto inf = infections.begin(); inf != infections.end(); ++inf ){
delete *inf;
}
infections.clear();
}


// ----- Simple infection adders/removers -----

void DescriptiveWithinHostModel::loadInfection(istream& stream) {
infections.push_back(DescriptiveInfection(stream));
infections.push_back(new DescriptiveInfection(stream));
}

void DescriptiveWithinHostModel::clearInfections( Treatments::Stages stage ){
for(auto inf = infections.begin(); inf != infections.end();) {
if( stage == Treatments::BOTH ||
(stage == Treatments::LIVER && !inf->bloodStage()) ||
(stage == Treatments::BLOOD && inf->bloodStage())
(stage == Treatments::LIVER && !(*inf)->bloodStage()) ||
(stage == Treatments::BLOOD && (*inf)->bloodStage())
){
delete *inf;
inf = infections.erase( inf );
}else{
++inf;
Expand All @@ -77,11 +84,12 @@ void DescriptiveWithinHostModel::clearInfections( Treatments::Stages stage ){

void DescriptiveWithinHostModel::clearImmunity() {
for(auto inf = infections.begin(); inf != infections.end(); ++inf) {
inf->clearImmunity();
(*inf)->clearImmunity();
}
m_cumulative_h = 0.0;
m_cumulative_Y_lag = 0.0;
}

void DescriptiveWithinHostModel::importInfection(LocalRng& rng, int origin){
if( numInfs < MAX_INFECTIONS ){
m_cumulative_h += 1;
Expand All @@ -90,7 +98,8 @@ void DescriptiveWithinHostModel::importInfection(LocalRng& rng, int origin){
// should use initial frequencies to select genotypes.
vector<double> weights( 0 ); // zero length: signal to use initial frequencies
uint32_t genotype = Genotypes::sampleGenotype(rng, weights);
infections.push_back(DescriptiveInfection(rng, genotype, origin));
infections.push_back(new DescriptiveInfection(rng, genotype, origin));

}
assert( numInfs == static_cast<int>(infections.size()) );
}
Expand Down Expand Up @@ -119,10 +128,10 @@ void DescriptiveWithinHostModel::update(Host::Human &human, LocalRng& rng, int &
{
double vaccineFactor = human.vaccine.getFactor( interventions::Vaccine::PEV, genotype );
if(vaccineFactor == 1.0 || human.rng.bernoulli(vaccineFactor))
infections.push_back(DescriptiveInfection (rng, genotype, InfectionOrigin::Introduced));
infections.push_back(new DescriptiveInfection (rng, genotype, InfectionOrigin::Introduced));
}
else if (opt_vaccine_genotype == false)
infections.push_back(DescriptiveInfection (rng, genotype, InfectionOrigin::Introduced));
infections.push_back(new DescriptiveInfection (rng, genotype, InfectionOrigin::Introduced));
}
assert( numInfs == static_cast<int>(infections.size()) );

Expand All @@ -136,10 +145,10 @@ void DescriptiveWithinHostModel::update(Host::Human &human, LocalRng& rng, int &
{
double vaccineFactor = human.vaccine.getFactor( interventions::Vaccine::PEV, genotype );
if(vaccineFactor == 1.0 || human.rng.bernoulli(vaccineFactor))
infections.push_back(DescriptiveInfection (rng, genotype, InfectionOrigin::Indigenous));
infections.push_back(new DescriptiveInfection (rng, genotype, InfectionOrigin::Indigenous));
}
else if (opt_vaccine_genotype == false)
infections.push_back(DescriptiveInfection (rng, genotype, InfectionOrigin::Indigenous));
infections.push_back(new DescriptiveInfection (rng, genotype, InfectionOrigin::Indigenous));
}
assert( numInfs == static_cast<int>(infections.size()) );

Expand All @@ -160,9 +169,10 @@ void DescriptiveWithinHostModel::update(Host::Human &human, LocalRng& rng, int &
// any more).
// SP drug action and the PK/PD model would need to be abstracted
// behind a common interface.
if ( inf->expired() /* infection has self-terminated */ ||
(inf->bloodStage() ? treatmentBlood : treatmentLiver) )
if ( (*inf)->expired() /* infection has self-terminated */ ||
((*inf)->bloodStage() ? treatmentBlood : treatmentLiver) )
{
delete *inf;
inf=infections.erase(inf);
numInfs--;
continue;
Expand All @@ -171,18 +181,18 @@ void DescriptiveWithinHostModel::update(Host::Human &human, LocalRng& rng, int &
// Should be: infStepMaxDens = 0.0, but has some history.
// See MAX_DENS_CORRECTION in DescriptiveInfection.cpp.
double infStepMaxDens = timeStepMaxDensity;
double immSurvFact = immunitySurvivalFactor(ageInYears, inf->cumulativeExposureJ());
double bsvFactor = human.vaccine.getFactor(interventions::Vaccine::BSV, opt_vaccine_genotype? inf->genotype() : 0);
double immSurvFact = immunitySurvivalFactor(ageInYears, (*inf)->cumulativeExposureJ());
double bsvFactor = human.vaccine.getFactor(interventions::Vaccine::BSV, opt_vaccine_genotype? (*inf)->genotype() : 0);

inf->determineDensities(rng, m_cumulative_h, infStepMaxDens, immSurvFact, _innateImmSurvFact, bsvFactor);
(*inf)->determineDensities(rng, m_cumulative_h, infStepMaxDens, immSurvFact, _innateImmSurvFact, bsvFactor);

if (bugfix_max_dens)
infStepMaxDens = std::max(infStepMaxDens, timeStepMaxDensity);
timeStepMaxDensity = infStepMaxDens;

double density = inf->getDensity();
double density = (*inf)->getDensity();
totalDensity += density;
if( !inf->isHrp2Deficient() ){
if( !(*inf)->isHrp2Deficient() ){
hrp2Density += density;
}

Expand All @@ -207,30 +217,14 @@ void DescriptiveWithinHostModel::update(Host::Human &human, LocalRng& rng, int &
m_y_lag_l[y_lag_i * Genotypes::N() + g] = 0.0;
}

int nImported = 0, nIntroduced = 0, nIndigenous = 0;
for( auto inf = infections.begin(); inf != infections.end(); ++inf )
{
if(inf->origin() == InfectionOrigin::Imported)
m_y_lag_i[y_lag_i * Genotypes::N() + inf->genotype()] += inf->getDensity();
if((*inf)->origin() == InfectionOrigin::Imported)
m_y_lag_i[y_lag_i * Genotypes::N() + (*inf)->genotype()] += (*inf)->getDensity();
else
m_y_lag_l[y_lag_i * Genotypes::N() + inf->genotype()] += inf->getDensity();

if(inf->origin() == InfectionOrigin::Indigenous) nIndigenous++;
else if(inf->origin() == InfectionOrigin::Introduced) nIntroduced++;
else nImported++;
m_y_lag_l[y_lag_i * Genotypes::N() + (*inf)->genotype()] += (*inf)->getDensity();
}

/* The rules are:
- Imported only if all infections are imported
- Introduced if at least one Introduced
- Indigenous otherwise (Imported + Indigenous or just Indigenous infections) */
if(nIntroduced > 0)
infectionType = InfectionOrigin::Introduced;
else if(nIndigenous > 0)
infectionType = InfectionOrigin::Indigenous;
else
infectionType = InfectionOrigin::Imported;

// This is a bug, we keep it this way to be consistent with old simulations
if(opt_vaccine_genotype == false)
{
Expand All @@ -239,12 +233,18 @@ void DescriptiveWithinHostModel::update(Host::Human &human, LocalRng& rng, int &
}
}

InfectionOrigin DescriptiveWithinHostModel::getInfectionOrigin()const
{
return get_infection_origin(infections);
}

// ----- Summarize -----

bool DescriptiveWithinHostModel::summarize( Host::Human& human )const{
pathogenesisModel->summarize( human );

InfectionOrigin infectionType = get_infection_origin(infections);

// If the number of infections is 0 and parasite density is positive we default to Indigenous
if( infections.size() > 0 ){
mon::reportStatMHI( mon::MHR_INFECTED_HOSTS, human, 1 );
Expand All @@ -258,8 +258,8 @@ bool DescriptiveWithinHostModel::summarize( Host::Human& human )const{
int nImported = 0, nIntroduced = 0, nIndigenous = 0;
for( auto inf = infections.begin(); inf != infections.end(); ++inf )
{
if(inf->origin() == InfectionOrigin::Indigenous) nIndigenous++;
else if(inf->origin() == InfectionOrigin::Introduced) nIntroduced++;
if((*inf)->origin() == InfectionOrigin::Indigenous) nIndigenous++;
else if((*inf)->origin() == InfectionOrigin::Introduced) nIntroduced++;
else nImported++;
}

Expand All @@ -271,14 +271,14 @@ bool DescriptiveWithinHostModel::summarize( Host::Human& human )const{
mon::reportStatMHGI( mon::MHR_INFECTIONS_INDIGENOUS, human, 0, nIndigenous );

if( reportPatentInfected ){
for(std::list<DescriptiveInfection>::const_iterator inf = infections.begin(); inf != infections.end(); ++inf)
for(auto inf = infections.begin(); inf != infections.end(); ++inf)
{
if( diagnostics::monitoringDiagnostic().isPositive( human.rng, inf->getDensity(), std::numeric_limits<double>::quiet_NaN() ) )
if( diagnostics::monitoringDiagnostic().isPositive( human.rng, (*inf)->getDensity(), std::numeric_limits<double>::quiet_NaN() ) )
{
mon::reportStatMHGI( mon::MHR_PATENT_INFECTIONS, human, 0, 1 );
if(inf->origin() == InfectionOrigin::Indigenous)
if((*inf)->origin() == InfectionOrigin::Indigenous)
mon::reportStatMHGI( mon::MHR_PATENT_INFECTIONS_INDIGENOUS, human, 0, 1 );
else if(inf->origin() == InfectionOrigin::Introduced)
else if((*inf)->origin() == InfectionOrigin::Introduced)
mon::reportStatMHGI( mon::MHR_PATENT_INFECTIONS_INTRODUCED, human, 0, 1 );
else
mon::reportStatMHGI( mon::MHR_PATENT_INFECTIONS_IMPORTED, human, 0, 1 );
Expand All @@ -288,9 +288,8 @@ bool DescriptiveWithinHostModel::summarize( Host::Human& human )const{
if( reportInfectionsByGenotype ){
// accumulate total density by genotype
map<uint32_t, double> dens_by_gtype;
for( const DescriptiveInfection& inf: infections ){
dens_by_gtype[inf.genotype()] += inf.getDensity();
}
for(auto inf = infections.begin(); inf != infections.end(); ++inf)
dens_by_gtype[(*inf)->genotype()] += (*inf)->getDensity();

for( auto gtype: dens_by_gtype ){
// we had at least one infection of this genotype
Expand Down Expand Up @@ -334,8 +333,8 @@ void DescriptiveWithinHostModel::checkpoint (istream& stream) {
}
void DescriptiveWithinHostModel::checkpoint (ostream& stream) {
WHFalciparum::checkpoint (stream);
for(DescriptiveInfection& inf : infections) {
inf & stream;
for(auto inf = infections.begin(); inf != infections.end(); ++inf){
*inf & stream;
}
}

Expand Down
6 changes: 4 additions & 2 deletions model/Host/WithinHost/DescriptiveWithinHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ class DescriptiveWithinHostModel : public WHFalciparum {
virtual void update(Host::Human &human, LocalRng& rng, int &nNewInfs_i, int &nNewInfs_l,
vector<double>& genotype_weights_i, vector<double>& genotype_weights_l, double ageInYears);

virtual bool summarize( Host::Human& human )const;
virtual InfectionOrigin getInfectionOrigin() const;

virtual bool summarize( Host::Human& human ) const;

protected:
virtual void clearInfections( Treatments::Stages stage );
Expand All @@ -67,7 +69,7 @@ class DescriptiveWithinHostModel : public WHFalciparum {
*
* Since infection models and within host models are very much intertwined,
* the idea is that each WithinHostModel has its own list of infections. */
std::list<DescriptiveInfection> infections;
std::list<DescriptiveInfection*> infections;

bool opt_vaccine_genotype = false;
};
Expand Down
26 changes: 26 additions & 0 deletions model/Host/WithinHost/Infection/Infection.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,5 +154,31 @@ class Infection {
friend class ::UnittestUtil;
};

template <typename T>
InfectionOrigin get_infection_origin(const std::list<T*> &infections)
{
if(infections.empty())
return InfectionOrigin::Indigenous;

int nImported = 0, nIntroduced = 0, nIndigenous = 0;
for( auto inf = infections.begin(); inf != infections.end(); ++inf )
{
if((*inf)->origin() == InfectionOrigin::Indigenous) nIndigenous++;
else if((*inf)->origin() == InfectionOrigin::Introduced) nIntroduced++;
else nImported++;
}

/* The rules are:
- Imported only if all infections are imported
- Introduced if at least one Introduced
- Indigenous otherwise (Imported + Indigenous or just Indigenous infections) */
if(nIntroduced > 0)
return InfectionOrigin::Introduced;
else if(nIndigenous > 0)
return InfectionOrigin::Indigenous;
else
return InfectionOrigin::Imported;
}

} }
#endif
6 changes: 0 additions & 6 deletions model/Host/WithinHost/WHFalciparum.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ class WHFalciparum : public WHInterface {

virtual Pathogenesis::StatePair determineMorbidity( Host::Human& human, double ageYears, bool isDoomed );

virtual InfectionOrigin getInfectionType() const {
return infectionType;
}

inline double getCumulative_h() const {
return m_cumulative_h;
}
Expand Down Expand Up @@ -141,8 +137,6 @@ class WHFalciparum : public WHInterface {
/// End of step on which treatment expires = start of first step after expiry
SimTime treatExpiryLiver, treatExpiryBlood;

InfectionOrigin infectionType = InfectionOrigin::Indigenous;

virtual void checkpoint (istream& stream);
virtual void checkpoint (ostream& stream);

Expand Down
2 changes: 1 addition & 1 deletion model/Host/WithinHost/WHInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class WHInterface {
virtual double getCumulative_h() const =0;
virtual double getCumulative_Y() const =0;

virtual InfectionOrigin getInfectionType() const =0;
virtual InfectionOrigin getInfectionOrigin() const =0;

/** The maximum number of infections a human can have. The only real reason
* for this limit is to prevent incase bad input from causing the number of
Expand Down
Loading

0 comments on commit 74e9554

Please sign in to comment.