Program Listing for File Symbiont.h¶
↰ Return to documentation for file (source/default_mode/Symbiont.h
)
#ifndef SYMBIONT_H
#define SYMBIONT_H
#include "../../Empirical/include/emp/math/Random.hpp"
#include "../../Empirical/include/emp/tools/string_utils.hpp"
#include "SymWorld.h"
#include <set>
#include <iomanip> // setprecision
#include <sstream> // stringstream
class Symbiont: public Organism {
protected:
double interaction_val = 0;
double points = 0;
bool dead = false;
double infection_chance = 0.0;
int age = 0;
emp::Ptr<emp::Random> random = NULL;
emp::Ptr<SymWorld> my_world = NULL;
emp::Ptr<Organism> my_host = NULL;
emp::Ptr<SymConfigBase> my_config = NULL;
emp::Ptr<emp::Taxon<int>> my_taxon = NULL;
public:
Symbiont(emp::Ptr<emp::Random> _random, emp::Ptr<SymWorld> _world, emp::Ptr<SymConfigBase> _config, double _intval=0.0, double _points = 0.0) : interaction_val(_intval), points(_points), random(_random), my_world(_world), my_config(_config) {
infection_chance = my_config->SYM_INFECTION_CHANCE();
if (infection_chance == -2) infection_chance = random->GetDouble(0,1); //randomized starting infection chance
if (infection_chance > 1 || infection_chance < 0) throw "Invalid infection chance. Must be between 0 and 1"; //exception for invalid infection chance
if (_intval == -2) {
interaction_val = random->GetDouble(-1, 1);
}
if (interaction_val > 1 || interaction_val < -1) {
throw "Invalid interaction value. Must be between -1 and 1"; // Exception for invalid interaction value
};
}
Symbiont(const Symbiont &) = default;
Symbiont(Symbiont &&) = default;
Symbiont() = default;
Symbiont & operator=(const Symbiont &) = default;
Symbiont & operator=(Symbiont &&) = default;
~Symbiont() {
if(my_config->PHYLOGENY() == 1) {my_world->GetSymSys()->RemoveOrg(my_taxon, my_world->GetUpdate());}
}
std::string const GetName() {
return "Symbiont";
}
double GetIntVal() const {return interaction_val;}
double GetPoints() {return points;}
bool IsPhage() {return false;}
bool IsHost() {return false;}
double GetInfectionChance() {return infection_chance;}
emp::Ptr<Organism> GetHost() {return my_host;}
emp::Ptr<emp::Taxon<int>> GetTaxon() {return my_taxon;}
void SetTaxon(emp::Ptr<emp::Taxon<int>> _in) {my_taxon = _in;}
// std::set<int> GetResTypes() const {return res_types;}
void SetDead() { dead = true; }
bool GetDead() { return dead; }
void SetIntVal(double _in) {
if ( _in > 1 || _in < -1) {
throw "Invalid interaction value. Must be between -1 and 1"; // Exception for invalid interaction value
}
else {
interaction_val = _in;
}
}
void SetPoints(double _in) {points = _in;}
void AddPoints(double _in) { points += _in;}
int GetAge() {return age;}
void SetAge(int _in) {age = _in;}
void SetHost(emp::Ptr<Organism> _in) {my_host = _in;}
void SetInfectionChance(double _in) {
if(_in > 1 || _in < 0) throw "Invalid infection chance. Must be between 0 and 1 (inclusive)";
else infection_chance = _in;
}
//void SetResTypes(std::set<int> _in) {res_types = _in;}
void UponInjection(){
//does nothing for now, added for backwards compatibility from phage to symbiont
}
void GrowOlder(){
age = age + 1;
if(age > my_config->SYM_AGE_MAX() && my_config->SYM_AGE_MAX() > 0){
SetDead();
}
}
void Mutate(){
double local_rate = my_config->MUTATION_RATE();
double local_size = my_config->MUTATION_SIZE();
if (random->GetDouble(0.0, 1.0) <= local_rate) {
interaction_val += random->GetRandNormal(0.0, local_size);
if(interaction_val < -1) interaction_val = -1;
else if (interaction_val > 1) interaction_val = 1;
//also modify infection chance, which is between 0 and 1
if(my_config->FREE_LIVING_SYMS()){
infection_chance += random->GetRandNormal(0.0, local_size);
if (infection_chance < 0) infection_chance = 0;
else if (infection_chance > 1) infection_chance = 1;
}
}
}
double ProcessResources(double host_donation, emp::Ptr<Organism> host = nullptr){
if(host == nullptr){
host = my_host;
}
double sym_int_val = GetIntVal();
double sym_portion = 0;
double host_portion = 0;
double synergy = my_config->SYNERGY();
if (sym_int_val<0){
double stolen = host->StealResources(sym_int_val);
host_portion = 0;
sym_portion = stolen + host_donation;
}
else if (sym_int_val >= 0){
host_portion = host_donation * sym_int_val;
sym_portion = host_donation - host_portion;
}
AddPoints(sym_portion);
return host_portion * synergy;
}
bool WantsToInfect(){
bool result = random->GetDouble(0.0, 1.0) < infection_chance;
return result;
}
bool InfectionFails(){
//note: this can be returned true, and an infecting sym can then be killed by a host that is already infected.
bool sym_dies = random->GetDouble(0.0, 1.0) < my_config->SYM_INFECTION_FAILURE_RATE();
return sym_dies;
}
void LoseResources(double resources){
double int_val = interaction_val;
if(my_host.IsNull()) { // this method should only be called on free-living syms, but double check!
if(int_val >= 0){
double spent = resources * int_val;
this->AddPoints(resources - spent);
}
else {
double attack = -1.0 * int_val * resources;
this->AddPoints(resources - attack);
}
}
}
//size_t rank=-1
void Process(emp::WorldPosition location) {
//ID is where they are in the world, INDEX is where they are in the host's symbiont list (or 0 if they're free living)
if (my_host.IsNull() && my_config->FREE_LIVING_SYMS()) { //free living symbiont
double resources = my_world->PullResources(my_config->FREE_SYM_RES_DISTRIBUTE()); //receive resources from the world
LoseResources(resources);
}
//Check if horizontal transmission can occur and do it
HorizontalTransmission(location);
//Age the organism
GrowOlder();
//Check if the organism should move and do it
if (my_host.IsNull() && my_config->FREE_LIVING_SYMS() && !dead) {
//if the symbiont should move, and hasn't been killed
my_world->MoveFreeSym(location);
}
}
emp::Ptr<Organism> MakeNew() {
emp::Ptr<Symbiont> new_sym = emp::NewPtr<Symbiont>(random, my_world, my_config, GetIntVal());
new_sym->SetInfectionChance(GetInfectionChance());
return new_sym;
}
emp::Ptr<Organism> Reproduce() {
emp::Ptr<Organism> sym_baby = MakeNew();
sym_baby->Mutate();
if(my_config->PHYLOGENY() == 1){
my_world->AddSymToSystematic(sym_baby, my_taxon);
//baby's taxon will be set in AddSymToSystematic
}
return sym_baby;
}
void VerticalTransmission(emp::Ptr<Organism> host_baby) {
if((my_world->WillTransmit()) && GetPoints() >= my_config->SYM_VERT_TRANS_RES()){ //if the world permits vertical tranmission and the sym has enough resources, transmit!
emp::Ptr<Organism> sym_baby = Reproduce();
points = points - my_config->SYM_VERT_TRANS_RES();
host_baby->AddSymbiont(sym_baby);
//vertical transmission data node
emp::DataMonitor<int>& data_node_attempts_verttrans = my_world->GetVerticalTransmissionAttemptCount();
data_node_attempts_verttrans.AddDatum(1);
}
}
void HorizontalTransmission(emp::WorldPosition location) {
if (my_config->HORIZ_TRANS()) { //non-lytic horizontal transmission enabled
double required_points = my_config->SYM_HORIZ_TRANS_RES();
if (my_config->FREE_LIVING_SYMS() && my_host == nullptr && my_config->FREE_SYM_REPRO_RES() > -1) {
required_points = my_config->FREE_SYM_REPRO_RES();
}
if (GetPoints() >= required_points) {
// symbiont reproduces independently (horizontal transmission) if it has enough resources
//TODO: try just subtracting points to be consistent with vertical transmission
//points = points - my_config->SYM_HORIZ_TRANS_RES();
SetPoints(0);
emp::Ptr<Organism> sym_baby = Reproduce();
emp::WorldPosition new_pos = my_world->SymDoBirth(sym_baby, location);
//horizontal transmission data nodes
emp::DataMonitor<int>& data_node_attempts_horiztrans = my_world->GetHorizontalTransmissionAttemptCount();
data_node_attempts_horiztrans.AddDatum(1);
emp::DataMonitor<int>& data_node_successes_horiztrans = my_world->GetHorizontalTransmissionSuccessCount();
if(new_pos.IsValid()){
data_node_successes_horiztrans.AddDatum(1);
}
}
}
}
};
#endif