AntibodyModel.java
package org.matsim.episim.model;
import org.matsim.episim.EpisimPerson;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Updates the antibody level of a person after each iteration.
*/
public interface AntibodyModel {
/**
* Executed each day in order to update the antibody level of a person.
* @param person person to update.
* @param day current day / iteration
*/
void updateAntibodies(EpisimPerson person, int day);
/**
* Initialize antibody model.
* @param persons persons whose antibodies are initialized
* @param iteration current simulation iteration
*/
void init(Collection<EpisimPerson> persons, int iteration);
/**
* Recalculates antibody levels after loading a snapshot.
*/
void recalculateAntibodiesAfterSnapshot(Collection<EpisimPerson> persons, int iteration);
/**
* Parameters of {@link DefaultAntibodyModel}.
*
* <p>Deliberately not a MATSim config group. The values are calibrated for SARS-CoV-2 and carry no source, so
* they are not meant to be set per run in a config file; an immunity model for other pathogens does not use
* them. It is bound in Guice, and a scenario that needs different values binds its own instance, as before
* this was briefly a config group.</p>
*
* <p>An immunity event without an entry induces no antibodies and does not refresh existing ones. This is what
* lets a pathogen without antibody parameters run at all, without having to configure zeros for it.</p>
*/
final class Config {
private final Map<ImmunityEvent, Map<VirusStrain, Double>> initialAntibodies;
private final Map<ImmunityEvent, Map<VirusStrain, Double>> antibodyRefreshFactors;
/**
* Sigma of the log-normal distribution of a person's individual immune-response multiplier; {@code 0}
* means every person reacts identically.
*/
private double immuneResponseSigma = 0.;
/**
* Half-life multiplier for persons whose immunity comes from both infection and vaccination, or from many
* events.
*/
private double hlMultiplierForInfected = 1.0;
/**
* Default values, calibrated for SARS-CoV-2.
*/
public Config() {
this(defaultInitialAntibodies(), defaultAntibodyRefreshFactors());
}
public Config(Map<ImmunityEvent, Map<VirusStrain, Double>> initialAntibodies,
Map<ImmunityEvent, Map<VirusStrain, Double>> antibodyRefreshFactors) {
this.initialAntibodies = initialAntibodies;
this.antibodyRefreshFactors = antibodyRefreshFactors;
}
/**
* Antibody level against each strain right after this immunity event; empty if it induces none.
*/
public Map<VirusStrain, Double> getInitialAntibodies(ImmunityEvent immunityEvent) {
return initialAntibodies.getOrDefault(immunityEvent, Map.of());
}
public void setInitialAntibodies(ImmunityEvent immunityEvent, Map<VirusStrain, Double> antibodies) {
initialAntibodies.put(immunityEvent, new LinkedHashMap<>(antibodies));
}
/**
* Factor by which an existing level against each strain is refreshed when this event happens again;
* empty if it refreshes nothing.
*/
public Map<VirusStrain, Double> getAntibodyRefreshFactors(ImmunityEvent immunityEvent) {
return antibodyRefreshFactors.getOrDefault(immunityEvent, Map.of());
}
public void setAntibodyRefreshFactors(ImmunityEvent immunityEvent, Map<VirusStrain, Double> factors) {
antibodyRefreshFactors.put(immunityEvent, new LinkedHashMap<>(factors));
}
public double getImmuneResponseSigma() {
return immuneResponseSigma;
}
public void setImmuneResponseSigma(double immuneResponseSigma) {
this.immuneResponseSigma = immuneResponseSigma;
}
public double getHlMultiplierForInfected() {
return hlMultiplierForInfected;
}
public void setHlMultiplierForInfected(double hlMultiplierForInfected) {
this.hlMultiplierForInfected = hlMultiplierForInfected;
}
private static Map<ImmunityEvent, Map<VirusStrain, Double>> defaultInitialAntibodies() {
Map<ImmunityEvent, Map<VirusStrain, Double>> initialAntibodies = new LinkedHashMap<>();
for (VaccinationType immunityType : VaccinationType.getAllStandardOptions()) {
initialAntibodies.put(immunityType, new LinkedHashMap<>());
for (VirusStrain virusStrain : VirusStrain.getAllStandardOptions()) {
if (immunityType == VaccinationType.mRNA) {
initialAntibodies.get(immunityType).put(virusStrain, 29.2); //10.0
} else if (immunityType == VaccinationType.vector) {
initialAntibodies.get(immunityType).put(virusStrain, 6.8); //2.5
} else {
initialAntibodies.get(immunityType).put(virusStrain, 5.0);
}
}
}
for (VirusStrain immunityType : VirusStrain.getAllStandardOptions()) {
initialAntibodies.put(immunityType, new LinkedHashMap<>());
for (VirusStrain virusStrain : VirusStrain.getAllStandardOptions()) {
initialAntibodies.get(immunityType).put(virusStrain, 5.0);
}
}
//mRNAAlpha, mRNADelta, mRNABA1 comes from Sydney's calibration.
//The other values come from Rössler et al.
double mutEscDelta = 29.2 / 10.9;
double mutEscBa1 = 10.9 / 1.9;
double mutEscBa5 = 2.9;
//Wildtype
double mRNAAlpha = 29.2;
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.SARS_CoV_2, mRNAAlpha);
initialAntibodies.get(VaccinationType.vector).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 210. / 700.);
initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 300. / 700.);
initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 300. / 700.);
initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.SARS_CoV_2, mRNAAlpha * 210. / 700.);
initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.SARS_CoV_2, 0.01);
initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.SARS_CoV_2, 0.01);
initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.SARS_CoV_2, 0.01);
initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.SARS_CoV_2, mRNAAlpha / mutEscDelta / mutEscBa1);
initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.SARS_CoV_2, mRNAAlpha / mutEscDelta / mutEscBa1 / mutEscBa5);
//Alpha
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.ALPHA, mRNAAlpha);
initialAntibodies.get(VaccinationType.vector).put(VirusStrain.ALPHA, mRNAAlpha * 210. / 700.);
initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.ALPHA, mRNAAlpha * 300. / 700.);
initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.ALPHA, mRNAAlpha * 300. / 700.);
initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.ALPHA, mRNAAlpha * 210. / 700.);
initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.ALPHA, 0.01);
initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.ALPHA, 0.01);
initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.ALPHA, 0.01);
initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.ALPHA, mRNAAlpha / mutEscDelta / mutEscBa1);
initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.ALPHA, mRNAAlpha / mutEscDelta / mutEscBa1 / mutEscBa5);
//DELTA
double mRNADelta = mRNAAlpha / mutEscDelta;
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.DELTA, mRNADelta);
initialAntibodies.get(VaccinationType.vector).put(VirusStrain.DELTA, mRNADelta * 150. / 300.);
initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.DELTA, mRNADelta * 64. / 300.);
initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.DELTA, mRNADelta * 64. / 300.);
initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.DELTA, mRNADelta * 450. / 300.);
initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.DELTA, 0.01);
initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.DELTA, 0.01);
initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.DELTA, 0.01);
initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.DELTA, mRNADelta / mutEscBa1);
initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.DELTA, mRNADelta / mutEscBa1 / mutEscBa5);
//BA.1
double mRNABA1 = mRNADelta / mutEscBa1;
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA1, mRNABA1);
initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA1, mRNABA1 * 4. / 20.); //???
initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6. / 20.);
initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 6. / 20.);
initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA1, mRNABA1 * 8. / 20.);
initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA1, 64.0 / 300.);
initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / 1.4);
initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA1, 64.0 / 300. / mutEscBa5); //todo: is 1.4
initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA1, mRNAAlpha);
initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA1, mRNAAlpha / mutEscBa5);
//BA.2
double mRNABA2 = mRNABA1;
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA2, mRNABA2);
initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA2, mRNABA2 * 4. / 20.);
initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6. / 20.);
initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 6. / 20.);
initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA2, mRNABA2 * 8. / 20.);
initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / 1.4);
initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA2, 64.0 / 300.);
initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA2, 64.0 / 300. / mutEscBa5);
initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA2, mRNAAlpha);
initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA2, mRNAAlpha / mutEscBa5);
//BA.5
double mRNABa5 = mRNABA2 / mutEscBa5;
initialAntibodies.get(VaccinationType.mRNA).put(VirusStrain.OMICRON_BA5, mRNABa5);
initialAntibodies.get(VaccinationType.vector).put(VirusStrain.OMICRON_BA5, mRNABa5 * 4. / 20.);
initialAntibodies.get(VirusStrain.SARS_CoV_2).put(VirusStrain.OMICRON_BA5, mRNABa5 * 6. / 20.);
initialAntibodies.get(VirusStrain.ALPHA).put(VirusStrain.OMICRON_BA5, mRNABa5 * 6. / 20.);
initialAntibodies.get(VirusStrain.DELTA).put(VirusStrain.OMICRON_BA5, mRNABa5 * 8. / 20.);
initialAntibodies.get(VirusStrain.OMICRON_BA1).put(VirusStrain.OMICRON_BA5, 64.0 / 300. / mutEscBa5); // todo: do we need 1.4?
initialAntibodies.get(VirusStrain.OMICRON_BA2).put(VirusStrain.OMICRON_BA5, 64.0 / 300. / mutEscBa5);
initialAntibodies.get(VirusStrain.OMICRON_BA5).put(VirusStrain.OMICRON_BA5, 64.0 / 300.);
initialAntibodies.get(VaccinationType.ba1Update).put(VirusStrain.OMICRON_BA5, mRNAAlpha / mutEscBa5);
initialAntibodies.get(VaccinationType.ba5Update).put(VirusStrain.OMICRON_BA5, mRNAAlpha);
return initialAntibodies;
}
/**
* Default refresh factors, calibrated for SARS-CoV-2.
*/
private static Map<ImmunityEvent, Map<VirusStrain, Double>> defaultAntibodyRefreshFactors() {
Map<ImmunityEvent, Map<VirusStrain, Double>> antibodyRefreshFactors = new LinkedHashMap<>();
for (VaccinationType immunityType : VaccinationType.getAllStandardOptions()) {
antibodyRefreshFactors.put(immunityType, new LinkedHashMap<>());
for (VirusStrain virusStrain : VirusStrain.getAllStandardOptions()) {
if (immunityType == VaccinationType.mRNA) {
antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
} else if (immunityType == VaccinationType.vector) {
antibodyRefreshFactors.get(immunityType).put(virusStrain, 5.0);
} else if (immunityType == VaccinationType.ba1Update) {
antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
} else if (immunityType == VaccinationType.ba5Update) {
antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
} else {
antibodyRefreshFactors.get(immunityType).put(virusStrain, Double.NaN);
}
}
}
for (VirusStrain immunityType : VirusStrain.getAllStandardOptions()) {
antibodyRefreshFactors.put(immunityType, new LinkedHashMap<>());
for (VirusStrain virusStrain : VirusStrain.getAllStandardOptions()) {
antibodyRefreshFactors.get(immunityType).put(virusStrain, 15.0);
}
}
return antibodyRefreshFactors;
}
}
}