From 509066ab17c82c67abe8f17d41d10ad5af86f795 Mon Sep 17 00:00:00 2001 From: smeriglio Date: Fri, 22 Nov 2024 14:41:46 +0100 Subject: [PATCH 1/8] added start & stop add-on --- .gitignore | 1 + ALL_CITATIONS.txt | 7 + BioFVM/BioFVM_microenvironment.cpp | 771 + BioFVM/BioFVM_microenvironment.h | 2 + Makefile | 818 +- addons/PhysiBoSS/src/maboss_intracellular.h | 95 + addons/PhysiBoSS/src/maboss_network.cpp | 17 + addons/PhysiBoSS/src/maboss_network.h | 43 + addons/start_and_stop/start_and_stop.cpp | 496 + addons/start_and_stop/start_and_stop.h | 17 + config/PhysiCell_settings.xml | 470 +- config/PhysiCell_settings_2D.xml | 286 + config/PhysiCell_settings_3D.xml | 287 + config/TNF_conf.cfg | 101 + config/TNF_nodes.bnd | 184 + config/init.tsv | 126 + core/PhysiCell_cell.cpp | 165 + core/PhysiCell_cell.h | 10 + core/PhysiCell_cell_container.cpp | 120 +- core/PhysiCell_cell_container.h | 3 + core/PhysiCell_custom.cpp | 149 +- core/PhysiCell_custom.h | 6 + core/PhysiCell_phenotype.cpp | 1049 + core/PhysiCell_phenotype.h | 67 +- core/PhysiCell_utilities.cpp | 51 + core/PhysiCell_utilities.h | 10 + custom_modules/custom.cpp | 551 + custom_modules/custom.h | 126 + custom_modules/submodel_data_structures.cpp | 114 + custom_modules/submodel_data_structures.h | 53 + .../tnf_boolean_model_interface.cpp | 189 + custom_modules/tnf_boolean_model_interface.h | 42 + custom_modules/tnf_receptor_dynamics.cpp | 143 + custom_modules/tnf_receptor_dynamics.h | 39 + output/empty.txt => main-backup.cpp | 0 main.cpp | 393 + sample_projects/Makefile-default | 12 +- sample_projects/biorobots/Makefile | 10 +- .../biorobots/config/PhysiCell_settings.xml | 1 + .../biorobots/custom_modules/custom.h | 2 + sample_projects/biorobots/main.cpp | 28 +- .../boolean/physiboss_cell_lines/Makefile | 8 +- .../config/PhysiCell_settings.xml | 1 + .../custom_modules/custom.h | 2 + .../boolean/physiboss_cell_lines/main.cpp | 27 +- .../boolean/spheroid_tnf_model/Makefile | 282 + .../config/PhysiCell_settings.xml | 225 + .../config/PhysiCell_settings_2D.xml | 286 + .../config/PhysiCell_settings_3D.xml | 287 + .../spheroid_tnf_model/config/TNF_conf.cfg | 101 + .../spheroid_tnf_model/config/TNF_nodes.bnd | 184 + .../spheroid_tnf_model/config/init.tsv | 126 + .../custom_modules/custom.cpp | 551 + .../custom_modules/custom.h | 126 + .../submodel_data_structures.cpp | 114 + .../custom_modules/submodel_data_structures.h | 53 + .../tnf_boolean_model_interface.cpp | 189 + .../tnf_boolean_model_interface.h | 42 + .../custom_modules/tnf_receptor_dynamics.cpp | 143 + .../custom_modules/tnf_receptor_dynamics.h | 39 + .../spheroid_tnf_model/main-spheroid_TNF.cpp | 393 + .../scripts/params/cell_phases_dict.json | 23 + .../scripts/params/phases_grouping_dict.json | 20 + .../scripts/plot_time_course.py | 159 + .../scripts/summarize_simulation.py | 113 + scripts/params/cell_phases_dict.json | 23 + scripts/params/phases_grouping_dict.json | 20 + scripts/plot_time_course.py | 159 + scripts/summarize_simulation.py | 113 + spheroid_TNF_model | Bin 0 -> 2102640 bytes start_and_stop_saving_files/bool_data.txt | 258 + start_and_stop_saving_files/cell_data.txt | 62258 ++++++++++++++++ start_and_stop_saving_files/global_param.txt | 24 + start_and_stop_saving_files/initial.tsv | 259 + start_and_stop_saving_files/microenv_data.txt | 12560 ++++ .../random_counters.txt | 3 + 76 files changed, 85406 insertions(+), 819 deletions(-) create mode 100644 ALL_CITATIONS.txt create mode 100644 addons/start_and_stop/start_and_stop.cpp create mode 100644 addons/start_and_stop/start_and_stop.h create mode 100644 config/PhysiCell_settings_2D.xml create mode 100644 config/PhysiCell_settings_3D.xml create mode 100644 config/TNF_conf.cfg create mode 100644 config/TNF_nodes.bnd create mode 100644 config/init.tsv create mode 100644 custom_modules/custom.cpp create mode 100644 custom_modules/custom.h create mode 100644 custom_modules/submodel_data_structures.cpp create mode 100644 custom_modules/submodel_data_structures.h create mode 100644 custom_modules/tnf_boolean_model_interface.cpp create mode 100644 custom_modules/tnf_boolean_model_interface.h create mode 100644 custom_modules/tnf_receptor_dynamics.cpp create mode 100644 custom_modules/tnf_receptor_dynamics.h rename output/empty.txt => main-backup.cpp (100%) create mode 100644 main.cpp create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/Makefile create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings.xml create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings_2D.xml create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings_3D.xml create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/config/TNF_conf.cfg create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/config/TNF_nodes.bnd create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/config/init.tsv create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/custom.cpp create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/custom.h create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/submodel_data_structures.cpp create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/submodel_data_structures.h create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_boolean_model_interface.cpp create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_boolean_model_interface.h create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_receptor_dynamics.cpp create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_receptor_dynamics.h create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/main-spheroid_TNF.cpp create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/params/cell_phases_dict.json create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/params/phases_grouping_dict.json create mode 100644 sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/plot_time_course.py create mode 100755 sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/summarize_simulation.py create mode 100644 scripts/params/cell_phases_dict.json create mode 100644 scripts/params/phases_grouping_dict.json create mode 100644 scripts/plot_time_course.py create mode 100755 scripts/summarize_simulation.py create mode 100755 spheroid_TNF_model create mode 100644 start_and_stop_saving_files/bool_data.txt create mode 100644 start_and_stop_saving_files/cell_data.txt create mode 100644 start_and_stop_saving_files/global_param.txt create mode 100644 start_and_stop_saving_files/initial.tsv create mode 100644 start_and_stop_saving_files/microenv_data.txt create mode 100644 start_and_stop_saving_files/random_counters.txt diff --git a/.gitignore b/.gitignore index c6e78d6e8..25744e2cf 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ project studio_debug.log user_projects/* !user_projects/empty.txt +output/* diff --git a/ALL_CITATIONS.txt b/ALL_CITATIONS.txt new file mode 100644 index 000000000..9c8a3800a --- /dev/null +++ b/ALL_CITATIONS.txt @@ -0,0 +1,7 @@ +Using PhysiBoSS version 2.2.3 + Please cite DOI: 10.1038/s41540-023-00314-4 + Project website: https://github.com/PhysiBoSS/PhysiBoSS +Using PhysiCell version 1.14.0 + Please cite DOI: 10.1371/journal.pcbi.1005991 + Project website: http://physicell.org + diff --git a/BioFVM/BioFVM_microenvironment.cpp b/BioFVM/BioFVM_microenvironment.cpp index 47e3d5621..517cb0389 100644 --- a/BioFVM/BioFVM_microenvironment.cpp +++ b/BioFVM/BioFVM_microenvironment.cpp @@ -50,6 +50,11 @@ #include "BioFVM_solvers.h" #include "BioFVM_vector.h" #include +#include +#include +#include +#include +#include "../core/PhysiCell_phenotype.h" #include "BioFVM_basic_agent.h" @@ -1613,4 +1618,770 @@ void get_row_from_substrate_initial_condition_csv(std::vector &voxel_set, c } voxel_set.push_back(voxel_ind); } + +std::ostream& operator<<(std::ostream& os, Microenvironment& S) +{ + os << std::endl << "Microenvironment summary: " << std::endl; + os << S.name << ": " << std::endl; + + os << "Microenvironment_private_data:" << std::endl; + //temporary_density_vectors1 + os << "temporary_density_vectors1:" << std::endl; + for (const auto& temporary_density_vectors1_v : S.temporary_density_vectors1) { + for( const auto& temporary_density_vectors1 : temporary_density_vectors1_v){ + os << temporary_density_vectors1 << " "; + }os << std::endl;} + os << std::endl; + + //temporary_density_vectors + os << "temporary_density_vectors2:" << std::endl; + for (const auto& temporary_density_vectors2_v : S.temporary_density_vectors2) { + for( const auto& temporary_density_vectors2 : temporary_density_vectors2_v){ + os << temporary_density_vectors2 << " "; + }os << std::endl;} + os << std::endl; + + //bulk_source_sink_solver_temp1 + os << "bulk_source_sink_solver_temp1:" << std::endl; + for (const auto& bulk_source_sink_solver_temp1_v : S.bulk_source_sink_solver_temp1) { + for( const auto& bulk_source_sink_solver_temp1 : bulk_source_sink_solver_temp1_v){ + os << bulk_source_sink_solver_temp1 << " "; + }os << std::endl;} + os << std::endl; + + //bulk_source_sink_solver_temp2 + os << "bulk_source_sink_solver_temp2:" << std::endl; + for (const auto& bulk_source_sink_solver_temp2_v : S.bulk_source_sink_solver_temp2) { + for( const auto& bulk_source_sink_solver_temp2 : bulk_source_sink_solver_temp2_v){ + os << bulk_source_sink_solver_temp2 << " "; + }os << std::endl;} + os << std::endl; + + //bulk_source_sink_solver_tem3 + os << "bulk_source_sink_solver_temp3:" << std::endl; + for (const auto& bulk_source_sink_solver_temp3_v : S.bulk_source_sink_solver_temp3) { + for( const auto& bulk_source_sink_solver_temp3 : bulk_source_sink_solver_temp3_v){ + os << bulk_source_sink_solver_temp3 << " "; + }os << std::endl;} + os << std::endl; + + //bulk_source_sink_solver_setup_done + os << "bulk_source_sink_solver_setup_done: " << (S.bulk_source_sink_solver_setup_done ? "true" : "false") << std::endl; + + //gradient_vectors + os << "gradient_vectors:" << std::endl; + for (const auto& gradient_vectors_v : S.gradient_vectors) { + for( const auto& gradient_vectors_n : gradient_vectors_v){ + for( const auto& gradient_vectors : gradient_vectors_n){ + os << gradient_vectors << " ";} + }os << std::endl;} + os << std::endl; + + //gradient_vector_computed + os << "gradient_vector_computed: "; + for (const auto& gradient_vector_computed : S.gradient_vector_computed) { + os << (gradient_vector_computed ? "true" : "false") << " "; + } + os << std::endl; + + //one + os << "one: "; + for (const auto& one : S.one) { + os << one << " "; + } + os << std::endl; + + //zero + os << "zero: "; + for (const auto& zero : S.zero) { + os << zero << " "; + } + os << std::endl; + + //one_half + os << "one_half: "; + for (const auto& one_half : S.one_half) { + os << one_half << " "; + } + os << std::endl; + + //one_third + os << "one_third: "; + for (const auto& one_third : S.one_third) { + os << one_third << " "; + } + os << std::endl; + + //thomas_temp1 + os << "thomas_temp1:" << std::endl; + for (const auto& thomas_temp1_v : S.thomas_temp1) { + for( const auto& thomas_temp1 : thomas_temp1_v){ + os << thomas_temp1 << " "; + }os << std::endl;} + os << std::endl; + + //thomas_temp2 + os << "thomas_temp2:" << std::endl; + for (const auto& thomas_temp2_v : S.thomas_temp2) { + for( const auto& thomas_temp2 : thomas_temp2_v){ + os << thomas_temp2 << " "; + }os << std::endl;} + os << std::endl; + + //thomas_constant1x + os << "thomas_constant1x: "; + for (const auto& thomas_constant1x : S.thomas_constant1x) { + os << thomas_constant1x << " "; + } + os << std::endl; + + //thomas_constant1y + os << "thomas_constant1y: "; + for (const auto& thomas_constant1y : S.thomas_constant1y) { + os << thomas_constant1y << " "; + } + os << std::endl; + + //thomas_constant1z + os << "thomas_constant1z: "; + for (const auto& thomas_constant1z : S.thomas_constant1z) { + os << thomas_constant1z << " "; + } + os << std::endl; + + //thomas_neg_constant1x + os << "thomas_neg_constant1x: "; + for (const auto& thomas_neg_constant1x : S.thomas_neg_constant1x) { + os << thomas_neg_constant1x << " "; + } + os << std::endl; + + //thomas_neg_constant1y + os << "thomas_neg_constant1y: "; + for (const auto& thomas_neg_constant1y : S.thomas_neg_constant1y) { + os << thomas_neg_constant1y << " "; + } + os << std::endl; + + //thomas_neg_constant1z + os << "thomas_neg_constant1z: "; + for (const auto& thomas_neg_constant1z : S.thomas_neg_constant1z) { + os << thomas_neg_constant1z << " "; + } + os << std::endl; + + //thomas_setup_done + os << "thomas_setup_done: " << (S.thomas_setup_done ? "true" : "false") << std::endl; + + //thomas_i_jump + os << "thomas_i_jump: " << S.thomas_i_jump << std::endl; + + //thomas_i_jump + os << "thomas_j_jump: " << S.thomas_j_jump << std::endl; + + //thomas_i_jump + os << "thomas_k_jump: " << S.thomas_k_jump << std::endl; + + //thomas_constant1 + os << "thomas_constant1: "; + for (const auto& thomas_constant1 : S.thomas_constant1) { + os << thomas_constant1 << " "; + } + os << std::endl; + + //thomas_constant1a + os << "thomas_constant1a: "; + for (const auto& thomas_constant1a : S.thomas_constant1a) { + os << thomas_constant1a << " "; + } + os << std::endl; + + //thomas_constant2 + os << "thomas_constant2: "; + for (const auto& thomas_constant2 : S.thomas_constant2) { + os << thomas_constant2 << " "; + } + os << std::endl; + + //thomas_constant3 + os << "thomas_constant3: "; + for (const auto& thomas_constant3 : S.thomas_constant3) { + os << thomas_constant3 << " "; + } + os << std::endl; + + //thomas_constant3a + os << "thomas_constant3a: "; + for (const auto& thomas_constant3a : S.thomas_constant3a) { + os << thomas_constant3a << " "; + } + os << std::endl; + + //name + os << "name: " << S.name << std::endl; + + //supply_rates + os << "supply_rates:" << std::endl; + for (const auto& supply_rates_v : S.supply_rates) { + for( const auto& supply_rates : supply_rates_v){ + os << supply_rates << " "; + }os << std::endl;} + os << std::endl; + + //uptake_rates + os << "uptake_rates:" << std::endl; + for (const auto& uptake_rates_v : S.uptake_rates) { + for( const auto& uptake_rates : uptake_rates_v){ + os << uptake_rates << " "; + }os << std::endl;} + os << std::endl; + + os << "Densities: " << S.number_of_densities() << std::endl; + for (unsigned int i = 0; i < S.density_names.size(); i++) + { + os << S.density_names[i] << std::endl + << "units: " << S.density_units[i] << std::endl + << "diffusion_coefficient: " << S.diffusion_coefficients[i] + << " " << S.spatial_units << " " << S.time_units << std::endl + << "decay_rate: " << S.decay_rates[i] + << " " << S.time_units << std::endl; + } + os << "\n"; + // Display all the densities for each voxel. + os << "Values for each voxel: " << std::endl; + for (unsigned int n = 0; n < S.number_of_voxels(); n++) + { + os << S.density_vector(n) << std::endl; + } + os << std::endl; + + os << "centers of voxels: " << std::endl; + for (unsigned int n = 0; n < S.number_of_voxels(); n++) + { + os << S.voxels(n).center << std::endl; + } + os << std::endl; + return os; +} + +std::istream& operator>>(std::istream& is, Microenvironment& microenv){ + + std::string dummy; + double value; + int j = 0; + std::string value_2; + + // read headers + std::getline(is, dummy); + std::getline(is, dummy); + std::getline(is, dummy); + std::getline(is, dummy); + + //temporary_density_vectors1 + std::getline(is, dummy); + + unsigned int n_lines = 0; + + for( unsigned int n=0; n < microenv.temporary_density_vectors1.size() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + j = 0; + while(stream4 >> value) { + microenv.temporary_density_vectors1[n][j] = value; + j = j+1; + } + } + + + + assert(n_lines == microenv.temporary_density_vectors1.size()); + //read empty line + std::getline(is, dummy); + + //temporary_density_vectors2 + std::getline(is, dummy); + + n_lines = 0; + for( unsigned int n=0; n < microenv.temporary_density_vectors2.size() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + j = 0; + while(stream4 >> value) { + microenv.temporary_density_vectors2[n][j] = value; + j = j+1; + } + } + + + assert(n_lines == microenv.temporary_density_vectors2.size()); + //read empty line + std::getline(is, dummy); + + //bulk_source_sink_solver_temp1 + std::getline(is, dummy); + n_lines = 0; + for( unsigned int n=0; n < microenv.bulk_source_sink_solver_temp1.size() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + j = 0; + while(stream4 >> value) { + microenv.bulk_source_sink_solver_temp1[n][j] = value; + j = j+1; + } + } + + assert(n_lines == microenv.bulk_source_sink_solver_temp1.size()); + //read empty line + std::getline(is, dummy); + + //bulk_source_sink_solver_temp2 + std::getline(is, dummy); + n_lines = 0; + for( unsigned int n=0; n < microenv.bulk_source_sink_solver_temp2.size() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + j = 0; + while(stream4 >> value) { + microenv.bulk_source_sink_solver_temp2[n][j] = value; + j = j+1; + } + } + assert(n_lines == microenv.bulk_source_sink_solver_temp2.size()); + //read empty line + std::getline(is, dummy); + + //bulk_source_sink_solver_temp3 + std::getline(is, dummy); + n_lines = 0; + for( unsigned int n=0; n < microenv.bulk_source_sink_solver_temp3.size() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + j = 0; + while(stream4 >> value) { + microenv.bulk_source_sink_solver_temp3[n][j] = value; + j = j+1; + } + } + assert(n_lines == microenv.bulk_source_sink_solver_temp3.size()); + + //read empty line + std::getline(is, dummy); + + //bulk_source_sink_solver_setup_done + std::getline(is, dummy); + microenv.bulk_source_sink_solver_setup_done = read_number_in_line_bool(dummy); + + + //gradient_vectors + std::getline(is, dummy); + + n_lines = 0; + for (unsigned int n = 0; n < microenv.gradient_vectors.size(); n++) + { std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + for (unsigned int l = 0; l < microenv.gradient_vectors[n].size(); l++) + { + + double value; + for (int j = 0; j < microenv.gradient_vectors[n][l].size(); j++) + { + stream4 >> value; + microenv.gradient_vectors[n][l][j] = value; + } + } + } + assert(n_lines == microenv.gradient_vectors.size()); + + + //skip empty line + std::getline(is, dummy); + + //gradient_vector_computed + std::getline(is, dummy); + bool gradient_vector_computed; + std::istringstream stream_gradient_vector_computed(dummy); + std::string key_gradient_vector_computed; + stream_gradient_vector_computed >> key_gradient_vector_computed; + for (int i = 0; i < microenv.gradient_vector_computed.size(); i++){ + stream_gradient_vector_computed >> value; + if(value_2 == "true"){ + gradient_vector_computed = true; + } + else if(value_2 == "false"){ + gradient_vector_computed = false; + } + microenv.gradient_vector_computed[i] = gradient_vector_computed; + } + + // one + std::getline(is, dummy); + std::istringstream stream_one(dummy); + std::string key_one; + stream_one >> key_one; + std::vector one; + while(stream_one >> value) { + one.push_back(value); + } + microenv.one.clear(); + microenv.one = one; + + // zero + std::getline(is, dummy); + std::istringstream stream_zero(dummy); + std::string key_zero; + stream_zero >> key_zero; + std::vector zero; + while(stream_zero >> value) { + zero.push_back(value); + } + microenv.zero.clear(); + microenv.zero = zero; + + // one_half + std::getline(is, dummy); + std::istringstream stream_one_half(dummy); + std::string key_one_half; + stream_one_half >> key_one_half; + std::vector one_half; + while(stream_one_half >> value) { + one_half.push_back(value); + } + microenv.one_half.clear(); + microenv.one_half = one_half; + + // one_third + std::getline(is, dummy); + std::istringstream stream_one_third(dummy); + std::string key_one_third; + stream_one_third >> key_one_third; + std::vector one_third; + while(stream_one_third >> value) { + one_third.push_back(value); + } + microenv.one_third.clear(); + microenv.one_third = one_third; + + //thomas_temp1 + std::getline(is, dummy); + n_lines = 0; + for( unsigned int n=0; n < microenv.thomas_temp1.size() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + j = 0; + while(stream4 >> value) { + microenv.thomas_temp1[n][j] = value; + j = j+1; + } + } + + assert(n_lines == microenv.thomas_temp1.size()); + //read empty line + std::getline(is, dummy); + + //thomas_temp2 + std::getline(is, dummy); + n_lines = 0; + for( unsigned int n=0; n < microenv.thomas_temp2.size() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + j = 0; + while(stream4 >> value) { + microenv.thomas_temp2[n][j] = value; + j = j+1; + } + } + assert(n_lines == microenv.thomas_temp2.size()); + //read empty line + std::getline(is, dummy); + + // thomas_constant1x + std::getline(is, dummy); + std::istringstream stream_thomas_constant1x(dummy); + std::string key_thomas_constant1x; + stream_thomas_constant1x >> key_thomas_constant1x; + std::vector thomas_constant1x; + while(stream_thomas_constant1x >> value) { + thomas_constant1x.push_back(value); + } + microenv.thomas_constant1x.clear(); + microenv.thomas_constant1x = thomas_constant1x; + + // thomas_constant1y + std::getline(is, dummy); + std::istringstream stream_thomas_constant1y(dummy); + std::string key_thomas_constant1y; + stream_thomas_constant1y >> key_thomas_constant1y; + std::vector thomas_constant1y; + while(stream_thomas_constant1y >> value) { + thomas_constant1y.push_back(value); + } + microenv.thomas_constant1y.clear(); + microenv.thomas_constant1y = thomas_constant1y; + + // thomas_constant1z + std::getline(is, dummy); + std::istringstream stream_thomas_constant1z(dummy); + std::string key_thomas_constant1z; + stream_thomas_constant1z >> key_thomas_constant1z; + std::vector thomas_constant1z; + while(stream_thomas_constant1z >> value) { + thomas_constant1z.push_back(value); + } + microenv.thomas_constant1z.clear(); + microenv.thomas_constant1z = thomas_constant1z; + + // thomas_neg_constant1x + std::getline(is, dummy); + std::istringstream stream_thomas_neg_constant1x(dummy); + std::string key_thomas_neg_constant1x; + stream_thomas_neg_constant1x >> key_thomas_neg_constant1x; + std::vector thomas_neg_constant1x; + while(stream_thomas_neg_constant1x >> value) { + thomas_neg_constant1x.push_back(value); + } + microenv.thomas_neg_constant1x.clear(); + microenv.thomas_neg_constant1x = thomas_neg_constant1x; + + // thomas_neg_constant1y + std::getline(is, dummy); + std::istringstream stream_thomas_neg_constant1y(dummy); + std::string key_thomas_neg_constant1y; + stream_thomas_neg_constant1y >> key_thomas_neg_constant1y; + std::vector thomas_neg_constant1y; + while(stream_thomas_neg_constant1y >> value) { + thomas_neg_constant1y.push_back(value); + } + microenv.thomas_neg_constant1y.clear(); + microenv.thomas_neg_constant1y = thomas_neg_constant1y; + + // thomas_neg_constant1y + std::getline(is, dummy); + std::istringstream stream_thomas_neg_constant1z(dummy); + std::string key_thomas_neg_constant1z; + stream_thomas_neg_constant1z >> key_thomas_neg_constant1z; + std::vector thomas_neg_constant1z; + while(stream_thomas_neg_constant1z >> value) { + thomas_neg_constant1z.push_back(value); + } + microenv.thomas_neg_constant1z.clear(); + microenv.thomas_neg_constant1z = thomas_neg_constant1z; + + //thomas_setup_done + std::getline(is, dummy); + microenv.thomas_setup_done = read_number_in_line_bool(dummy); + + //thomas_i_jump + std::getline(is, dummy); + microenv.thomas_i_jump = read_number_in_line_int(dummy); + + //thomas_j_jump + std::getline(is, dummy); + microenv.thomas_j_jump = read_number_in_line_int(dummy); + + //thomas_k_jump + std::getline(is, dummy); + microenv.thomas_k_jump = read_number_in_line_int(dummy); + + // thomas_constant1 + std::getline(is, dummy); + std::istringstream stream_thomas_constant1(dummy); + std::string key_thomas_constant1; + stream_thomas_constant1 >> key_thomas_constant1; + std::vector thomas_constant1; + while(stream_thomas_constant1 >> value) { + thomas_constant1.push_back(value); + } + microenv.thomas_constant1.clear(); + microenv.thomas_constant1 = thomas_constant1; + + // thomas_constant1a + std::getline(is, dummy); + std::istringstream stream_thomas_constant1a(dummy); + std::string key_thomas_constant1a; + stream_thomas_constant1a >> key_thomas_constant1a; + std::vector thomas_constant1a; + while(stream_thomas_constant1a >> value) { + thomas_constant1a.push_back(value); + } + microenv.thomas_constant1a.clear(); + microenv.thomas_constant1a = thomas_constant1a; + + // thomas_constant2 + std::getline(is, dummy); + std::istringstream stream_thomas_constant2(dummy); + std::string key_thomas_constant2; + stream_thomas_constant2 >> key_thomas_constant2; + std::vector thomas_constant2; + while(stream_thomas_constant2 >> value) { + thomas_constant2.push_back(value); + } + microenv.thomas_constant2.clear(); + microenv.thomas_constant2 = thomas_constant2; + + // thomas_constant3 + std::getline(is, dummy); + std::istringstream stream_thomas_constant3(dummy); + std::string key_thomas_constant3; + stream_thomas_constant3 >> key_thomas_constant3; + std::vector thomas_constant3; + while(stream_thomas_constant3 >> value) { + thomas_constant3.push_back(value); + } + microenv.thomas_constant3.clear(); + microenv.thomas_constant3 = thomas_constant3; + + // thomas_constant3a + std::getline(is, dummy); + std::istringstream stream_thomas_constant3a(dummy); + std::string key_thomas_constant3a; + stream_thomas_constant3a >> key_thomas_constant3a; + std::vector thomas_constant3a; + while(stream_thomas_constant3a >> value) { + thomas_constant3a.push_back(value); + } + microenv.thomas_constant3a.clear(); + microenv.thomas_constant3a = thomas_constant3a; + + //name + std::getline(is, dummy); + std::istringstream stream_name(dummy); + std::string key_name; + stream_name >> key_name >> value_2; + microenv.name = value_2; + + //supply_rates + std::getline(is, dummy); + n_lines = 0; + for( unsigned int n=0; n < microenv.supply_rates.size() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + j = 0; + while(stream4 >> value) { + microenv.supply_rates[n][j] = value; + j = j+1; + } + } + assert(n_lines == microenv.supply_rates.size()); + //read empty line + std::getline(is, dummy); + + //uptake_rates + std::getline(is, dummy); + n_lines = 0; + for( unsigned int n=0; n < microenv.uptake_rates.size() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + j = 0; + while(stream4 >> value) { + microenv.uptake_rates[n][j] = value; + j = j+1; + } + } + assert(n_lines == microenv.uptake_rates.size()); + //read empty line + std::getline(is, dummy); + + //number_of_densities + std::getline(is, dummy); + + double number_of_densities; + std::istringstream stream(dummy); + std::string key; + stream >> key; + double number; + while(stream >> number) { + number_of_densities = number; + } + + for (size_t i = 0; i < number_of_densities; ++i) { + //get name + std::string name; + std::getline(is, name); + microenv.density_names[i] = name; + + + // get unit + std::getline(is, dummy); + std::istringstream stream(dummy); + std::string key; + std::string unit; + stream >> key; + stream >> unit; + microenv.density_units[i] = unit; + + // get diffusion_coefficient + std::string spatial_unit; + std::string time_unit; + std::getline(is, dummy); + std::istringstream stream2(dummy); + double diffusion_coefficient; + stream2 >> key; + stream2 >> diffusion_coefficient; + stream2 >> spatial_unit; + stream2 >> time_unit; + microenv.diffusion_coefficients[i] = diffusion_coefficient; + microenv.spatial_units = spatial_unit; + microenv.time_units = time_unit; + + + //get decay rate + std::getline(is, dummy); + std::istringstream stream3(dummy); + double decay_rate; + stream3 >> key; + stream3 >> decay_rate; + microenv.decay_rates[i] = decay_rate; + } + + // skip empty line + std::getline(is, dummy); + + // skip header + std::getline(is, dummy); + + n_lines = 0; + //reassign all values for all the voxels. + for( unsigned int n=0; n < microenv.number_of_voxels() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + double value; + int j = 0; + while(stream4 >> value) { + microenv.density_vector(n)[j] = value; + j = j+1; + } + } + assert(n_lines == microenv.number_of_voxels()); + + std::getline(is, dummy); + std::getline(is, dummy); + + //reassign all values for all the voxels. + n_lines = 0; + for( unsigned int n=0; n < microenv.number_of_voxels() ; n++ ) + { + std::getline(is, dummy); n_lines++; + std::istringstream stream4(dummy); + double value; + int j = 0; + while(stream4 >> value) { + microenv.voxels(n).center[j] = value; + j = j+1; + } + } + assert(n_lines == microenv.number_of_voxels()); + + + return is; +} }; diff --git a/BioFVM/BioFVM_microenvironment.h b/BioFVM/BioFVM_microenvironment.h index 8b894e880..c8593051d 100644 --- a/BioFVM/BioFVM_microenvironment.h +++ b/BioFVM/BioFVM_microenvironment.h @@ -237,6 +237,8 @@ class Microenvironment void simulate_cell_sources_and_sinks( double dt ); void display_information( std::ostream& os ); + friend std::ostream& operator<<(std::ostream& os, Microenvironment& S); + friend std::istream& operator>>(std::istream& is, Microenvironment& microenv); void add_dirichlet_node( int voxel_index, std::vector& value ); void update_dirichlet_node( int voxel_index , std::vector& new_value ); diff --git a/Makefile b/Makefile index 440b03cf0..5bab5c2a0 100644 --- a/Makefile +++ b/Makefile @@ -1,536 +1,282 @@ -VERSION := $(shell grep . VERSION.txt | cut -f1 -d:) -PROGRAM_NAME := project - -CC := g++ -# CC := g++-mp-7 # typical macports compiler name -# CC := g++-7 # typical homebrew compiler name - -# Check for environment definitions of compiler -# e.g., on CC = g++-7 on OSX -ifdef PHYSICELL_CPP - CC := $(PHYSICELL_CPP) -endif - -ARCH := native # best auto-tuning -# ARCH := core2 # a reasonably safe default for most CPUs since 2007 -# ARCH := corei7 -# ARCH := core-avx-i # i7 ivy bridge or newer -# ARCH := core-avx2 # i7 with Haswell or newer -# ARCH := silvermont -# ARCH := skylake-avx512 -# ARCH := nocona #64-bit pentium 4 or later - -# CFLAGS := -march=$(ARCH) -Ofast -s -fomit-frame-pointer -mfpmath=both -fopenmp -m64 -std=c++11 -CFLAGS := -march=$(ARCH) -O3 -fomit-frame-pointer -mfpmath=both -fopenmp -m64 -std=c++11 - -ifeq ($(OS),Windows_NT) -else - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - UNAME_P := $(shell uname -p) - var := $(shell which $(CC) | xargs file) - ifeq ($(lastword $(var)),arm64) - CFLAGS := -march=$(ARCH) -O3 -fomit-frame-pointer -fopenmp -m64 -std=c++11 - endif - endif -endif - -COMPILE_COMMAND := $(CC) $(CFLAGS) - -BioFVM_OBJECTS := BioFVM_vector.o BioFVM_mesh.o BioFVM_microenvironment.o BioFVM_solvers.o BioFVM_matlab.o \ -BioFVM_utilities.o BioFVM_basic_agent.o BioFVM_MultiCellDS.o BioFVM_agent_container.o - -PhysiCell_core_OBJECTS := PhysiCell_phenotype.o PhysiCell_cell_container.o PhysiCell_standard_models.o \ -PhysiCell_cell.o PhysiCell_custom.o PhysiCell_utilities.o PhysiCell_constants.o PhysiCell_basic_signaling.o \ -PhysiCell_signal_behavior.o PhysiCell_rules.o - -PhysiCell_module_OBJECTS := PhysiCell_SVG.o PhysiCell_pathology.o PhysiCell_MultiCellDS.o PhysiCell_various_outputs.o \ -PhysiCell_pugixml.o PhysiCell_settings.o PhysiCell_geometry.o - -# put your custom objects here (they should be in the custom_modules directory) - -PhysiCell_custom_module_OBJECTS := .o - -pugixml_OBJECTS := pugixml.o - -PhysiCell_OBJECTS := $(BioFVM_OBJECTS) $(pugixml_OBJECTS) $(PhysiCell_core_OBJECTS) $(PhysiCell_module_OBJECTS) -ALL_OBJECTS := $(PhysiCell_OBJECTS) $(PhysiCell_custom_module_OBJECTS) - -EXAMPLES := ./examples/PhysiCell_test_mechanics_1.cpp ./examples/PhysiCell_test_mechanics_2.cpp \ - ./examples/PhysiCell_test_DCIS.cpp ./examples/PhysiCell_test_HDS.cpp \ - ./examples/PhysiCell_test_cell_cycle.cpp ./examples/PhysiCell_test_volume.cpp - -all: - make heterogeneity-sample - make - -name: - @echo "" - @echo "Executable name is" $(PROGRAM_NAME) - @echo "" - -# sample projects -list-projects: - @echo "Sample projects: template biorobots-sample cancer-biorobots-sample cancer-immune-sample" - @echo " celltypes3-sample heterogeneity-sample pred-prey-farmer virus-macrophage-sample" - @echo " worm-sample interaction-sample mechano-sample rules-sample physimess-sample custom-division-sample" - @echo "" - @echo "Sample intracellular projects: template_BM ode-energy-sample physiboss-cell-lines-sample" - @echo " cancer-metabolism-sample physiboss-tutorial physiboss-tutorial-invasion" - @echo "" - -template: - cp -r ./sample_projects/template/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/template/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/template/Makefile . - cp -r ./sample_projects/template/config/* ./config - -# sample projects - -# ---- non-intracellular projects -biorobots-sample: - cp ./sample_projects/biorobots/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/biorobots/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/biorobots/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/biorobots/config/* ./config/ - -cancer-biorobots-sample: - cp ./sample_projects/cancer_biorobots/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/cancer_biorobots/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/cancer_biorobots/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/cancer_biorobots/config/* ./config/ - -cancer-immune-sample: - cp ./sample_projects/cancer_immune/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/cancer_immune/main-cancer_immune_3D.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/cancer_immune/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/cancer_immune/config/* ./config/ - -celltypes3-sample: - cp ./sample_projects/celltypes3/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/celltypes3/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/celltypes3/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/celltypes3/config/* ./config/ - -heterogeneity-sample: - cp ./sample_projects/heterogeneity/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/heterogeneity/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/heterogeneity/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/heterogeneity/config/* ./config/ - -pred-prey-farmer: - cp ./sample_projects/pred_prey_farmer/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/pred_prey_farmer/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/pred_prey_farmer/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/pred_prey_farmer/config/* ./config/ - -virus-macrophage-sample: - cp ./sample_projects/virus_macrophage/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/virus_macrophage/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/virus_macrophage/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/virus_macrophage/config/* ./config/ - -worm-sample: - cp ./sample_projects/worm/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/worm/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/worm/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/worm/config/* ./config/ - -interaction-sample: - cp ./sample_projects/interactions/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/interactions/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/interactions/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/interactions/config/* ./config/ - -mechano-sample: - cp ./sample_projects/mechano/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/mechano/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/mechano/Makefile . - cp ./sample_projects/mechano/config/* ./config/ - -rules-sample: - cp ./sample_projects/rules_sample/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/rules_sample/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/rules_sample/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/rules_sample/config/* ./config/ - -physimess-sample: - cp ./sample_projects/physimess/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/physimess/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/physimess/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp -r ./sample_projects/physimess/config/* ./config/ - - -custom-division-sample: - cp ./sample_projects/custom_division/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects/custom_division/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects/custom_division/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects/custom_division/config/* ./config/ - -# ---- intracellular projects -ode-energy-sample: - cp ./sample_projects_intracellular/ode/ode_energy/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects_intracellular/ode/ode_energy/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects_intracellular/ode/ode_energy/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects_intracellular/ode/ode_energy/config/* ./config/ - -physiboss-cell-lines-sample: - cp ./sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects_intracellular/boolean/physiboss_cell_lines/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects_intracellular/boolean/physiboss_cell_lines/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects_intracellular/boolean/physiboss_cell_lines/config/* ./config/ - -physiboss-tutorial: - cp ./sample_projects_intracellular/boolean/tutorial/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects_intracellular/boolean/tutorial/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects_intracellular/boolean/tutorial/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp -r ./sample_projects_intracellular/boolean/tutorial/config/* ./config/ - -physiboss-tutorial-invasion: - cp ./sample_projects_intracellular/boolean/cancer_invasion/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects_intracellular/boolean/cancer_invasion/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects_intracellular/boolean/cancer_invasion/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp -r ./sample_projects_intracellular/boolean/cancer_invasion/config/* ./config/ - -ecoli-acetic-switch-sample: - cp ./sample_projects_intracellular/fba/ecoli_acetic_switch/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects_intracellular/fba/ecoli_acetic_switch/main_ecoli_acetic_switch.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects_intracellular/fba/ecoli_acetic_switch/Makefile ./ - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects_intracellular/fba/ecoli_acetic_switch/config/* ./config/ - -cancer-metabolism-sample: - cp ./sample_projects_intracellular/fba/cancer_metabolism/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects_intracellular/fba/cancer_metabolism/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects_intracellular/fba/cancer_metabolism/Makefile ./ - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./sample_projects_intracellular/fba/cancer_metabolism/config/* ./config/ - -template_BM: - cp ./sample_projects_intracellular/boolean/template_BM/custom_modules/* ./custom_modules/ - touch main.cpp && cp main.cpp main-backup.cpp - cp ./sample_projects_intracellular/boolean/template_BM/main.cpp ./main.cpp - cp Makefile Makefile-backup - cp ./sample_projects_intracellular/boolean/template_BM/Makefile . - cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp -r ./sample_projects_intracellular/boolean/template_BM/config/* ./config/ - mkdir ./scripts/ - cp ./sample_projects_intracellular/boolean/template_BM/scripts/* ./scripts/ - -# early examples for convergence testing - -physicell_test_mech1: $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_mechanics_1.cpp - $(COMPILE_COMMAND) -o test_mech1 $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_mechanics_1.cpp - -physicell_test_mech2: $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_mechanics_2.cpp - $(COMPILE_COMMAND) -o test_mech2 $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_mechanics_2.cpp - -physicell_test_DCIS: $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_DCIS.cpp - $(COMPILE_COMMAND) -o test_DCIS $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_DCIS.cpp - -physicell_test_HDS: $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_HDS.cpp - $(COMPILE_COMMAND) -o test_HDS $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_HDS.cpp - -physicell_test_cell_cycle: $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_cell_cycle.cpp - $(COMPILE_COMMAND) -o test_cycle $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_cell_cycle.cpp - -PhysiCell_test_volume: $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_volume.cpp - $(COMPILE_COMMAND) -o test_volume $(PhysiCell_OBJECTS) ./examples/PhysiCell_test_volume.cpp - -examples: $(PhysiCell_OBJECTS) - $(COMPILE_COMMAND) -o ./examples/test_mech1 ./examples/PhysiCell_test_mechanics_1.cpp $(PhysiCell_OBJECTS) - $(COMPILE_COMMAND) -o ./examples/test_mech2 ./examples/PhysiCell_test_mechanics_2.cpp $(PhysiCell_OBJECTS) - $(COMPILE_COMMAND) -o ./examples/test_DCIS ./examples/PhysiCell_test_DCIS.cpp $(PhysiCell_OBJECTS) - $(COMPILE_COMMAND) -o ./examples/test_HDS ./examples/PhysiCell_test_HDS.cpp $(PhysiCell_OBJECTS) - $(COMPILE_COMMAND) -o ./examples/test_cycle ./examples/PhysiCell_test_cell_cycle.cpp $(PhysiCell_OBJECTS) - $(COMPILE_COMMAND) -o ./examples/test_volume ./examples/PhysiCell_test_volume.cpp $(PhysiCell_OBJECTS) - -# PhysiCell core components - -PhysiCell_phenotype.o: ./core/PhysiCell_phenotype.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_phenotype.cpp - -PhysiCell_digital_cell_line.o: ./core/PhysiCell_digital_cell_line.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_digital_cell_line.cpp - -PhysiCell_cell.o: ./core/PhysiCell_cell.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_cell.cpp - -PhysiCell_cell_container.o: ./core/PhysiCell_cell_container.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_cell_container.cpp - -PhysiCell_standard_models.o: ./core/PhysiCell_standard_models.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_standard_models.cpp - -PhysiCell_utilities.o: ./core/PhysiCell_utilities.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_utilities.cpp - -PhysiCell_custom.o: ./core/PhysiCell_custom.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_custom.cpp - -PhysiCell_constants.o: ./core/PhysiCell_constants.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_constants.cpp - -PhysiCell_signal_behavior.o: ./core/PhysiCell_signal_behavior.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_signal_behavior.cpp - -PhysiCell_rules.o: ./core/PhysiCell_rules.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_rules.cpp - -# BioFVM core components (needed by PhysiCell) - -BioFVM_vector.o: ./BioFVM/BioFVM_vector.cpp - $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_vector.cpp - -BioFVM_agent_container.o: ./BioFVM/BioFVM_agent_container.cpp - $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_agent_container.cpp - -BioFVM_mesh.o: ./BioFVM/BioFVM_mesh.cpp - $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_mesh.cpp - -BioFVM_microenvironment.o: ./BioFVM/BioFVM_microenvironment.cpp - $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_microenvironment.cpp - -BioFVM_solvers.o: ./BioFVM/BioFVM_solvers.cpp - $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_solvers.cpp - -BioFVM_utilities.o: ./BioFVM/BioFVM_utilities.cpp - $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_utilities.cpp - -BioFVM_basic_agent.o: ./BioFVM/BioFVM_basic_agent.cpp - $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_basic_agent.cpp - -BioFVM_matlab.o: ./BioFVM/BioFVM_matlab.cpp - $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_matlab.cpp - -BioFVM_MultiCellDS.o: ./BioFVM/BioFVM_MultiCellDS.cpp - $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_MultiCellDS.cpp - -pugixml.o: ./BioFVM/pugixml.cpp - $(COMPILE_COMMAND) -c ./BioFVM/pugixml.cpp - -# standard PhysiCell modules - -PhysiCell_SVG.o: ./modules/PhysiCell_SVG.cpp - $(COMPILE_COMMAND) -c ./modules/PhysiCell_SVG.cpp - -PhysiCell_pathology.o: ./modules/PhysiCell_pathology.cpp - $(COMPILE_COMMAND) -c ./modules/PhysiCell_pathology.cpp - -PhysiCell_MultiCellDS.o: ./modules/PhysiCell_MultiCellDS.cpp - $(COMPILE_COMMAND) -c ./modules/PhysiCell_MultiCellDS.cpp - -PhysiCell_various_outputs.o: ./modules/PhysiCell_various_outputs.cpp - $(COMPILE_COMMAND) -c ./modules/PhysiCell_various_outputs.cpp - -PhysiCell_pugixml.o: ./modules/PhysiCell_pugixml.cpp - $(COMPILE_COMMAND) -c ./modules/PhysiCell_pugixml.cpp - -PhysiCell_settings.o: ./modules/PhysiCell_settings.cpp - $(COMPILE_COMMAND) -c ./modules/PhysiCell_settings.cpp - -PhysiCell_basic_signaling.o: ./core/PhysiCell_basic_signaling.cpp - $(COMPILE_COMMAND) -c ./core/PhysiCell_basic_signaling.cpp - -PhysiCell_geometry.o: ./modules/PhysiCell_geometry.cpp - $(COMPILE_COMMAND) -c ./modules/PhysiCell_geometry.cpp - -# user-defined PhysiCell modules - -# cleanup - -reset: - rm -f *.cpp PhysiCell_cell.o - cp ./sample_projects/Makefile-default Makefile - rm -rf ./custom_modules/* - touch ./custom_modules/empty.txt - touch ALL_CITATIONS.txt - touch ./core/PhysiCell_cell.cpp - rm ALL_CITATIONS.txt - cp ./config/PhysiCell_settings-backup.xml ./config/PhysiCell_settings.xml - touch ./config/empty.csv - rm ./config/*.csv - -clean: - rm -f *.o - rm -f $(PROGRAM_NAME)* - -data-cleanup: - rm -rf ./output - mkdir ./output - touch ./output/empty.txt - -# archival - -checkpoint: - zip -r $$(date +%b_%d_%Y_%H%M).zip Makefile *.cpp *.h config/*.xml custom_modules/* - -zip: - zip -r latest.zip Makefile* *.cpp *.h BioFVM/* config/* core/* custom_modules/* matlab/* modules/* sample_projects/* - cp latest.zip $$(date +%b_%d_%Y_%H%M).zip - cp latest.zip VERSION_$(VERSION).zip - mv *.zip archives/ - -tar: - tar --ignore-failed-read -czf latest.tar Makefile* *.cpp *.h BioFVM/* config/* core/* custom_modules/* matlab/* modules/* sample_projects/* - cp latest.tar $$(date +%b_%d_%Y_%H%M).tar - cp latest.tar VERSION_$(VERSION).tar - mv *.tar archives/ - -unzip: - cp ./archives/latest.zip . - unzip latest.zip - -untar: - cp ./archives/latest.tar . - tar -xzf latest.tar - -# easier animation - -FRAMERATE := 24 -OUTPUT := output - -jpeg: - @magick identify -format "%h" $(OUTPUT)/initial.svg > __H.txt - @magick identify -format "%w" $(OUTPUT)/initial.svg > __W.txt - @expr 2 \* \( $$(grep . __H.txt) / 2 \) > __H1.txt - @expr 2 \* \( $$(grep . __W.txt) / 2 \) > __W1.txt - @echo "$$(grep . __W1.txt)!x$$(grep . __H1.txt)!" > __resize.txt - @magick mogrify -format jpg -resize $$(grep . __resize.txt) $(OUTPUT)/s*.svg - rm -f __H*.txt __W*.txt __resize.txt - -gif: - magick convert $(OUTPUT)/s*.svg $(OUTPUT)/out.gif - -movie: - ffmpeg -r $(FRAMERATE) -f image2 -i $(OUTPUT)/snapshot%08d.jpg -vcodec libx264 -pix_fmt yuv420p -strict -2 -tune animation -crf 15 -acodec none $(OUTPUT)/out.mp4 - -# upgrade rules - -SOURCE := PhysiCell_upgrade.zip -get-upgrade: - @echo $$(curl https://raw.githubusercontent.com/MathCancer/PhysiCell/master/VERSION.txt) > VER.txt - @echo https://github.com/MathCancer/PhysiCell/releases/download/$$(grep . VER.txt)/PhysiCell_V.$$(grep . VER.txt).zip > DL_FILE.txt - rm -f VER.txt - $$(curl -L $$(grep . DL_FILE.txt) --output PhysiCell_upgrade.zip) - rm -f DL_FILE.txt - -PhysiCell_upgrade.zip: - make get-upgrade - -upgrade: $(SOURCE) - unzip $(SOURCE) PhysiCell/VERSION.txt - mv -f PhysiCell/VERSION.txt . - unzip $(SOURCE) PhysiCell/core/* - cp -r PhysiCell/core/* core - unzip $(SOURCE) PhysiCell/modules/* - cp -r PhysiCell/modules/* modules - unzip $(SOURCE) PhysiCell/sample_projects/* - cp -r PhysiCell/sample_projects/* sample_projects - unzip $(SOURCE) PhysiCell/BioFVM/* - cp -r PhysiCell/BioFVM/* BioFVM - unzip $(SOURCE) PhysiCell/documentation/User_Guide.pdf - mv -f PhysiCell/documentation/User_Guide.pdf documentation - rm -f -r PhysiCell - rm -f $(SOURCE) - -# use: make save PROJ=your_project_name -PROJ := my_project - -save: - echo "Saving project as $(PROJ) ... " - mkdir -p ./user_projects - mkdir -p ./user_projects/$(PROJ) - mkdir -p ./user_projects/$(PROJ)/custom_modules - mkdir -p ./user_projects/$(PROJ)/config - cp main.cpp ./user_projects/$(PROJ) - cp Makefile ./user_projects/$(PROJ) - cp VERSION.txt ./user_projects/$(PROJ) - cp -r ./config/* ./user_projects/$(PROJ)/config - cp -r ./custom_modules/* ./user_projects/$(PROJ)/custom_modules - -load: - echo "Loading project from $(PROJ) ... " - cp ./user_projects/$(PROJ)/main.cpp . - cp ./user_projects/$(PROJ)/Makefile . - cp -r ./user_projects/$(PROJ)/config/* ./config/ - cp -r ./user_projects/$(PROJ)/custom_modules/* ./custom_modules/ - -pack: - @echo " " - @echo "Preparing project $(PROJ) for sharing ... " - @echo " " - cd ./user_projects && zip -r $(PROJ).zip $(PROJ) - @echo " " - @echo "Share ./user_projects/$(PROJ).zip ... " - @echo "Other users can unzip $(PROJ).zip in their ./user_projects, compile, and run." - @echo " " - -unpack: - @echo " " - @echo "Preparing shared project $(PROJ).zip for use ... " - @echo " " - cd ./user_projects && unzip $(PROJ).zip - @echo " " - @echo "Load this project via make load PROJ=$(PROJ) ... " - @echo " " - -list-user-projects: - @echo "user projects::" - @cd ./user_projects && ls -dt1 * | grep . | sed 's!empty.txt!!' +VERSION := $(shell grep . VERSION.txt | cut -f1 -d:) +PROGRAM_NAME := spheroid_TNF_model + +CC := g++ +# CC := g++-mp-7 # typical macports compiler name +# CC := g++-7 # typical homebrew compiler name + +# Check for environment definitions of compiler +# e.g., on CC = g++-7 on OSX +ifdef PHYSICELL_CPP + CC := $(PHYSICELL_CPP) +endif + +### MaBoSS configuration +# MaBoSS max nodes +ifndef MABOSS_MAX_NODES +MABOSS_MAX_NODES = 64 +endif + +# MaBoSS directory +MABOSS_DIR = addons/PhysiBoSS/MaBoSS/engine +CUR_DIR = $(shell pwd) + +ifneq ($(OS), Windows_NT) + LDL_FLAG = -ldl +endif + +LIB := -L$(CUR_DIR)/$(MABOSS_DIR)/lib -lMaBoSS-static $(LDL_FLAG) +INC := -DADDON_PHYSIBOSS -I$(CUR_DIR)/$(MABOSS_DIR)/include -DMAXNODES=$(MABOSS_MAX_NODES) + + +# If max nodes > 64, change lib path +ifeq ($(shell expr $(MABOSS_MAX_NODES) '>' 64), 1) +LIB := -L$(CUR_DIR)/$(MABOSS_DIR)/lib -lMaBoSS_$(MABOSS_MAX_NODES)n-static $(LDL_FLAG) +endif + +ARCH := native # best auto-tuning +# ARCH := core2 # a reasonably safe default for most CPUs since 2007 +# ARCH := corei7 +# ARCH := corei7-avx # earlier i7 +# ARCH := core-avx-i # i7 ivy bridge or newer +# ARCH := core-avx2 # i7 with Haswell or newer +# ARCH := nehalem +# ARCH := westmere +# ARCH := sandybridge # circa 2011 +# ARCH := ivybridge # circa 2012 +# ARCH := haswell # circa 2013 +# ARCH := broadwell # circa 2014 +# ARCH := skylake # circa 2015 +# ARCH := bonnell +# ARCH := silvermont +# ARCH := skylake-avx512 +# ARCH := nocona #64-bit pentium 4 or later + +# CFLAGS := -march=$(ARCH) -Ofast -s -fomit-frame-pointer -mfpmath=both -fopenmp -m64 -std=c++11 +CFLAGS := -march=$(ARCH) -O3 -fomit-frame-pointer -mfpmath=both -fopenmp -m64 -std=c++11 + +ifeq ($(OS),Windows_NT) +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Darwin) + UNAME_P := $(shell uname -p) + var := $(shell which $(CC) | xargs file) + ifeq ($(lastword $(var)),arm64) + CFLAGS := -march=$(ARCH) -O3 -fomit-frame-pointer -fopenmp -m64 -std=c++11 + endif + endif +endif + +COMPILE_COMMAND := $(CC) $(CFLAGS) + +BioFVM_OBJECTS := BioFVM_vector.o BioFVM_mesh.o BioFVM_microenvironment.o BioFVM_solvers.o BioFVM_matlab.o \ +BioFVM_utilities.o BioFVM_basic_agent.o BioFVM_MultiCellDS.o BioFVM_agent_container.o + +PhysiCell_core_OBJECTS := PhysiCell_phenotype.o PhysiCell_cell_container.o PhysiCell_standard_models.o \ +PhysiCell_cell.o PhysiCell_custom.o PhysiCell_utilities.o PhysiCell_constants.o PhysiCell_basic_signaling.o \ +PhysiCell_signal_behavior.o PhysiCell_rules.o + +PhysiCell_module_OBJECTS := PhysiCell_SVG.o PhysiCell_pathology.o PhysiCell_MultiCellDS.o PhysiCell_various_outputs.o \ +PhysiCell_pugixml.o PhysiCell_settings.o PhysiCell_geometry.o + +# put your custom objects here (they should be in the custom_modules directory) +MaBoSS := ./addons/PhysiBoSS/MaBoSS/engine/src/BooleanNetwork.h + +PhysiBoSS_OBJECTS := maboss_network.o maboss_intracellular.o + +PhysiCell_custom_module_OBJECTS := custom.o submodel_data_structures.o tnf_receptor_dynamics.o tnf_boolean_model_interface.o + +pugixml_OBJECTS := pugixml.o + +PhysiCell_OBJECTS := $(BioFVM_OBJECTS) $(pugixml_OBJECTS) $(PhysiCell_core_OBJECTS) $(PhysiCell_module_OBJECTS) + +start_and_stop_OBJECTS := start_and_stop.o +ALL_OBJECTS := $(PhysiCell_OBJECTS) $(PhysiCell_custom_module_OBJECTS) $(PhysiBoSS_OBJECTS) $(PhysiBoSS_module_OBJECTS) $(start_and_stop_OBJECTS) + +# compile the project + +all: main.cpp $(ALL_OBJECTS) $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -o $(PROGRAM_NAME) $(ALL_OBJECTS) main.cpp $(LIB) + @echo "" + @echo "check for $(PROGRAM_NAME)" + +# PhysiCell core components + +PhysiCell_phenotype.o: ./core/PhysiCell_phenotype.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_phenotype.cpp + +PhysiCell_digital_cell_line.o: ./core/PhysiCell_digital_cell_line.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_digital_cell_line.cpp + +PhysiCell_cell.o: ./core/PhysiCell_cell.cpp $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -c ./core/PhysiCell_cell.cpp + +PhysiCell_cell_container.o: ./core/PhysiCell_cell_container.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_cell_container.cpp + +PhysiCell_standard_models.o: ./core/PhysiCell_standard_models.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_standard_models.cpp + +PhysiCell_utilities.o: ./core/PhysiCell_utilities.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_utilities.cpp + +PhysiCell_custom.o: ./core/PhysiCell_custom.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_custom.cpp + +PhysiCell_constants.o: ./core/PhysiCell_constants.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_constants.cpp + +PhysiCell_signal_behavior.o: ./core/PhysiCell_signal_behavior.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_signal_behavior.cpp + +PhysiCell_rules.o: ./core/PhysiCell_rules.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_rules.cpp + +# BioFVM core components (needed by PhysiCell) + +BioFVM_vector.o: ./BioFVM/BioFVM_vector.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_vector.cpp + +BioFVM_agent_container.o: ./BioFVM/BioFVM_agent_container.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_agent_container.cpp + +BioFVM_mesh.o: ./BioFVM/BioFVM_mesh.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_mesh.cpp + +BioFVM_microenvironment.o: ./BioFVM/BioFVM_microenvironment.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_microenvironment.cpp + +BioFVM_solvers.o: ./BioFVM/BioFVM_solvers.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_solvers.cpp + +BioFVM_utilities.o: ./BioFVM/BioFVM_utilities.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_utilities.cpp + +BioFVM_basic_agent.o: ./BioFVM/BioFVM_basic_agent.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_basic_agent.cpp + +BioFVM_matlab.o: ./BioFVM/BioFVM_matlab.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_matlab.cpp + +BioFVM_MultiCellDS.o: ./BioFVM/BioFVM_MultiCellDS.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_MultiCellDS.cpp + +pugixml.o: ./BioFVM/pugixml.cpp + $(COMPILE_COMMAND) -c ./BioFVM/pugixml.cpp + +# standard PhysiCell modules + +PhysiCell_SVG.o: ./modules/PhysiCell_SVG.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_SVG.cpp + +PhysiCell_pathology.o: ./modules/PhysiCell_pathology.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_pathology.cpp + +PhysiCell_MultiCellDS.o: ./modules/PhysiCell_MultiCellDS.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_MultiCellDS.cpp + +PhysiCell_various_outputs.o: ./modules/PhysiCell_various_outputs.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_various_outputs.cpp + + +PhysiCell_pugixml.o: ./modules/PhysiCell_pugixml.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_pugixml.cpp + +PhysiCell_settings.o: ./modules/PhysiCell_settings.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_settings.cpp + +PhysiCell_basic_signaling.o: ./core/PhysiCell_basic_signaling.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_basic_signaling.cpp + +PhysiCell_geometry.o: ./modules/PhysiCell_geometry.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_geometry.cpp + +# start_and_stop +start_and_stop.o: ./addons/start_and_stop/start_and_stop.cpp + $(COMPILE_COMMAND) $(INC) -c ./addons/start_and_stop/start_and_stop.cpp + +# user-defined PhysiCell modules + +Compile_MaBoSS: ./addons/PhysiBoSS/MaBoSS/engine/src/BooleanNetwork.h + cd ./addons/PhysiBoSS/MaBoSS/engine/src;make CXX=$(CC) install_alib;make clean; cd ../../../../.. + +$(MaBoSS): +ifeq ($(OS), Windows_NT) + python addons/PhysiBoSS/setup_libmaboss.py +else + python3 addons/PhysiBoSS/setup_libmaboss.py +endif + +maboss_network.o: ./addons/PhysiBoSS/src/maboss_network.cpp $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -c ./addons/PhysiBoSS/src/maboss_network.cpp + +maboss_intracellular.o: ./addons/PhysiBoSS/src/maboss_intracellular.cpp $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -c ./addons/PhysiBoSS/src/maboss_intracellular.cpp + +custom.o: ./custom_modules/custom.cpp $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -c ./custom_modules/custom.cpp + +submodel_data_structures.o: ./custom_modules/submodel_data_structures.cpp + $(COMPILE_COMMAND) $(INC) -c ./custom_modules/submodel_data_structures.cpp + +tnf_receptor_dynamics.o: ./custom_modules/tnf_receptor_dynamics.cpp + $(COMPILE_COMMAND) $(INC) -c ./custom_modules/tnf_receptor_dynamics.cpp + +tnf_boolean_model_interface.o: ./custom_modules/tnf_boolean_model_interface.cpp $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -c ./custom_modules/tnf_boolean_model_interface.cpp + @echo "compiling" +# cleanup + +reset: + rm -f *.cpp + cp ./sample_projects/Makefile-default Makefile + rm -f ./custom_modules/* + touch ./custom_modules/empty.txt + rm ALL_CITATIONS.txt + rm -f ./config/PhysiCell_settings.xml + rm -f ./config/PhysiCell_settings_2D.xml + rm -f ./config/PhysiCell_settings_3D.xml + rm -f ./config/init.tsv + rm -f ./config/TNF_conf.cfg + rm -f ./config/TNF_nodes.bnd + rm -fr ./scripts + cp ./config/PhysiCell_settings-backup.xml ./config/PhysiCell_settings.xml + +MaBoSS-clean: + rm -fr addons/PhysiBoSS/MaBoSS + +clean: MaBoSS-clean + rm -f *.o + rm -f $(PROGRAM_NAME)* + +data-cleanup: + rm -f *.mat + rm -f *.xml + rm -f *.svg + rm -f ./output/* + touch ./output/empty.txt + +# archival + +checkpoint: + zip -r $$(date +%b_%d_%Y_%H%M).zip Makefile *.cpp *.h config/*.xml custom_modules/* + +zip: + zip -r latest.zip Makefile* *.cpp *.h BioFVM/* config/* core/* custom_modules/* matlab/* modules/* sample_projects/* + cp latest.zip $$(date +%b_%d_%Y_%H%M).zip + cp latest.zip VERSION_$(VERSION).zip + mv *.zip archives/ + +tar: + tar --ignore-failed-read -czf latest.tar Makefile* *.cpp *.h BioFVM/* config/* core/* custom_modules/* matlab/* modules/* sample_projects/* + cp latest.tar $$(date +%b_%d_%Y_%H%M).tar + cp latest.tar VERSION_$(VERSION).tar + mv *.tar archives/ + +unzip: + cp ./archives/latest.zip . + unzip latest.zip + +untar: + cp ./archives/latest.tar . + tar -xzf latest.tar diff --git a/addons/PhysiBoSS/src/maboss_intracellular.h b/addons/PhysiBoSS/src/maboss_intracellular.h index 06242a8c7..130fe9fff 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.h +++ b/addons/PhysiBoSS/src/maboss_intracellular.h @@ -117,6 +117,101 @@ class MaBoSSIntracellular : public PhysiCell::Intracellular { void print_current_nodes(){ this->maboss.print_nodes(); } + void save_current_nodes(std::ostream& out_stream){ + this->maboss.save_nodes(out_stream); + } + + void save_current_parameters_maboss(std::ostream& out_stream){ + this->maboss.save_current_parameters(out_stream); + } + void read_current_parameter_maboss(std::ifstream& in_stream){ + this->maboss.read_current_parameter(in_stream); + } + int get_number_of_nodes(){ + return this->maboss.get_nodes_number().size(); + } + + void reinit_maboss(std::string networkFile, std::string configFile){ + this->maboss.init_maboss(networkFile, configFile); + } + + void save_current_parameters(std::ostream& out_stream){ + + out_stream << "maboss_intracellular_parameters:" << std::endl; + out_stream << "time_step: " << this->time_step << std::endl; + out_stream << "discrete_time: " << (this->discrete_time ? "true" : "false") << std::endl; + out_stream << "time_tick: " << this->time_tick << std::endl; + out_stream << "scaling: " << this->scaling << std::endl; + out_stream << "time_stochasticity: " << this->time_stochasticity << std::endl; + out_stream << "inherit_state: " << (this->inherit_state ? "true" : "false") << std::endl; + out_stream << "start_time: " << this->start_time << std::endl; + out_stream << "next_physiboss_run: " << this->next_physiboss_run << std::endl; + /* + // Print the contents of the inherit_nodes map + for(const auto& pair : inherit_nodes) { + out_stream << "Key: " << pair.first << " Value: " << (pair.second ? "true" : "false") << std::endl; + } + + // Print the contents of the initial_values map + for(const auto& pair : initial_values) { + out_stream << "Key: " << pair.first << " Value: " << pair.second << std::endl; + } + + // Print the contents of the mutations map + for(const auto& pair : mutations) { + out_stream << "Key: " << pair.first << " Value: " << pair.second << std::endl; + } + + // Print the contents of the parameters map + for(const auto& pair : parameters) { + out_stream << "Key: " << pair.first << " Value: " << pair.second << std::endl; + }*/ + out_stream << std::endl; + + } + + void read_current_parameter(std::ifstream& in_stream){ + std::string dummy; + + //skip header + std::getline(in_stream, dummy); + + //time_step + std::getline(in_stream, dummy); + this->time_step = read_number_in_line(dummy); + + //discrete_time + std::getline(in_stream, dummy); + this->discrete_time = read_number_in_line_bool(dummy); + + //time_tick + std::getline(in_stream, dummy); + this->time_tick = read_number_in_line(dummy); + + //scaling + std::getline(in_stream, dummy); + this->scaling = read_number_in_line(dummy); + + //time_stochasticity + std::getline(in_stream, dummy); + this->time_stochasticity = read_number_in_line(dummy); + + //inherit_state + std::getline(in_stream, dummy); + this->inherit_state = read_number_in_line_bool(dummy); + + //start_time + std::getline(in_stream, dummy); + this->start_time = read_number_in_line(dummy); + + //next_physiboss_run + std::getline(in_stream, dummy); + this->next_physiboss_run = read_number_in_line(dummy); + + // skip empty line + std::getline(in_stream, dummy); + + } void display(std::ostream& os); diff --git a/addons/PhysiBoSS/src/maboss_network.cpp b/addons/PhysiBoSS/src/maboss_network.cpp index ebcee8be3..b4561381e 100644 --- a/addons/PhysiBoSS/src/maboss_network.cpp +++ b/addons/PhysiBoSS/src/maboss_network.cpp @@ -164,4 +164,21 @@ void MaBoSSNetwork::print_nodes() i++; } std::cout << std::endl; +} + +void MaBoSSNetwork::save_nodes(std::ostream& out_stream) +{ + int i = 0; + //out_stream << this->get_state(); + + std::vector nodes = this->network->getNodes(); + for ( auto node: nodes ) + { + out_stream << node->getLabel() << "=" << state.getNodeState(node) << " "; + i++; + } +} + +std::vector MaBoSSNetwork::get_nodes_number(){ + return this->network->getNodes(); } \ No newline at end of file diff --git a/addons/PhysiBoSS/src/maboss_network.h b/addons/PhysiBoSS/src/maboss_network.h index 5aace16d3..2dd3897b8 100644 --- a/addons/PhysiBoSS/src/maboss_network.h +++ b/addons/PhysiBoSS/src/maboss_network.h @@ -5,6 +5,7 @@ #include "BooleanNetwork.h" #include "RunConfig.h" #include "../../../core/PhysiCell_utilities.h" +#include "../../../core/PhysiCell_phenotype.h" /** * \class MaBoSSNetwork @@ -111,6 +112,7 @@ class MaBoSSNetwork bool has_node( std::string name ); void set_node_value(std::string name, bool value); bool get_node_value(std::string name); + std::vector get_nodes_number(); std::string get_state(); /** \brief Return update time value */ @@ -141,6 +143,47 @@ class MaBoSSNetwork */ void print_nodes(); + /** + * \brief Save current state of all the nodes of the network + * \param node_values Boolean vector mapping a boolean network + * \param out_stream Output file used to save data + */ + void save_nodes(std::ostream& out_stream); + + void save_current_parameters(std::ostream& out_stream){ + + out_stream << "maboss_network_parameters:" << std::endl; + //out_stream << "update_time_step: " << this->update_time_step << std::endl; + out_stream << "time_to_update: " << this->time_to_update << std::endl; + out_stream << "scaling: " << this->scaling << std::endl; + out_stream << "time_stochasticity: " << this->time_stochasticity << std::endl; + //out_stream << "seed: " << this->seed << std::endl; + out_stream << std::endl; + } + + void read_current_parameter(std::ifstream& in_stream){ + std::string dummy; + + //skip header + std::getline(in_stream, dummy); + + //time_to_update + std::getline(in_stream, dummy); + this->time_to_update = read_number_in_line(dummy); + + //scaling + std::getline(in_stream, dummy); + this->scaling = read_number_in_line(dummy); + + //time_stochasticity + std::getline(in_stream, dummy); + this->time_stochasticity = read_number_in_line(dummy); + + // skip empty line + std::getline(in_stream, dummy); + + } + void set_state(NetworkState _state) { state = NetworkState(_state.getState()); } NetworkState get_maboss_state() { return state;} void inherit_state(NetworkState mother, bool inherit_state, std::map& inherit_nodes) { diff --git a/addons/start_and_stop/start_and_stop.cpp b/addons/start_and_stop/start_and_stop.cpp new file mode 100644 index 000000000..e4f1e90d8 --- /dev/null +++ b/addons/start_and_stop/start_and_stop.cpp @@ -0,0 +1,496 @@ +#include "./start_and_stop.h" +#include +#include + +using namespace std; + +// reset microenv +void reset_microenv(){ + + string filename = "start_and_stop_saving_files/microenv_data.txt"; + + // Open the file for input + ifstream input_file(filename); + if (!input_file.is_open()) { + cerr << "Error: Unable to open file " << filename << endl; + return; + } + + // Call the operator>> function to read data from the file into the Microenvironment instance + input_file >> microenvironment; + + // Close the file + input_file.close(); + return; +} + +// Function to save cell data +void save_cell_microenv_data(Cell_Container* cell_container) +{ + + // decide if restart from a previous point or from the beginning + string filename_cells = "start_and_stop_saving_files/cell_data.txt"; + string filename_bool = "start_and_stop_saving_files/bool_data.txt"; + string filename_microenv = "start_and_stop_saving_files/microenv_data.txt"; + string cell_pos_filename = "start_and_stop_saving_files/initial.tsv"; + string global_param_filename = "start_and_stop_saving_files/global_param.txt"; + string random_counters_filename = "start_and_stop_saving_files/random_counters.txt"; + + // Open the files in write mode + ofstream file_cells(filename_cells); + ofstream file_bool(filename_bool); + ofstream file_microenv(filename_microenv); + ofstream cell_pos_file(cell_pos_filename); + ofstream global_param_file(global_param_filename); + ofstream random_counters_file(random_counters_filename); + + // Check if the files are successfully opened + if (!file_cells.is_open()) + { + // Handle the case where the file cannot be opened + cerr << "Error opening file " << filename_cells << endl; + return; + } + if (!file_bool.is_open()) + { + // Handle the case where the file cannot be opened + cerr << "Error opening file " << filename_bool << endl; + return; + } + if (!file_microenv.is_open()) + { + // Handle the case where the file cannot be opened + cerr << "Error opening file " << filename_microenv << endl; + return; + } + if (!cell_pos_file.is_open()) + { + // Handle the case where the file cannot be opened + cerr << "Error opening file " << cell_pos_filename << endl; + return; + } + if (!global_param_file.is_open()) + { + // Handle the case where the file cannot be opened + cerr << "Error opening file " << global_param_filename << endl; + return; + } + if (!random_counters_file.is_open()) + { + // Handle the case where the file cannot be opened + cerr << "Error opening file " << random_counters_filename << endl; + return; + } + + // display microenvironment + + file_microenv << microenvironment; + + // add header to pos file + cell_pos_file << "x y z" << endl; + + // Iterate through all cells + for (int i = 0; i < (*all_cells).size(); i++) + { + // Access the current cell + Cell *pCell = (*all_cells)[i]; + + // Write the cell data to the file using the insertion operator + file_cells << *pCell << endl; + + if (pCell->phenotype.intracellular){ + //save parameters maboss_intracellular + pCell->phenotype.intracellular->save_current_parameters(file_cells); + + //save parameters maboss network + pCell->phenotype.intracellular->save_current_parameters_maboss(file_cells); + } + + // current_voxel_index + file_cells << "current_voxel_index: " << pCell->get_current_voxel_index() << std::endl; + + // nearest_density_vector + file_cells << "nearest_density_vector: " << pCell->nearest_density_vector() << std::endl; + + + // empty line + file_cells << std::endl; + + // Write the positions in the cell file + cell_pos_file << pCell->position[0] << " "; + cell_pos_file << pCell->position[1] << " "; + cell_pos_file << pCell->position[2]; + + + if (pCell->phenotype.intracellular){ + // Write the output for Boolean network + // iterate among the nodes and write the name of all the active nodes for each cell, a row = a cell. + pCell->phenotype.intracellular->save_current_nodes(file_bool); + + + + // Write newline except for the last cell + if (i != (*all_cells).size() - 1) { + cell_pos_file << "\n"; + file_bool << "\n"; + } + } + + + } + // Save global parameters and cell container + global_param_file << "current_time: " << PhysiCell_globals.current_time << endl; + global_param_file << "full_output_index: " <phenotype.intracellular){ + global_param_file << "intracellular_dt: " << intracellular_dt << std::endl; + } + cell_container->save_data(global_param_file); + + //save random counters + save_counters(random_counters_file); + + //close all the files + file_cells.close(); + file_bool.close(); + file_microenv.close(); + global_param_file.close(); + random_counters_file.close(); + + return; +} +using namespace std; + + +void reset_cell(double last_cell_cycle_time) +{ + + // Specify the path to the input files + std::string input_file_cells_path = "start_and_stop_saving_files/cell_data.txt"; + std::string input_file_bool_path = "start_and_stop_saving_files/bool_data.txt"; + + // Open the files in input mode using std::ifstream + std::ifstream input_file_cells(input_file_cells_path); + std::ifstream input_file_bool(input_file_bool_path); + + + + // Check if the files was opened successfully + if (!input_file_cells.is_open()) + { + std::cerr << "Error opening the file: " << input_file_cells_path << std::endl; + return; + } + if (!input_file_bool.is_open()) + { + std::cerr << "Error opening the file: " << input_file_bool_path << std::endl; + return; + } + + // Iterate through all cells + for (int i = 0; i < (*all_cells).size(); i++) + { + // Use the extraction operator >> to read data from the file line into the cell + + // Access the current cell + Cell *pCell = (*all_cells)[i]; + //read header + string header; + getline(input_file_cells, header); + // ID: + getline(input_file_cells, header); + pCell->ID = read_number_in_line_int(header); + // index: + getline(input_file_cells, header); + pCell->index = read_number_in_line_int(header); + // type: + getline(input_file_cells, header); + pCell->type = read_number_in_line_int(header); + + // is_active: + std::getline(input_file_cells, header); + pCell->is_active = read_number_in_line_bool(header); + // type_name + getline(input_file_cells >> ws, pCell->type_name); + // is_out_of_domain + std::getline(input_file_cells, header); + pCell->is_out_of_domain = read_number_in_line_bool(header); + + // is_movable + std::getline(input_file_cells, header); + pCell->is_movable = read_number_in_line_bool(header); + + // state + input_file_cells >> pCell->state; + + + //parameters + input_file_cells >> pCell->parameters; + + + + string line; + + // flagged_for_division: + std::getline(input_file_cells, line); + pCell->phenotype.flagged_for_division = read_number_in_line_bool(line); + + + // flagged_for_removal: + std::getline(input_file_cells, line); + pCell->phenotype.flagged_for_removal = read_number_in_line_bool(line); + + + //death + input_file_cells >> pCell->phenotype.death; + + if(pCell->phenotype.death.dead == true){ + pCell->phenotype.cycle.sync_to_cycle_model(pCell->phenotype.death.current_model()); + } + //cycle + input_file_cells >> pCell->phenotype.cycle; + if( pCell->phenotype.cycle.current_phase().entry_function ) + { + pCell->phenotype.cycle.current_phase().entry_function( pCell, pCell->phenotype, PhysiCell_globals.current_time - last_cell_cycle_time); + } + + //volume + input_file_cells >> pCell->phenotype.volume; + pCell->set_total_volume(pCell->phenotype.volume.total); + //geometry + input_file_cells >> pCell->phenotype.geometry; + //mechanics + input_file_cells >> pCell->phenotype.mechanics; + //motility + input_file_cells >> pCell->phenotype.motility; + + //secretion + input_file_cells >> pCell->phenotype.secretion; + + //molecular + input_file_cells >> pCell->phenotype.molecular; + + //Cell_Interactions + input_file_cells >> pCell->phenotype.cell_interactions; + + //Cell_Transformations + input_file_cells >> pCell->phenotype.cell_transformations; + + //custom_data + input_file_cells >> pCell->custom_data; + + getline(input_file_cells, header); + getline(input_file_cells, header); + + //intracellular + if (pCell->phenotype.intracellular){ + pCell->phenotype.intracellular->read_current_parameter(input_file_cells); + + pCell->phenotype.intracellular->read_current_parameter_maboss(input_file_cells); + + std::string current_bnd_filename; + std::string current_cfg_filename; + + // load and parse settings file(s) + pugi::xml_document physicell_xml; + pugi::xml_node node; + pugi::xml_parse_result result = physicell_xml.load_file( "./config/PhysiCell_settings.xml" ); + + if( result.status != pugi::xml_parse_status::status_ok ) + { + std::cout << "Error loading " << "./config/PhysiCell_settings.xml" << "!" << std::endl; + } + + // navigate to the desired value + pugi::xml_node physicell_settings = physicell_xml.child("PhysiCell_settings"); + pugi::xml_node cell_defs = physicell_settings.child("cell_definitions"); + + for (pugi::xml_node cell_def = cell_defs.child("cell_definition"); cell_def; cell_def = cell_def.next_sibling("cell_definition")) + { + if (std::string(cell_def.attribute("name").value()) == pCell->type_name) + { + pugi::xml_node phenotype = cell_def.child("phenotype"); + + pugi::xml_node intracellular = phenotype.child("intracellular"); + + if(intracellular && std::string(intracellular.attribute("type").value()) == "maboss") + { + pugi::xml_node bnd_filename = intracellular.child("bnd_filename"); + pugi::xml_node cfg_filename = intracellular.child("cfg_filename"); + + current_bnd_filename = bnd_filename.text().get(); + current_cfg_filename = cfg_filename.text().get(); + + } + } + } + // reinit maboss + pCell->phenotype.intracellular->reinit_maboss(current_bnd_filename, current_cfg_filename); + } + + // current_voxel_index + std::getline(input_file_cells, header); + + // nearest_density_vector + std::getline(input_file_cells, header); + + // empty line + std::getline(input_file_cells, header); + + if (pCell->phenotype.intracellular){ + // Boolean network reinitialization + string dummy; + getline(input_file_bool, dummy); + + // Use a stringstream to extract tokens from the line + istringstream iss(dummy); + + // Loop to extract node names and values from the line + string token; + unsigned int n_line = 0; + while (getline(iss, token, ' ')) { // Read the string until the ';' character + // Find the position of the '=' character + size_t pos = token.find('='); + if (pos != string::npos) { // If the '=' character is found + // Extract the node name and its value from the substring + string node_name = token.substr(0, pos); + string node_value_str = token.substr(pos + 1); + bool node_value = (node_value_str == "1"); + + pCell->phenotype.intracellular->set_boolean_variable_value(node_name, node_value); + n_line++; + + } + + + } + // Check if the number of nodes is the same + + assert(n_line == pCell->phenotype.intracellular->get_number_of_nodes()); + } + + } + input_file_cells.close(); + input_file_bool.close(); + return; + + } + + void reset_global_parameters(Cell_Container* cell_container) + { + string global_param_filename = "start_and_stop_saving_files/global_param.txt"; + + ifstream global_param_file(global_param_filename); + + if (!global_param_file.is_open()) + { + // Handle the case where the file cannot be opened + cerr << "Error opening file " << global_param_filename << endl; + return; + } + + // current_time: + string line_current_time; + getline(global_param_file, line_current_time); + PhysiCell_globals.current_time = read_number_in_line(line_current_time); + + // full_output_index: + string line_full_output_index; + getline(global_param_file, line_full_output_index); + PhysiCell_globals.full_output_index = read_number_in_line_int(line_full_output_index); + + // intracellular_output_index: + string line_intracellular_output_index; + getline(global_param_file, line_intracellular_output_index); + PhysiCell_globals.intracellular_output_index = read_number_in_line_int(line_intracellular_output_index); + + // next_full_save_time: + string line_next_full_save_time; + getline(global_param_file, line_next_full_save_time); + PhysiCell_globals.next_full_save_time = read_number_in_line(line_next_full_save_time); + + // next_intracellular_save_time: + string line_next_intracellular_save_time; + getline(global_param_file, line_next_intracellular_save_time); + PhysiCell_globals.next_intracellular_save_time = read_number_in_line(line_next_intracellular_save_time); + + // next_SVG_save_time: + string line_next_SVG_save_time; + getline(global_param_file, line_next_SVG_save_time); + PhysiCell_globals.next_SVG_save_time = read_number_in_line(line_next_SVG_save_time); + + // SVG_output_index: + string line_SVG_output_index; + getline(global_param_file, line_SVG_output_index); + PhysiCell_globals.SVG_output_index = read_number_in_line_int(line_SVG_output_index); + + // diffusion_dt: + string line_diffusion_dt; + getline(global_param_file, line_diffusion_dt); + diffusion_dt = read_number_in_line(line_diffusion_dt); + + // diffusion_dt: + string line_mechanics_dt; + getline(global_param_file, line_mechanics_dt); + mechanics_dt = read_number_in_line(line_mechanics_dt); + + // phenotype_dt: + string line_phenotype_dt; + getline(global_param_file, line_phenotype_dt); + phenotype_dt = read_number_in_line(line_phenotype_dt); + + // intracellular_dt: + if (((*all_cells)[0])->phenotype.intracellular){ + string line_intracellular_dt; + getline(global_param_file, line_intracellular_dt); + intracellular_dt = read_number_in_line(line_intracellular_dt); + } + + //reset cell_container + cell_container->reset_data(global_param_file); + + // Close the file after finishing reading + global_param_file.close(); + + return; + } + + void reset_randomness() + { + + string random_counters_filename = "start_and_stop_saving_files/random_counters.txt"; + + ifstream random_counters_file(random_counters_filename); + + if (!random_counters_file.is_open()) + { + // Handle the case where the file cannot be opened + cerr << "Error opening file " << random_counters_filename << endl; + return; + } + + // counter_double_random: + string line_counter_double_random; + getline(random_counters_file, line_counter_double_random); + set_counter_double_random(read_number_in_line(line_counter_double_random)); + + // counter_int_random: + string line_counter_int_random; + getline(random_counters_file, line_counter_int_random); + set_counter_int_random(read_number_in_line(line_counter_int_random)); + + // counter_normal_random: + string line_counter_normal_random; + getline(random_counters_file, line_counter_normal_random); + set_counter_normal_random(read_number_in_line(line_counter_normal_random)); + + random_counters_file.close(); + + } diff --git a/addons/start_and_stop/start_and_stop.h b/addons/start_and_stop/start_and_stop.h new file mode 100644 index 000000000..c9bee9c07 --- /dev/null +++ b/addons/start_and_stop/start_and_stop.h @@ -0,0 +1,17 @@ + +#include "../../core/PhysiCell.h" +#include "../../modules/PhysiCell_standard_modules.h" + +using namespace BioFVM; +using namespace PhysiCell; + +void reset_microenv(); + +// Function to save cell data +void save_cell_microenv_data(Cell_Container* cell_container); + +void reset_cell(double last_cell_cycle_time); + +void reset_global_parameters(Cell_Container* cell_container); + +void reset_randomness(); \ No newline at end of file diff --git a/config/PhysiCell_settings.xml b/config/PhysiCell_settings.xml index d35c44fc7..635cdfcfd 100644 --- a/config/PhysiCell_settings.xml +++ b/config/PhysiCell_settings.xml @@ -1,271 +1,225 @@ + + -500 + 500 + -500 + 500 + -10 + 10 + 20 + 20 + 20 + true + + + + 1440 + min + micron + 0.02 + 0.1 + 2 + + + + 8 + + + + output + + 30 + true + + + 30 + true + + + false + + + + + + + 100000.0 + .1 + + 38.0 + 38.0 + + + + + 1200.0 + .0275 + + 0.0 + 0.0 + - - -500 - 500 - -500 - 500 - -10 - 10 - 20 - 20 - 20 - true - + + false + true + + + ./config/initial.mat + + + + ./config/dirichlet.mat + + + + + + + + + + + + 0.0011 + + + + + + 5.31667e-05 + + 516 + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + - - 14400 - min - micron - 0.01 - 0.1 - 6 - + + 0.0 + + 0 + 86400 + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + + 2494 + 0.75 + 540 + + 0.05 + 0.0045 + 0.0055 + + 0 + 0 + + 2.0 + - - 6 - + + + 0 + 38 + 10 + 0 + + + 0 + 0 + 0 + 0 + + + - - output - - 60 - true - - - 60 - true - - - false - - + + ./config/TNF_nodes.bnd + ./config/TNF_conf.cfg + + 10.0 + 0.01 + + + + + + 0.243 + 0.128 + 0.293 + + 0.50 + 1.0 + 0 - - false - true - + + 0 + 0 + 0 + 0 + + + + 0.0035 + 0.0035 + 1.0 + + + - - - - 100000.0 - 0.1 - - 38 - 0 - - 38 - 10 - 10 - 38 - 0 - 0 - - - - - 10 - .1 - - 0 - 0 - - 0 - 0 - 0 - 0 - 0 - 0 - - - - - 10 - 0.1 - - 0 - 0 - - 0 - 0 - 0 - 0 - 0 - 0 - - - - true - true - - ./config/initial.mat - - - ./config/dirichlet.mat - - - + + 0 + false + ./start_and_stop_saving_files/initial.tsv + 100 + - - - - - - 0.000 - - - - - 5.31667e-05 - - 516 - - - 0.05 - 0 - 1.66667e-02 - 5.83333e-03 - 0 - 2.0 - - - - 2.80E-03 - - 0 - 86400 - - - 1.11667e-2 - 8.33333e-4 - 5.33333e-5 - 2.16667e-3 - 0 - 2.0 - - - - - 2494 - 0.75 - 540 - 0.05 - 0.0045 - 0.0055 - 0 - 0 - 2.0 - - - 0.4 - 10.0 - 1.25 - - 1 - - - 1.8 - 15.12 - - 4.0 - 10.0 - 0.01 - 0.0 - 0.0 - - - 1 - 1 - .5 - - false - true - - false - oxygen - 1 - - - false - false - - 0.0 - 0.0 - 0.0 - - - - - - - 0 - 1 - 10 - 0 - - - 0.0 - 1 - 0.0 - 0.0 - - - 0.0 - 1 - 0.0 - 0.0 - - - - 0 - - 0 - 0 - - - 0 - 0 - - 1 - - 0 - 0 - - - - - 0 - 0 - - - - - 1.0 - - - + 120 + + true + false + false - - - ./config - cells.csv - - + true + 150 + 10 + 0.005 + 999999 + + + + 0.0 + 0.05 + 0.95 - - - - ./config - cell_rules_v2.csv - - - - + + 0.0 + 0.05 + 0.95 + + 0.0 + 0.05 + 0.95 + - - 0 - 0 - + + + + \ No newline at end of file diff --git a/config/PhysiCell_settings_2D.xml b/config/PhysiCell_settings_2D.xml new file mode 100644 index 000000000..a6764a6f4 --- /dev/null +++ b/config/PhysiCell_settings_2D.xml @@ -0,0 +1,286 @@ + + + + + + + + -500 + 500 + -500 + 500 + -10 + 10 + 20 + 20 + 20 + true + + + + 1440 + min + micron + 0.02 + 0.1 + 2 + + + + 8 + + + + output + + 30 + true + + + 30 + true + + + false + + + + + + + 100000.0 + .1 + + 38.0 + 38.0 + + + + + 1200.0 + .0275 + + 0.0 + 0.0 + + + + false + true + + + ./config/initial.mat + + + + ./config/dirichlet.mat + + + + + + + + + + + + 0.00075 + + + + + + 5.31667e-05 + + 516 + + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + 0.0 + + 0 + 86400 + + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + + 2494 + 0.75 + 540 + + 0.05 + 0.0045 + 0.0055 + + 0 + 0 + + 2.0 + + + + + + 0 + 38 + 10 + 0 + + + 0 + 0 + 0 + 0 + + + + + + ./config/TNF_nodes.bnd + ./config/TNF_conf.cfg + + 10 + 1 + + + + + + 0.243 + 0.128 + 0.293 + + 0.50 + 1.0 + 0 + + + 0 + 0 + 0 + 0 + + + 0.0027 + 0.0055 + + + + + + 0 + false + ./config/init.tsv + 100.0 + + 0.0 + 0.05 + 0.95 + + 0.0 + 0.05 + 0.95 + + 0.0 + 0.05 + 0.95 + + 150.0 + 10.0 + 0.0015 + 999999 + 120 + + + + diff --git a/config/PhysiCell_settings_3D.xml b/config/PhysiCell_settings_3D.xml new file mode 100644 index 000000000..dab033eb4 --- /dev/null +++ b/config/PhysiCell_settings_3D.xml @@ -0,0 +1,287 @@ + + + + + + + + -200 + 200 + -200 + 200 + -200 + 200 + 20 + 20 + 20 + false + + + + 2160 + min + micron + 0.02 + 0.1 + 2 + + + + 8 + + + + output + + 30 + true + + + 30 + true + + + false + + + + + + + 100000.0 + .1 + + 38.0 + 38.0 + + + + + 1200.0 + .0275 + + 0.0 + 0.0 + + + + false + true + + + ./config/initial.mat + + + + ./config/dirichlet.mat + + + + + + + + + + + + 0.00075 + + + + + + 5.31667e-05 + + 516 + + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + 0.0 + + 0 + 86400 + + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + + 2494 + 0.75 + 540 + + 0.05 + 0.0045 + 0.0055 + + 0 + 0 + + 2.0 + + + + + + 0 + 38 + 10 + 0 + + + 0 + 0 + 0 + 0 + + + + + + ./config/TNF_nodes.bnd + ./config/TNF_conf.cfg + + 10 + 1 + + + + + + 0.243 + 0.128 + 0.293 + + 0.50 + 1.0 + 0 + + + 0 + 0 + 0 + 0 + + + 0.0027 + 0.0055 + 1e-7 + + + + + + 0 + ./config/init.tsv + false + 50.0 + + 0.0 + 0.05 + 0.95 + + 0.0 + 0.05 + 0.95 + + 0.0 + 0.05 + 0.95 + + 150.0 + 10.0 + 0.002 + 999999 + 80 + + + + \ No newline at end of file diff --git a/config/TNF_conf.cfg b/config/TNF_conf.cfg new file mode 100644 index 000000000..5e9c9892a --- /dev/null +++ b/config/TNF_conf.cfg @@ -0,0 +1,101 @@ + +// input +FADD.istate = 0; +TNF.istate = 0; +FASL.istate = 0; + +// output +NonACD.istate = 0; +Apoptosis.istate = 0 ; +Survival.istate = 0 ; + +// specific state +ATP.istate = 1; +cIAP.istate = 1; + +TNFR.istate = 0 ; +DISC_TNF.istate = 0 ; +DISC_FAS.istate = 0 ; +RIP1.istate = 0 ; +RIP1ub.istate = 0 ; +RIP1K.istate = 0 ; +IKK.istate = 0 ; +NFkB.istate = 0 ; +CASP8.istate = 0 ; +BAX.istate = 0 ; +BCL2.istate = 0 ; +ROS.istate = 0 ; +mROS.istate = 0 ; +MPT.istate = 0 ; +MOMP.istate = 0 ; +SMAC.istate = 0 ; +mcIAP.istate = 0 ; +Cyt_c.istate = 0 ; +XIAP.istate = 0 ; +mXIAP.istate = 0 ; +apoptosome.istate = 0 ; +CASP3.istate = 0 ; +cFLIP.istate = 0 ; + +//$ProdTNF_NFkB = 1; +$TransRate = 1/24; +//$DivRate = 1/24; +//$Degr_TNF = 1/6; +//$TNF_induc = 0; + +//[TNF].istate = 1 [1] , 0 [0]; + + +//TNF.is_internal = TRUE ; +//ATP.is_internal = TRUE ; +//FADD.is_internal = TRUE ; +//cIAP.is_internal = TRUE ; +// +//FASL.is_internal = TRUE ; +//TNFR.is_internal = TRUE ; +//DISC_TNF.is_internal = TRUE ; +//DISC_FAS.is_internal = TRUE ; +//RIP1.is_internal = TRUE ; +//RIP1ub.is_internal = TRUE ; +//RIP1K.is_internal = TRUE ; +//IKK.is_internal = TRUE ; +//NFkB.is_internal = TRUE ; +//CASP8.is_internal = TRUE ; +//BAX.is_internal = TRUE ; +//BCL2.is_internal = TRUE ; +//ROS.is_internal = TRUE ; +//MPT.is_internal = TRUE ; +//MOMP.is_internal = TRUE ; +//SMAC.is_internal = TRUE ; +//Cyt_c.is_internal = TRUE ; +//XIAP.is_internal = TRUE ; +//apoptosome.is_internal = TRUE ; +//CASP3.is_internal = TRUE ; +//cFLIP.is_internal = TRUE ; + + +sample_count = 1; +max_time = 1; // 10 min: 1 in maboss = 10 min in Physicell +time_tick = .01; +discrete_time = 0; +use_physrandgen = FALSE; +seed_pseudorandom = 37; +display_traj = FALSE; + +thread_count = 1; + +statdist_traj_count = 1; +statdist_cluster_threshold = 0.8; + +$Low_CASP3 = 0.0; +$High_CASP3 = 0.0; +$High_Cytc = 0.0; +$Low_CASP8 = 0.0; +$High_CASP8 = 0.0; +$High_IKK = 0.0; +$High_cFLIP = 0.0; +$Low_cIAP = 0.0; +$High_mROS = 0.0; +$Low_RIP1 = 0.0; +$High_NFkB = 0.0; +$Low_NFkB = 0.0; diff --git a/config/TNF_nodes.bnd b/config/TNF_nodes.bnd new file mode 100644 index 000000000..d91d6f8dc --- /dev/null +++ b/config/TNF_nodes.bnd @@ -0,0 +1,184 @@ +node FASL +{ + rate_up = 0.0; + rate_down = 0.0; +} +node TNF +{ + logic = TNF; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node TNFR +{ + logic = TNF; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node DISC_TNF +{ + logic = FADD & TNFR; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node DISC_FAS +{ + logic = FASL & FADD; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node FADD +{ + rate_up = 0.0; + rate_down = 0.0; +} +node RIP1 +{ + logic = (DISC_FAS | TNFR) & (!CASP8); + rate_up = ($Low_RIP1 ? 0.0 : ( @logic ? 1.0: 0.0 )); + rate_down = ($Low_RIP1 ? 1E+100 : ( @logic ? 0.0 : 1.0 )); +} +node RIP1ub +{ + logic = cIAP & RIP1; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node RIP1K +{ + logic = RIP1; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node IKK +{ + logic = RIP1ub; + rate_up = ($High_IKK ? 1E+100 : (@logic ? 1.0 : 0.0) ); + rate_down = ($High_IKK ? 0.0 : (@logic ? 0.0 : 1.0) ); +} +node NFkB +{ + logic = IKK & (!CASP3); + rate_up = ($Low_NFkB ? 0.0 : ($High_NFkB ? 1E+100 : ( @logic ? 1.0 : 0.0) )); + rate_down = ($Low_NFkB ? 1E+100 : ($High_NFkB ? 0.0 : (@logic ? 0.0 : 1.0) )); +} +node CASP8 +{ + logic = (DISC_TNF | (DISC_FAS | CASP3) ) & (!cFLIP); + rate_up = ($Low_CASP8 ? 0.0 : ( $High_CASP8 ? 1E+100 : ( @logic ? 1.0: 0.0 )) ); + rate_down = ($Low_CASP8 ? 1E+100 : ( $High_CASP8 ? 0.0 : (@logic ? 0.0 : 1.0 )) ); +} +node BAX +{ + logic = CASP8 & (!BCL2); + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node BCL2 +{ + logic = NFkB; + rate_up = (@logic ? $TransRate : 0.0); + rate_down = @logic ? 0.0 : 1.0; +} +node mROS +{ + logic = (!NFkB); + rate_up = ($High_mROS ? 1E+100 : (@logic ? $TransRate : 0.0) ); + rate_down = ($High_mROS ? 0.0: (@logic ? 0.0 : 1.0) ); +} +node ROS +{ + logic = (mROS) & (MPT | RIP1K ); + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node ATP +{ + logic = !MPT; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node MPT +{ + logic = (!BCL2) & ROS; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node MOMP +{ + logic = BAX | MPT; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node SMAC +{ + logic = MOMP; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node mcIAP +{ + logic = (NFkB); + rate_up = @logic ? $TransRate : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node cIAP +{ + logic = (mcIAP & (!SMAC)); + rate_up = ($Low_cIAP ? 0.0 : ( @logic ? $TransRate: 0.0 )); + rate_down = ($Low_cIAP ? 1E+100 : ( (SMAC) ? 1.0 : 0.0 )); +} +node Cyt_c +{ + logic = MOMP; + rate_up = ($High_Cytc ? 1E+100 : (@logic ? 1.0 : 0.0) ); + rate_down = ($High_Cytc ? 0.0 : (@logic ? 0.0 : 1.0) ); +} +node mXIAP +{ + logic = (NFkB); + rate_up = @logic ? $TransRate : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node XIAP +{ + logic = (!SMAC) & mXIAP; + rate_up = (@logic) ? 1.0 : 0.0; + rate_down = (@logic ? 0.0 : 1.0); +} +node apoptosome +{ + logic = Cyt_c & (ATP & (!XIAP)); + rate_up = (@logic) ? 1.0 : 0.0; + rate_down = (@logic ? 0.0 : 1.0); +} +node CASP3 +{ + logic = apoptosome & (!XIAP); + rate_up = ( $Low_CASP3 ? 0.0 : ($High_CASP3 ? 1E+100 : ((@logic ? 1.0 : 0.0)) ) ); + rate_down = ($Low_CASP3 ? 1E+100 : ($High_CASP3 ? 0.0 : ( @logic ? 0.0 : 1.0) ) ); +} +node cFLIP +{ + logic = NFkB ; + rate_up = ($High_cFLIP ? 1E+100 : ((@logic) ? $TransRate : 0.0) ); + rate_down = ($High_cFLIP ? 0.0 : (@logic ? 0.0 : 1.0) ); +} +node NonACD +{ + logic = !ATP; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node Apoptosis +{ + logic = CASP3; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node Survival +{ + logic = NFkB; + rate_up = @logic ? $TransRate : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} diff --git a/config/init.tsv b/config/init.tsv new file mode 100644 index 000000000..02e46f221 --- /dev/null +++ b/config/init.tsv @@ -0,0 +1,126 @@ +x y z +-93.7351 -16.7883 0.0 +-95.7338 2.90696 0.0 +-95.9399 18.5505 0.0 +-79.8482 -55.7662 0.0 +-82.7174 -41.7014 0.0 +-80.7886 -22946 0.0 +-79.0268 -6.05337 0.0 +-82.0067 10.4321 0.0 +-80.6049 25.4132 0.0 +-82.8366 44.0516 0.0 +-78.9526 61124 0.0 +-64102 -65.5156 0.0 +-64.2225 -46.9066 0.0 +-68468 -33.3416 0.0 +-68.4907 -14.3586 0.0 +-67762 -0.0687358 0.0 +-64.3596 17.0034 0.0 +-65.1953 36802 0.0 +-65.7418 51.8249 0.0 +-64.8725 70.5213 0.0 +-49.7993 -75.1665 0.0 +-50.1662 -59.6431 0.0 +-51.6159 -42.4253 0.0 +-52.2097 -24.4339 0.0 +-49.6998 -5.49337 0.0 +-52.8067 10.2768 0.0 +-53.0525 25.5959 0.0 +-50.1145 42.8981 0.0 +-50.8895 63.7084 0.0 +-51.5362 77.8187 0.0 +-35.1206 -84.1124 0.0 +-39.0413 -67.4176 0.0 +-36.7631 -50.2966 0.0 +-35.5977 -32.8759 0.0 +-38.2835 -13.9819 0.0 +-36793 3.2073 0.0 +-38.2603 20.0752 0.0 +-38.5707 36.7987 0.0 +-35.5583 50.5694 0.0 +-35.4349 71.8035 0.0 +-34977 87.9757 0.0 +-20.4709 -93.9292 0.0 +-20396 -76.3795 0.0 +-23.7124 -57.6671 0.0 +-23908 -40.2429 0.0 +-21.0551 -22.9972 0.0 +-20.3947 -5.09517 0.0 +-20212 9.72254 0.0 +-24.1934 27.5216 0.0 +-19.9637 47.0325 0.0 +-22.1828 63.9466 0.0 +-22.5229 76.7938 0.0 +-23.5922 96.0568 0.0 +-7.4651 -98934 0.0 +-5.63692 -80.5666 0.0 +-9.19887 -66.9041 0.0 +-7.83299 -49.2237 0.0 +-7.58047 -29.8289 0.0 +-9.17806 -14.3046 0.0 +-8.47321 1.79866 0.0 +-6.22558 17232 0.0 +-6.1979 34592 0.0 +-6.06438 51.8374 0.0 +-7.99579 71.8464 0.0 +-9.34279 88.3144 0.0 +8.09689 -92.1459 0.0 +8.56241 -76.1541 0.0 +5.75799 -58.7743 0.0 +6.80561 -42.8107 0.0 +7.29498 -24.8781 0.0 +9.49315 -8.67633 0.0 +5.48934 10.7607 0.0 +7.48964 25.2213 0.0 +8.37825 44.0642 0.0 +6.63344 60.3534 0.0 +8.82467 76.4799 0.0 +5.50615 97.7667 0.0 +20.0973 -85.3025 0.0 +23.6045 -66.3319 0.0 +21.6682 -31.0106 0.0 +20.8476 -14.3643 0.0 +23354 4.3938 0.0 +23.2571 21.0108 0.0 +21.9115 37.8318 0.0 +23.0517 50.9854 0.0 +20875 68.0303 0.0 +37.9323 -76.0558 0.0 +38.8808 -59.6001 0.0 +34.7439 -39.8988 0.0 +34.7224 -26.0126 0.0 +38066 -8.93449 0.0 +36.8513 9.09404 0.0 +36.4099 27.3056 0.0 +35.4412 44.6587 0.0 +36.1567 62.8726 0.0 +37.3943 79938 0.0 +50.5785 -83.4395 0.0 +51.7827 -64.4546 0.0 +50186 -48.5523 0.0 +53.3226 -33.7905 0.0 +51.1424 -15.7653 0.0 +52.0446 1.17038 0.0 +52.8293 16.8413 0.0 +49.7305 34.3809 0.0 +51.0108 55.0179 0.0 +49.4942 67.6309 0.0 +68.0616 -56.1252 0.0 +67.5741 -38.8549 0.0 +64.4535 -24.3364 0.0 +67.9933 -6.46241 0.0 +65.0907 12.6911 0.0 +65.1839 25.4711 0.0 +66.8215 44.4639 0.0 +67.4613 60.1319 0.0 +82.3886 -46.9536 0.0 +82.0147 -33.4872 0.0 +81.3058 -15.8358 0.0 +79.4432 -0.165153 0.0 +81181 18.2513 0.0 +82.8324 35.9978 0.0 +82.6803 55.3748 0.0 +95.6087 -23.2664 0.0 +96.4069 -7.70411 0.0 +94.1872 12.5324 0.0 +93.7707 26.4937 0.0 diff --git a/core/PhysiCell_cell.cpp b/core/PhysiCell_cell.cpp index f96cf789c..80d9e09bd 100644 --- a/core/PhysiCell_cell.cpp +++ b/core/PhysiCell_cell.cpp @@ -3477,6 +3477,171 @@ int find_cell_definition_index( int search_type ) return -1; } +// Definition of the output operator for parameters class for now i haven't included the pointer to phenotype. +std::ostream& operator<<(std::ostream& os, const Cell_Parameters& params) +{ + os << "o2_hypoxic_threshold: " << params.o2_hypoxic_threshold << std::endl; + os << "o2_hypoxic_response: " << params.o2_hypoxic_response << std::endl; + os << "o2_hypoxic_saturation: " << params.o2_hypoxic_saturation << std::endl; + os << "o2_proliferation_saturation: " << params.o2_proliferation_saturation << std::endl; + os << "o2_proliferation_threshold: " << params.o2_proliferation_threshold << std::endl; + os << "o2_reference: " << params.o2_reference << std::endl; + os << "o2_necrosis_threshold: " << params.o2_necrosis_threshold << std::endl; + os << "o2_necrosis_max: " << params.o2_necrosis_max << std::endl; + os << "max_necrosis_rate: " << params.max_necrosis_rate << std::endl; + os << "necrosis_type: " << params.necrosis_type << std::endl; + + // Add other class members if necessary + + return os; +} + +// Definition of the input operator for parameters class +std::istream& operator>>(std::istream& is, Cell_Parameters& params) +{ std::string dummy; + //o2_hypoxic_threshold + std::getline(is, dummy); + params.o2_hypoxic_threshold = read_number_in_line(dummy); + + //o2_hypoxic_response + std::getline(is, dummy); + params.o2_hypoxic_response = read_number_in_line(dummy); + + //o2_hypoxic_saturation + std::getline(is, dummy); + params.o2_hypoxic_saturation = read_number_in_line(dummy); + + //o2_proliferation_saturation + std::getline(is, dummy); + params.o2_proliferation_saturation = read_number_in_line(dummy); + + //o2_proliferation_threshold + std::getline(is, dummy); + params.o2_proliferation_threshold = read_number_in_line(dummy); + + //o2_reference + std::getline(is, dummy); + params.o2_reference = read_number_in_line(dummy); + + //o2_necrosis_threshold + std::getline(is, dummy); + params.o2_necrosis_threshold = read_number_in_line(dummy); + + //o2_necrosis_max + std::getline(is, dummy); + params.o2_necrosis_max = read_number_in_line(dummy); + + //max_necrosis_rate + std::getline(is, dummy); + params.max_necrosis_rate = read_number_in_line(dummy); + + //necrosis_type + std::getline(is, dummy); + params.necrosis_type = read_number_in_line_int(dummy); + + // skip empty rows + std::getline(is, dummy); + return is; +} + + +// Implementation of stream operator for cell_state class but no neighbors since not yet tracked (comment in the .h file) + +std::ostream& operator<<(std::ostream& os, const Cell_State& cellState) +{ + + // Output orientation + os << "Orientation: "; + for (double angle : cellState.orientation) + { + os << angle << " "; + } + os << std::endl; + + // Output simple pressure + os << "Simple_Pressure: " << cellState.simple_pressure << std::endl; + + // number of nuclei + os << "number_of_nuclei: " << cellState.number_of_nuclei<< std::endl; + + // total_attack_time + //added this if since sometimes the values were very low but not zero and they were creating problems + if (cellState.total_attack_time < std::numeric_limits::min()) { + os << "total_attack_time: " << 0.0<< std::endl; + } else { + os << "total_attack_time: " << cellState.total_attack_time<< std::endl; + } + + // contact_with_basement_membrane + os << "contact_with_basement_membrane: " << cellState.contact_with_basement_membrane; + + return os; +} + +std::istream& operator>>(std::istream& is, Cell_State& cellState) +{ + // Input orientation + std::string dummy; + std::getline(is, dummy); + + // Use a stringstream to parse the string + std::istringstream stream(dummy); + + // Ignore the "Orientation:" part + std::string key_1; + stream >> key_1; // Ignore the "Orientation:" + + double number; + + // Clear orientation + cellState.orientation.clear(); + + // Update orientation + while (stream >> number) { + cellState.orientation.push_back(number); + } + + + //Simple_Pressure + std::getline(is, dummy); + cellState.simple_pressure = read_number_in_line(dummy); + + + //number_of_nuclei + std::getline(is, dummy); + cellState.number_of_nuclei = read_number_in_line_int(dummy); + + + //total_attack_time + std::getline(is, dummy); + cellState.total_attack_time = read_number_in_line(dummy); + + //contact_with_basement_membrane + std::getline(is, dummy); + cellState.contact_with_basement_membrane = read_number_in_line(dummy); + + return is; +} + + +// Implementation of the insertion operator for cell class +std::ostream& operator<<(std::ostream& os, const Cell& cell) { + os << "Cell" << std::endl; + // Write the cell's attributes to 'os' + os << "ID: " << cell.ID << std::endl; + os << "index: " << cell.index << std::endl; + os << "type: " << cell.type << std::endl; + os << "is_active: " << (cell.is_active ? "true" : "false") << std::endl; + os << cell.type_name << "\n"; + os << "is_out_of_domain: " << (cell.is_out_of_domain ? "true" : "false") << std::endl; + os << "is_movable: " << (cell.is_movable ? "true" : "false") << std::endl; + os << cell.state << "\n"; + os << cell.parameters << "\n"; + os << cell.phenotype << "\n"; + os << cell.custom_data << "\n"; + + return os; +} }; diff --git a/core/PhysiCell_cell.h b/core/PhysiCell_cell.h index 41342b4f3..48d1d457a 100644 --- a/core/PhysiCell_cell.h +++ b/core/PhysiCell_cell.h @@ -111,6 +111,10 @@ class Cell_Parameters // necrosis parameters (may evenually be moved into a reference necrotic phenotype double max_necrosis_rate; // deprecate int necrosis_type; // deprecate + + // Declaration of input/output operators + friend std::ostream& operator<<(std::ostream& os, const Cell_Parameters& params); + friend std::istream& operator>>(std::istream& is, Cell_Parameters& params); Cell_Parameters(); }; @@ -159,6 +163,9 @@ class Cell_State bool contact_with_basement_membrane; // not implemented yet Cell_State(); + friend std::ostream& operator<<(std::ostream& os, const Cell_State& cellState); + friend std::istream& operator>>(std::istream& is, Cell_State& cellState); + }; class Cell : public Basic_Agent @@ -249,6 +256,9 @@ class Cell : public Basic_Agent std::vector nearby_interacting_cells( void ); // new in 1.8.0 void convert_to_cell_definition( Cell_Definition& cd ); + + // stream operator to save cells + friend std::ostream& operator<<(std::ostream& os, const Cell& cell); }; Cell* create_cell( Cell* (*custom_instantiate)() = NULL ); diff --git a/core/PhysiCell_cell_container.cpp b/core/PhysiCell_cell_container.cpp index dcb046c72..eecddf5e0 100644 --- a/core/PhysiCell_cell_container.cpp +++ b/core/PhysiCell_cell_container.cpp @@ -72,6 +72,7 @@ #include #include +#include using namespace BioFVM; @@ -425,4 +426,121 @@ Cell_Container* create_cell_container_for_microenvironment( BioFVM::Microenviron return cell_container; } -}; +void Cell_Container::save_data(std::ofstream& os){ + os << "Cell_container:" << std::endl; + + //Cells_ready_to_divide + os << "Cells_ready_to_divide: " << cells_ready_to_divide.size() << std::endl; + + //cells_ready_to_die + os << "cells_ready_to_die: " << cells_ready_to_die.size() << std::endl; + + //boundary_condition_for_pushed_out_agents + os << "boundary_condition_for_pushed_out_agents: " << boundary_condition_for_pushed_out_agents << std::endl; + + //initialzed + os << "initialzed: " << (initialzed ? "true" : "false") << std::endl; + + //boundary_condition_for_pushed_out_agents + os << "num_divisions_in_current_step: " << num_divisions_in_current_step << std::endl; + + //boundary_condition_for_pushed_out_agents + os << "num_deaths_in_current_step: " << num_deaths_in_current_step << std::endl; + + //boundary_condition_for_pushed_out_agents + os << "last_diffusion_time: " << last_diffusion_time << std::endl; + + //boundary_condition_for_pushed_out_agents + os << "last_cell_cycle_time: " << last_cell_cycle_time << std::endl; + + //boundary_condition_for_pushed_out_agents + os << "last_mechanics_time: " << last_mechanics_time << std::endl; + + //max_cell_interactive_distance_in_voxel + os << "max_cell_interactive_distance_in_voxel: "; + for (const auto& value : max_cell_interactive_distance_in_voxel) { + os << value << " "; + } + os << std::endl; + //cells_ready_to_die + os << "cells_ready_to_die: " << cells_ready_to_die.size() << std::endl; + + os << "cells_ready_to_divide: " << cells_ready_to_divide.size() << std::endl; +/* + //cells_ready_to_die + os << "cells_ready_to_die: "; + for (const auto& cell_ptr : cells_ready_to_die) { + os << cell_ptr << " "; + } + os << std::endl; + + //cells_ready_to_divide + os << "cells_ready_to_divide: "; + for (const auto& cell_ptr : cells_ready_to_divide) { + os << cell_ptr << " "; + } + os << std::endl;*/ +} + +void Cell_Container::reset_data(std::ifstream& is){ + std::string dummy; + + //skip first 3 lines + std::getline(is, dummy); + std::getline(is, dummy); + std::getline(is, dummy); + + //cell_cell_adhesion_strength + std::getline(is, dummy); + boundary_condition_for_pushed_out_agents = read_number_in_line(dummy); + + //initialzed + std::getline(is, dummy); + initialzed = read_number_in_line_bool(dummy); + + //num_divisions_in_current_step + std::getline(is, dummy); + num_divisions_in_current_step = read_number_in_line_int(dummy); + + //num_deaths_in_current_step + std::getline(is, dummy); + num_deaths_in_current_step = read_number_in_line_int(dummy); + + //last_diffusion_time + std::getline(is, dummy); + last_diffusion_time = read_number_in_line(dummy); + + //last_cell_cycle_time + std::getline(is, dummy); + last_cell_cycle_time = read_number_in_line(dummy); + + //last_mechanics_time + std::getline(is, dummy); + last_mechanics_time = read_number_in_line(dummy); + + // max_cell_interactive_distance_in_voxel + static int n_line = 0; + std::getline(is, dummy); + std::istringstream stream_max_cell_interactive_distance_in_voxel(dummy); + std::string key_max_cell_interactive_distance_in_voxel; + stream_max_cell_interactive_distance_in_voxel >> key_max_cell_interactive_distance_in_voxel; + double number; + std::vector max_cell_interactive_distance_in_voxel_new; + while(stream_max_cell_interactive_distance_in_voxel >> number) { + max_cell_interactive_distance_in_voxel_new.push_back(number); + n_line++; + } + assert(n_line == max_cell_interactive_distance_in_voxel.size()); + max_cell_interactive_distance_in_voxel.clear(); + max_cell_interactive_distance_in_voxel = max_cell_interactive_distance_in_voxel_new; + + + // cells_ready_to_die + std::getline(is, dummy); + + // cells_ready_to_divide + std::getline(is, dummy); + + +} +}; \ No newline at end of file diff --git a/core/PhysiCell_cell_container.h b/core/PhysiCell_cell_container.h index c1c7243c1..191ec7159 100644 --- a/core/PhysiCell_cell_container.h +++ b/core/PhysiCell_cell_container.h @@ -115,6 +115,9 @@ class Cell_Container : public BioFVM::Agent_Container void flag_cell_for_division( Cell* pCell ); void flag_cell_for_removal( Cell* pCell ); bool contain_any_cell(int voxel_index); + + void save_data(std::ofstream& os); + void reset_data(std::ifstream& is); }; int find_escaping_face_index(Cell* agent); diff --git a/core/PhysiCell_custom.cpp b/core/PhysiCell_custom.cpp index ffe23ccb6..a1a44e02c 100644 --- a/core/PhysiCell_custom.cpp +++ b/core/PhysiCell_custom.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include namespace PhysiCell @@ -85,7 +86,13 @@ Variable::Variable() std::ostream& operator<<(std::ostream& os, const Variable& v) { - os << v.name << ": " << v.value << " " << v.units; + if (v.units.empty()){ + os << v.name << ": " << v.value << " no_dim"; + } + else{ + os << v.name << ": " << v.value << " " << v.units; + } + return os; } @@ -238,21 +245,137 @@ double& Custom_Cell_Data::operator[]( std::string name ) return variables[ name_to_index_map[name] ].value; } +//std::ostream& operator<<(std::ostream& os, const Custom_Cell_Data& ccd) +//{ +// os << "Custom data (scalar): " << std::endl; +// for( int i=0 ; i < ccd.variables.size() ; i++ ) +// { +// os << i << ": " << ccd.variables[i] << std::endl; +// } +// +// os << "Custom data (vector): " << std::endl; +// for( int i=0 ; i < ccd.vector_variables.size() ; i++ ) +// { +// os << i << ": " << ccd.vector_variables[i] << std::endl; +// } +// +// return os; +//} + +//Operators for variable class only is because os was already defined +std::istream& operator>>(std::istream& is, PhysiCell::Variable& v) +{ + // Read name, value, and units directly from the line + is >> v.name >> v.value >> v.units; + //std::cout << "ayooo " << v.name << std::endl; + // Check if the input was successful + if (is.fail()) + { + std::cerr << v.name << " Error: Unable to read variable data." << std::endl; + } + + return is; +} + + +//Operators for Vector_variable class only is because os was already defined +std::istream& operator>>(std::istream& is, PhysiCell::Vector_Variable& v) +{ + // Read name + is >> v.name; + + // Read values until a non-numeric character is encountered + double value; + while (is >> value) + { + v.value.push_back(value); + } + + // Clear the failbit if it was set due to encountering a non-numeric character + is.clear(); + + // Read units + is >> v.units; + + return is; +} + + +//Operators for custom data class std::ostream& operator<<(std::ostream& os, const Custom_Cell_Data& ccd) { - os << "Custom data (scalar): " << std::endl; - for( int i=0 ; i < ccd.variables.size() ; i++ ) - { - os << i << ": " << ccd.variables[i] << std::endl; - } + for (int i = 0; i < ccd.variables.size(); i++) + { - os << "Custom data (vector): " << std::endl; - for( int i=0 ; i < ccd.vector_variables.size() ; i++ ) - { - os << i << ": " << ccd.vector_variables[i] << std::endl; - } - - return os; + os << ccd.variables[i] << std::endl; + } + + for (int i = 0; i < ccd.vector_variables.size(); i++) + { + os << ccd.vector_variables[i] << std::endl; + } + + os << "End of custom data" << std::endl; + return os; } +std::istream& operator>>(std::istream& is, PhysiCell::Custom_Cell_Data& ccd) +{ + // Read scalar data until a line starts with a space + + std::string line; + for (;;) + { + // Read the whole line + std::getline(is, line); + + + // Check if the first character is a space or the line is empty + if (line.find("End of custom data") != std::string::npos) + { + break; + } + + // Use a stringstream to extract values from the line + std::istringstream line_stream(line); + PhysiCell::Variable v; + line_stream >> v; + + + // Add the variable to ccd in this version it is saving the : in name. i have to remove it + std::string correct_name = v.name.substr(0, v.name.size() - 1); + + int index = ccd.find_variable_index(correct_name); + ccd[index] = v.value; + } + + // Read vector data until a line starts with a space + //std::cout << "Enter Custom data (vector): " << std::endl; + /* + for (;;) + { + // Read the whole line + std::string line; + std::getline(is, line); + + // Check if the first character is a space or the line is empty + if (line.empty() || std::isspace(line[0])) + { + // Break the loop if the first character is a space + break; + } + + // Use a stringstream to extract values from the line + std::istringstream line_stream(line); + PhysiCell::Vector_Variable vv; + line_stream >> vv; + + // Add the vector variable to ccd + ccd.add_vector_variable(vv); + } +*/ + return is; +} + + }; diff --git a/core/PhysiCell_custom.h b/core/PhysiCell_custom.h index aea0743db..c2619593f 100644 --- a/core/PhysiCell_custom.h +++ b/core/PhysiCell_custom.h @@ -81,6 +81,7 @@ class Variable { private: friend std::ostream& operator<<(std::ostream& os, const Variable& v); // done + friend std::istream& operator>>(std::istream& is, Variable& v); public: std::string name; double value; @@ -94,6 +95,7 @@ class Vector_Variable { private: friend std::ostream& operator<<(std::ostream& os, const Vector_Variable& v); // done + friend std::istream& operator>>(std::istream& is, Vector_Variable& v); public: std::string name; @@ -133,6 +135,10 @@ class Custom_Cell_Data Custom_Cell_Data(); // done Custom_Cell_Data( const Custom_Cell_Data& ccd ); + + //stream operator declaration + friend std::ostream& operator<<(std::ostream& os, const Custom_Cell_Data& ccd); + friend std::istream& operator>>(std::istream& is, Custom_Cell_Data& ccd); }; }; diff --git a/core/PhysiCell_phenotype.cpp b/core/PhysiCell_phenotype.cpp index 806eed512..6d47e76ad 100644 --- a/core/PhysiCell_phenotype.cpp +++ b/core/PhysiCell_phenotype.cpp @@ -1430,5 +1430,1054 @@ void Cell_Integrity::advance_damage( double dt ) return; } +// streaming operator for phase +std::ostream& operator<<(std::ostream& os, const Phase& phase) { + os << "index: " << phase.index << std::endl; + os << "code: " << phase.code << std::endl; + os << "name: " << phase.name << std::endl; + os << "division_at_phase_exit: " << (phase.division_at_phase_exit ? "true" : "false") << std::endl; + os << "removal_at_phase_exit: " << (phase.removal_at_phase_exit ? "true" : "false") << std::endl; + os << "entry_function: " << phase.entry_function << std::endl; + + return os; +} + +std::istream& operator>>(std::istream& is, Phase& phase){ + + std::string dummy; + + //index + std::getline(is, dummy); + phase.index = read_number_in_line_int(dummy); + + //code + std::getline(is, dummy); + phase.code = read_number_in_line_int(dummy); + + // name + std::getline(is, dummy); + std::istringstream stream(dummy); + std::string key, name; + stream >> key; + std::getline(stream, name); + name.erase(0, name.find_first_not_of(" ")); + phase.name = name; + + // division_at_phase_exit + std::getline(is, dummy); + phase.division_at_phase_exit = read_number_in_line_bool(dummy); + + // removal_at_phase_exit + std::getline(is, dummy); + phase.removal_at_phase_exit = read_number_in_line_bool(dummy); + + // entry_function + std::getline(is, dummy); + + //empty_row + std::getline(is, dummy); + + return is; +} + +// streaming operator for phase link +std::ostream& operator<<(std::ostream& os, const Phase_Link& phase_link) { + os << "start_phase_index: " << phase_link.start_phase_index << std::endl; + os << "end_phase_index: " << phase_link.end_phase_index << std::endl; + os << "fixed_duration: " << (phase_link.fixed_duration ? "true" : "false") << std::endl; + os << "arrest_function: " << (phase_link.arrest_function ? "true" : "false") << std::endl; + //not boolean need fixing + os << "exit_function: " << phase_link.exit_function << std::endl; + + return os; +} + +std::istream& operator>>(std::istream& is, Phase_Link& phase_link){ + + std::string dummy; + + + //start_phase_index + std::getline(is, dummy); + phase_link.start_phase_index = read_number_in_line_int(dummy); + + //end_phase_index + std::getline(is, dummy); + phase_link.end_phase_index = read_number_in_line_int(dummy); + + // fixed_duration + std::getline(is, dummy); + phase_link.fixed_duration = read_number_in_line_bool(dummy); + + // arrest_function + std::getline(is, dummy); + + // exit_function + std::getline(is, dummy); + + //empty_row + std::getline(is, dummy); + + return is; +} + +// Streaming operator for cycle model +void Cycle_Model::save_data(std::ostream& os ) +{ + + //name + os << "name: " << name << std::endl; + + //code + os << "code: " << code << std::endl; + + //phases + os << "phases:" << std::endl; + for (size_t i = 0; i < phases.size(); ++i) { + os << phases[i] << std::endl;; + } + os << std::endl; + + //phase_links + os << "phase_links:" << std::endl; + for (const auto& phase_links_v : phase_links) { + for( const auto& phase_links_current : phase_links_v){ + os << phase_links_current << std::endl; + }} + os << std::endl; + + //default_phase_index + os << "default_phase_index: " << default_phase_index << std::endl; + +} + +void Cycle_Model::reset_data(std::istream& is) +{ + + std::string dummy; + + // Skip "Cycle" and read subsequent data + std::getline(is, dummy); + + + // name + std::getline(is, dummy); + std::istringstream stream(dummy); + std::string key, name_new; + stream >> key >> name_new; + name_new = name; + + //code + std::getline(is, dummy); + code = read_number_in_line_int(dummy); + + + //phases + std::getline(is, dummy); + + for (size_t i = 0; i < phases.size(); ++i) { + is >> phases[i]; + }std::getline(is, dummy); + + //phase_links + std::getline(is, dummy); + + for (auto& phase_links_v : phase_links) { + for( auto& phase_links_current : phase_links_v){ + is >> phase_links_current; + }}std::getline(is, dummy); + + //default_phase_index + std::getline(is, dummy); + default_phase_index = read_number_in_line_int(dummy); + + +} +// Streaming operator for cycle data +std::ostream& operator<<(std::ostream& os, const Cycle_Data& cycleData) { + os << "Time_Units: " << cycleData.time_units << std::endl; + os << "Current_Phase_Index: " << cycleData.current_phase_index << std::endl; + os << "Elapsed_Time_in_Phase: " << cycleData.elapsed_time_in_phase << std::endl; + + os << "Transition_Rates:" << std::endl; + int num_phases = cycleData.transition_rates.size(); + os << "num_Phases: " << num_phases << std::endl; + for (std::size_t i = 0; i < cycleData.transition_rates.size(); ++i) { + for (std::size_t j = 0; j < cycleData.transition_rates[i].size(); ++j) { + os << "i" << i << "j" << j << ": " << cycleData.transition_rates[i][j] << std::endl; + } + } + os << "End of cycle data" << std::endl; + return os; +} + +std::istream& operator>>(std::istream& is, Cycle_Data& cycleData) { + std::string dummy; + + // Read Time Units + std::getline(is, dummy); + std::istringstream stream(dummy); + std::string key, time_units; + stream >> key >> time_units; + cycleData.time_units = time_units; + + // current_phase_index + std::getline(is, dummy); + cycleData.current_phase_index = read_number_in_line_int(dummy); + + // elapsed_time_in_phase + std::getline(is, dummy); + cycleData.elapsed_time_in_phase = read_number_in_line(dummy); + + // Read "Transition Rates:" + std::getline(is, dummy); + + //Read num phases + std::getline(is, dummy); + double num_phases; + num_phases = read_number_in_line(dummy); + + // no need to reupdate since now the dimension should be good. + + // Read the transition rates until "End of cycle data" is encountered + while (std::getline(is, dummy)) { + // Check if the line contains "End of cycle data" + if (dummy.find("End of cycle data") != std::string::npos) { + break; + } + //read the phase + int i,j; + + size_t pos_i = dummy.find('i'); + size_t pos_j = dummy.find('j'); + + std::string value_i = dummy.substr(pos_i + 1, 1); + std::string value_j = dummy.substr(pos_j + 1, 1); + + i = std::stoi(value_i); + j = std::stoi(value_j); + + std::istringstream stream_case1(dummy); + std::string key_case1; + stream_case1 >> key_case1; + double p1; + while (stream_case1 >> p1) { + cycleData.transition_rates[i][j] = p1; + } + } + + // discard empty rows; + + std::getline(is, dummy); + std::getline(is, dummy); + + return is; +} + +// Stream operator for Cycle +std::ostream& operator<<(std::ostream& os, const Cycle& cycle) { + //for now no pointers in the saved model + cycle.pCycle_Model->save_data(os); + os << cycle.data << std::endl; + return os; +} + +std::istream& operator>>(std::istream& is, Cycle& cycle) { + // read string "Cycle Data:" + cycle.pCycle_Model->reset_data(is); + is >> cycle.data; + + return is; +} + +// stream operator for death parameter class +std::ostream& operator<<(std::ostream& os, const Death_Parameters& DParameters) { + os << "Death_Parameters:" << std::endl; + os << "Time_Units: " << DParameters.time_units << std::endl; + os << "Unlysed_Fluid_Change_Rate: " << DParameters.unlysed_fluid_change_rate << std::endl; + os << "Lysed_Fluid_Change_Rate: " << DParameters.lysed_fluid_change_rate << std::endl; + os << "Cytoplasmic_Biomass_Change_Rate: " << DParameters.cytoplasmic_biomass_change_rate << std::endl; + os << "Nuclear_Biomass_Change_Rate: " << DParameters.nuclear_biomass_change_rate << std::endl; + os << "Calcification_Rate: " << DParameters.calcification_rate << std::endl; + os << "Relative_Rupture_Volume: " << DParameters.relative_rupture_volume << std::endl; + + return os; +} + +std::istream& operator>>(std::istream& is, Death_Parameters& DParameters) { + std::string dummy; + + // skip the header death parameters and parameters: + std::getline(is, dummy); + std::getline(is, dummy); + + // time_units + std::getline(is, dummy); + std::istringstream stream(dummy); + std::string key, time_units; + stream >> key >> time_units; + DParameters.time_units = time_units; + + //unlysed_fluid_change_rate + std::getline(is, dummy); + DParameters.unlysed_fluid_change_rate = read_number_in_line(dummy); + + // lysed_fluid_change_rate + std::getline(is, dummy); + DParameters.lysed_fluid_change_rate = read_number_in_line(dummy); + + // cytoplasmic_biomass_change_rate + std::getline(is, dummy); + DParameters.cytoplasmic_biomass_change_rate = read_number_in_line(dummy); + + // nuclear_biomass_change_rate + std::getline(is, dummy); + DParameters.nuclear_biomass_change_rate = read_number_in_line(dummy); + + //calcification_rate + std::getline(is, dummy); + DParameters.calcification_rate = read_number_in_line(dummy); + + // relative_rupture_volume + std::getline(is, dummy); + DParameters.relative_rupture_volume = read_number_in_line(dummy); + + + //skip empty row + std::getline(is, dummy); + + return is; +} + + +//Stream operator for death class +std::ostream& operator<<(std::ostream& os, const Death& death) { + os << "Death_Information:" << std::endl; + os << "Current_Death_Model_Index: " << death.current_death_model_index << std::endl; + os << "Dead: " << (death.dead ? "true" : "false") << std::endl; + + os << "Death_Models: " << death.models.size() << std::endl; + for (size_t i = 0; i < death.models.size(); ++i) { + os << "Model " << i << ":" << std::endl; + os << "Rate: " << death.rates[i] << std::endl; + os << "Parameters:\n" << death.parameters[i] << std::endl; + } + + return os; +} +std::istream& operator>>(std::istream& is, Death& death) { + std::string dummy; + // Read the header "Death:" and "Death Information:" + std::getline(is, dummy); + std::getline(is, dummy); + + // current_death_model_index + std::getline(is, dummy); + death.current_death_model_index = read_number_in_line_int(dummy); + + // Dead status + std::getline(is, dummy); + death.dead = read_number_in_line_bool(dummy); + + // num_Death_Models + std::getline(is, dummy); + double num_Death_Models; + num_Death_Models = read_number_in_line(dummy); + + for (int i = 0; i < num_Death_Models; ++i) { + // skip the header Model: i + std::getline(is, dummy); + + // rate + std::getline(is, dummy); + death.rates[i] = read_number_in_line(dummy); + + // Parameters + is >> death.parameters[i]; + } + + // skip empty rows + std::getline(is, dummy); + return is; +} + +// Stream operator for volume class +std::ostream& operator<<(std::ostream& os, const Volume& volume) { + os << "Total: " << volume.total << std::endl; + os << "Solid: " << volume.solid << std::endl; + os << "Fluid: " << volume.fluid << std::endl; + os << "Fluid_Fraction: " << volume.fluid_fraction << std::endl; + os << "Nuclear: " << volume.nuclear << std::endl; + os << "Nuclear_Fluid: " << volume.nuclear_fluid << std::endl; + os << "Nuclear_Solid: " << volume.nuclear_solid << std::endl; + os << "Cytoplasmic: " << volume.cytoplasmic << std::endl; + os << "Cytoplasmic_Fluid: " << volume.cytoplasmic_fluid << std::endl; + os << "Cytoplasmic_Solid: " << volume.cytoplasmic_solid << std::endl; + os << "Calcified_Fraction: " << volume.calcified_fraction << std::endl; + os << "Cytoplasmic_to_Nuclear_Ratio: " << volume.cytoplasmic_to_nuclear_ratio << std::endl; + os << "Rupture_Volume: " << volume.rupture_volume << std::endl; + os << "Cytoplasmic_Biomass_Change_Rate: " << volume.cytoplasmic_biomass_change_rate << std::endl; + os << "Nuclear_Biomass_Change_Rate: " << volume.nuclear_biomass_change_rate << std::endl; + os << "Fluid_Change_Rate: " << volume.fluid_change_rate << std::endl; + os << "Calcification_Rate: " << volume.calcification_rate << std::endl; + os << "Target_Solid_Cytoplasmic: " << volume.target_solid_cytoplasmic << std::endl; + os << "Target_Solid_Nuclear: " << volume.target_solid_nuclear << std::endl; + os << "Target_Fluid_Fraction: " << volume.target_fluid_fraction << std::endl; + os << "Target_Cytoplasmic_to_Nuclear_Ratio: " << volume.target_cytoplasmic_to_nuclear_ratio << std::endl; + os << "Relative_Rupture_Volume: " << volume.relative_rupture_volume << std::endl; + + return os; +} +std::istream& operator>>(std::istream& is, Volume& volume) { + std::string dummy; + + //skip first 2 lines line + std::getline(is, dummy); + + //total + std::getline(is, dummy); + volume.total = read_number_in_line(dummy); + + //solid + std::getline(is, dummy); + volume.solid = read_number_in_line(dummy); + + //fluid + std::getline(is, dummy); + volume.fluid = read_number_in_line(dummy); + + //fluid_fraction + std::getline(is, dummy); + volume.fluid_fraction = read_number_in_line(dummy); + + //nuclear + std::getline(is, dummy); + volume.nuclear = read_number_in_line(dummy); + + //nuclear_fluid + std::getline(is, dummy); + volume.nuclear_fluid = read_number_in_line(dummy); + + //nuclear_solid + std::getline(is, dummy); + volume.nuclear_solid = read_number_in_line(dummy); + + //cytoplasmic + std::getline(is, dummy); + volume.cytoplasmic = read_number_in_line(dummy); + + //cytoplasmic_fluid + std::getline(is, dummy); + volume.cytoplasmic_fluid = read_number_in_line(dummy); + + //cytoplasmic_solid + std::getline(is, dummy); + volume.cytoplasmic_solid = read_number_in_line(dummy); + + //calcified_fraction + std::getline(is, dummy); + volume.calcified_fraction = read_number_in_line(dummy); + + //cytoplasmic_to_nuclear_ratio + std::getline(is, dummy); + volume.cytoplasmic_to_nuclear_ratio = read_number_in_line(dummy); + + //rupture_volume + std::getline(is, dummy); + volume.rupture_volume = read_number_in_line(dummy); + + //cytoplasmic_biomass_change_rate + std::getline(is, dummy); + volume.cytoplasmic_biomass_change_rate = read_number_in_line(dummy); + + //nuclear_biomass_change_rate + std::getline(is, dummy); + volume.nuclear_biomass_change_rate = read_number_in_line(dummy); + + //fluid_change_rate + std::getline(is, dummy); + volume.fluid_change_rate = read_number_in_line(dummy); + + //calcification_rate + std::getline(is, dummy); + volume.calcification_rate = read_number_in_line(dummy); + + //target_solid_cytoplasmic + std::getline(is, dummy); + volume.target_solid_cytoplasmic = read_number_in_line(dummy); + + //target_solid_nuclear + std::getline(is, dummy); + volume.target_solid_nuclear = read_number_in_line(dummy); + + //target_fluid_fraction + std::getline(is, dummy); + volume.target_fluid_fraction = read_number_in_line(dummy); + + //target_cytoplasmic_to_nuclear_ratio + std::getline(is, dummy); + volume.target_cytoplasmic_to_nuclear_ratio = read_number_in_line(dummy); + + //relative_rupture_volume + std::getline(is, dummy); + volume.relative_rupture_volume = read_number_in_line(dummy); + + //skip empty lines + std::getline(is, dummy); + return is; +} + +// Stream operator for geometry class +std::ostream& operator<<(std::ostream& os, const Geometry& geometry) { + os << "Radius: " << geometry.radius << std::endl; + os << "Nuclear_radius: " << geometry.nuclear_radius << std::endl; + os << "Surface_area: " << geometry.surface_area << std::endl; + os << "Polarity: " << geometry.polarity << std::endl; + + return os; +} + +std::istream& operator>>(std::istream& is, Geometry& geometry) { + std::string dummy; + + //skip first line + std::getline(is, dummy); + + //radius + std::getline(is, dummy); + geometry.radius = read_number_in_line(dummy); + + //nuclear_radius + std::getline(is, dummy); + geometry.nuclear_radius = read_number_in_line(dummy); + + //surface_area + std::getline(is, dummy); + geometry.surface_area = read_number_in_line(dummy); + + //polarity + std::getline(is, dummy); + geometry.polarity = read_number_in_line(dummy); + + + //skip last rows + std::getline(is, dummy); + return is; +} + +// Stream operator for Mechanics class +std::ostream& operator<<(std::ostream& os, const Mechanics& mechanics) { + os << "Cell_cell_adhesion_strength: " << mechanics.cell_cell_adhesion_strength << std::endl; + os << "Cell_BM_adhesion_strength: " << mechanics.cell_BM_adhesion_strength << std::endl; + os << "Cell_cell_repulsion_strength: " << mechanics.cell_cell_repulsion_strength << std::endl; + os << "Cell_BM_repulsion_strength: " << mechanics.cell_BM_repulsion_strength << std::endl; + os << "cell_adhesion_affinities: "; + for (const auto& affinity : mechanics.cell_adhesion_affinities) { + os << affinity << " "; + } + os << std::endl; + os << "Relative_maximum_adhesion_distance " << mechanics.relative_maximum_adhesion_distance << std::endl; + os << "maximum_number_of_attachments " << mechanics.maximum_number_of_attachments << std::endl; + os << "attachment_elastic_constant " << mechanics.attachment_elastic_constant << std::endl; + os << "attachment_rate " << mechanics.attachment_rate << std::endl; + os << "detachment_rate " << mechanics.detachment_rate << std::endl; + os << "relative_maximum_attachment_distance " << mechanics.relative_maximum_attachment_distance << std::endl; + os << "relative_detachment_distance " << mechanics.relative_detachment_distance << std::endl; + os << "maximum_attachment_rate " << mechanics.maximum_attachment_rate << std::endl; + + return os; +} + +std::istream& operator>>(std::istream& is, Mechanics& mechanics) { + std::string dummy; + + //skip first line + std::getline(is, dummy); + + //cell_cell_adhesion_strength + std::getline(is, dummy); + mechanics.cell_cell_adhesion_strength = read_number_in_line(dummy); + + //cell_BM_adhesion_strength + std::getline(is, dummy); + mechanics.cell_BM_adhesion_strength = read_number_in_line(dummy); + + //cell_cell_repulsion_strength + std::getline(is, dummy); + mechanics.cell_cell_repulsion_strength = read_number_in_line(dummy); + + //cell_BM_repulsion_strength + std::getline(is, dummy); + mechanics.cell_BM_repulsion_strength = read_number_in_line(dummy); + + // cell_adhesion_affinities + std::getline(is, dummy); + std::istringstream stream_cell_adhesion_affinities(dummy); + std::string key_cell_adhesion_affinities; + stream_cell_adhesion_affinities >> key_cell_adhesion_affinities; + double number; + std::vector cell_adhesion_affinities; + while(stream_cell_adhesion_affinities >> number) { + cell_adhesion_affinities.push_back(number); + } + mechanics.cell_adhesion_affinities.clear(); + mechanics.cell_adhesion_affinities = cell_adhesion_affinities; + + //relative_maximum_adhesion_distance + std::getline(is, dummy); + mechanics.relative_maximum_adhesion_distance = read_number_in_line(dummy); + + //maximum_number_of_attachments + std::getline(is, dummy); + mechanics.maximum_number_of_attachments = read_number_in_line_int(dummy); + + //attachment_elastic_constant + std::getline(is, dummy); + mechanics.attachment_elastic_constant = read_number_in_line(dummy); + + //attachment_rate + std::getline(is, dummy); + mechanics.attachment_rate = read_number_in_line(dummy); + + //detachment_rate + std::getline(is, dummy); + mechanics.detachment_rate = read_number_in_line(dummy); + + //relative_maximum_attachment_distance + std::getline(is, dummy); + mechanics.relative_maximum_attachment_distance = read_number_in_line(dummy); + //relative_detachment_distance + std::getline(is, dummy); + mechanics.relative_detachment_distance = read_number_in_line(dummy); + + //maximum_attachment_rate + std::getline(is, dummy); + mechanics.maximum_attachment_rate = read_number_in_line(dummy); + + //skip empty rows + std::getline(is, dummy); + return is; +} + +// stream operators for Motility class +std::ostream& operator<<(std::ostream& os, const Motility& motility) { + os << "Motility_Information:" << std::endl; + os << "Is_Motile: " << (motility.is_motile ? "true" : "false") << std::endl; + os << "Persistence_Time: " << motility.persistence_time << std::endl; + os << "Migration_Speed: " << motility.migration_speed << std::endl; + + os << "Migration_Bias_Direction: "; + for (const auto& direction : motility.migration_bias_direction) { + os << direction << " "; + } + os << std::endl; + + os << "Migration_Bias: " << motility.migration_bias << std::endl; + os << "Restrict_to_2D: " << (motility.restrict_to_2D ? "true" : "false") << std::endl; + + os << "Motility_Vector: "; + for (const auto& component : motility.motility_vector) { + os << component << " "; + } + os << std::endl; + + os << "Chemotaxis_Index: " << motility.chemotaxis_index << std::endl; + os << "Chemotaxis_Direction: " << motility.chemotaxis_direction << std::endl; + + return os; +} + +std::istream& operator>>(std::istream& is, Motility& motilityparams) { + std::string dummy; + + // read headers + std::getline(is, dummy); + std::getline(is, dummy); + + //is motile + std::getline(is, dummy); + motilityparams.is_motile = read_number_in_line_bool(dummy); + + //persistence_time + std::getline(is, dummy); + motilityparams.persistence_time = read_number_in_line(dummy); + + //migration_speed + std::getline(is, dummy); + motilityparams.migration_speed = read_number_in_line(dummy); + + // migration_bias_direction + std::getline(is, dummy); + std::istringstream stream_migration_bias_direction(dummy); + std::string key_migration_bias_direction; + stream_migration_bias_direction >> key_migration_bias_direction; + double number; + std::vector migration_bias_direction; + while(stream_migration_bias_direction >> number) { + migration_bias_direction.push_back(number); + } + motilityparams.migration_bias_direction.clear(); + motilityparams.migration_bias_direction = migration_bias_direction; + + //migration_bias + std::getline(is, dummy); + motilityparams.migration_bias = read_number_in_line(dummy); + + //restrict_to_2D + std::getline(is, dummy); + motilityparams.restrict_to_2D = read_number_in_line_bool(dummy); + + // motility_vector + std::getline(is, dummy); + std::istringstream stream_motility_vector(dummy); + std::string key_motility_vector; + stream_motility_vector >> key_motility_vector; + double number_2; + std::vector motility_vector; + while(stream_motility_vector >> number_2) { + motility_vector.push_back(number_2); + } + motilityparams.motility_vector.clear(); + motilityparams.motility_vector = motility_vector; + + //chemotaxis_index + std::getline(is, dummy); + motilityparams.chemotaxis_index = read_number_in_line_int(dummy); + + //chemotaxis_direction + std::getline(is, dummy); + motilityparams.chemotaxis_direction = read_number_in_line_int(dummy); + + //skip empty rows + std::getline(is, dummy); + + return is; +} + +// Streaming operators for Secretion class +std::ostream& operator<<(std::ostream& os, const Secretion& secretionparams) { + os << "Secretion_Information:" << std::endl; + os << "Number_of_Secretions: " << secretionparams.secretion_rates.size() << std::endl; + + for (size_t i = 0; i < secretionparams.secretion_rates.size(); ++i) { + os << "Secretion " << i << ":" << std::endl; + os << "Secretion_Rate: " << secretionparams.secretion_rates[i] << std::endl; + os << "Uptake_Rate: " << secretionparams.uptake_rates[i] << std::endl; + os << "Saturation_Density: " << secretionparams.saturation_densities[i] << std::endl; + os << "Net_Export_Rate: " << secretionparams.net_export_rates[i] << "\n" << std::endl; + } + + return os; +} + +std::istream& operator>>(std::istream& is, Secretion& secretionparams) { + std::string dummy; + + // read headers + std::getline(is, dummy); + std::getline(is, dummy); + + //number_of_secretions + std::getline(is, dummy); + double number_of_secretions; + number_of_secretions = read_number_in_line(dummy); + + for (size_t i = 0; i < number_of_secretions; ++i) { + + //skip header + std::getline(is, dummy); + + //secretion_rate + std::getline(is, dummy); + secretionparams.secretion_rates[i] = read_number_in_line(dummy); + + //uptake_rate + std::getline(is, dummy); + secretionparams.uptake_rates[i] = read_number_in_line(dummy); + + //saturation_density + std::getline(is, dummy); + secretionparams.saturation_densities[i] = read_number_in_line(dummy); + + //net_export_rate + std::getline(is, dummy); + secretionparams.net_export_rates[i] = read_number_in_line(dummy); + + //skip empty rows + std::getline(is, dummy); + + } + + //skip last rows + std::getline(is, dummy); + + return is; +} + +// Streaming operators for class Molecular +std::ostream& operator<<(std::ostream& os, const Molecular& molecular) { + os << "Molecular_Information:" << std::endl; + os << "number_of_substrates: " << molecular.internalized_total_substrates.size() << std::endl; + + for (size_t i = 0; i < molecular.internalized_total_substrates.size(); ++i){ + + os << "Substrate: " << i << std::endl; + os << "Internalized_Total_Substrates: " << molecular.internalized_total_substrates[i] << std::endl; + os << "Fraction_Released_at_Death: " << molecular.fraction_released_at_death[i] << std::endl; + os << "Fraction_Transferred_When_Ingested: " << molecular.fraction_transferred_when_ingested[i] << "\n" << std::endl; + + } + + return os; +} + +std::istream& operator>>(std::istream& is, Molecular& molecular) { + std::string dummy; + + // read headers + std::getline(is, dummy); + std::getline(is, dummy); + + //number_of_secretions + std::getline(is, dummy); + double number_of_substrates; + number_of_substrates = read_number_in_line(dummy); + + for (size_t i = 0; i < number_of_substrates; ++i) { + + //skip header + std::getline(is, dummy); + + //Internalized_Total_Substrates + std::getline(is, dummy); + molecular.internalized_total_substrates[i] = read_number_in_line(dummy); + + //Fraction_Released_at_Death + std::getline(is, dummy); + molecular.fraction_released_at_death[i] = read_number_in_line(dummy); + + //Fraction_Transferred_When_Ingested + std::getline(is, dummy); + molecular.fraction_released_at_death[i] = read_number_in_line(dummy); + + //skip empty rows + std::getline(is, dummy); + + } + + //skip last rows + std::getline(is, dummy); + std::getline(is, dummy); + return is; +} + +std::ostream& operator<<(std::ostream& os, const Cell_Interactions& cell_interactions) { + os << "Cell_Interactions_Information:" << std::endl; + os << "Dead_Phagocytosis_Rate: " << cell_interactions.other_dead_phagocytosis_rate << std::endl; + os << "Live_Phagocytosis_Rates: "; + for (size_t i = 0; i < cell_interactions.live_phagocytosis_rates.size(); ++i) { + os << cell_interactions.live_phagocytosis_rates[i] << " "; + } + os << std::endl; + os << "Attack_Rates: "; + for (size_t i = 0; i < cell_interactions.attack_rates.size(); ++i) { + os << cell_interactions.attack_rates[i] << " "; + } + os << std::endl; + os << "Immunogenicities: "; + for (size_t i = 0; i < cell_interactions.immunogenicities.size(); ++i) { + os << cell_interactions.immunogenicities[i] << " "; + } + os << std::endl; + + os << "Damage_Rate: " << cell_interactions.attack_damage_rate << std::endl; + os << "Fusion_Rates: "; + for (size_t i = 0; i < cell_interactions.fusion_rates.size(); ++i) { + os << cell_interactions.fusion_rates[i] << " "; + } + os << std::endl; + + return os; +} + +std::istream& operator>>(std::istream& is, Cell_Interactions& cell_interactions){ + std::string dummy; + + // read headers + std::getline(is, dummy); + + //other_dead_phagocytosis_rate + std::getline(is, dummy); + cell_interactions.other_dead_phagocytosis_rate = read_number_in_line(dummy); + + // Live_Phagocytosis_Rates + std::getline(is, dummy); + std::istringstream stream_Live_Phagocytosis_Rates(dummy); + std::string key_Live_Phagocytosis_Rates; + stream_Live_Phagocytosis_Rates >> key_Live_Phagocytosis_Rates; + double number1; + std::vector Live_Phagocytosis_Rates; + while(stream_Live_Phagocytosis_Rates >> number1) { + Live_Phagocytosis_Rates.push_back(number1); + } + cell_interactions.live_phagocytosis_rates.clear(); + cell_interactions.live_phagocytosis_rates = Live_Phagocytosis_Rates; + + // Attack_Rates + std::getline(is, dummy); + std::istringstream stream_Attack_Rates(dummy); + std::string key_Attack_Rates; + stream_Attack_Rates >> key_Attack_Rates; + double number2; + std::vector Attack_Rates; + while(stream_Attack_Rates >> number2) { + Attack_Rates.push_back(number2); + } + cell_interactions.attack_rates.clear(); + cell_interactions.attack_rates = Attack_Rates; + + // Immunogenicities + std::getline(is, dummy); + std::istringstream stream_Immunogenicities(dummy); + std::string key_Immunogenicities; + stream_Immunogenicities >> key_Immunogenicities; + double number3; + std::vector Immunogenicities; + while(stream_Immunogenicities >> number3) { + Immunogenicities.push_back(number3); + } + cell_interactions.immunogenicities.clear(); + cell_interactions.immunogenicities = Immunogenicities; + + //Damage_Rate + std::getline(is, dummy); + cell_interactions.attack_damage_rate = read_number_in_line(dummy); + + // Fusion_Rates + std::getline(is, dummy); + std::istringstream stream_Fusion_Rates(dummy); + std::string key_Fusion_Rates; + stream_Fusion_Rates >> key_Fusion_Rates; + double number4; + std::vector Fusion_Rates; + while(stream_Fusion_Rates >> number4) { + Fusion_Rates.push_back(number4); + } + cell_interactions.fusion_rates.clear(); + cell_interactions.fusion_rates = Fusion_Rates; + + std::getline(is, dummy); + + + return is; +} + +std::ostream& operator<<(std::ostream& os, const Cell_Transformations& cell_transformations) { + os << "Cell_Transformations_Information:" << std::endl; + os << "Transformation_Rates: "; + for (size_t i = 0; i < cell_transformations.transformation_rates.size(); ++i) { + os << cell_transformations.transformation_rates[i] << " "; + } + os << std::endl; + + return os; +} + +std::istream& operator>>(std::istream& is, Cell_Transformations& cell_transformations) { + std::string dummy; + + // read headers + std::getline(is, dummy); + std::getline(is, dummy); + + // Transformation_Rates + std::getline(is, dummy); + std::istringstream stream_Transformation_Rates(dummy); + std::string key_Transformation_Rates; + stream_Transformation_Rates >> key_Transformation_Rates; + double number; + std::vector Transformation_Rates; + while(stream_Transformation_Rates >> number) { + Transformation_Rates.push_back(number); + } + cell_transformations.transformation_rates.clear(); + cell_transformations.transformation_rates = Transformation_Rates; + + std::getline(is, dummy); + std::getline(is, dummy); + return is; + +} + +// Stream operator for Phenotyope class +std::ostream& operator<<(std::ostream& os, const Phenotype& phenotype) { + os << "Flagged_for_division: " << (phenotype.flagged_for_division ? "true" : "false") << std::endl; + os << "Flagged_for_removal: " << (phenotype.flagged_for_removal ? "true" : "false") << std::endl; + os << "Death:\n" << phenotype.death << std::endl; + os << "Cycle:\n" << phenotype.cycle << std::endl; + os << "Volume:\n" << phenotype.volume << std::endl; + os << "Geometry:\n" << phenotype.geometry << std::endl; + os << "Mechanics:\n" << phenotype.mechanics << std::endl; + os << "Motility:\n" << phenotype.motility << std::endl; + os << "Secretion:\n" << phenotype.secretion << std::endl; + os << "Molecular:\n" << phenotype.molecular << std::endl; + os << "Cell_Interactions:\n" << phenotype.cell_interactions << std::endl; + os << "Cell_Transformations:\n" << phenotype.cell_transformations << std::endl; + return os; + } + +}; +double read_number_in_line(const std::string& line){ + std::istringstream stream(line); + std::string key; + stream >> key; + std::string numberStr; + if(stream >> numberStr) { + try { + long double value = std::stod(numberStr); + + return value; + } catch (std::invalid_argument& e) { + throw std::runtime_error("Failed to parse value from line"); + } catch (std::out_of_range& e) { + throw std::runtime_error("Value out of range for type"); + } + } + throw std::runtime_error("Failed to parse value from line"); +}; + +int read_number_in_line_int(const std::string& line){ + std::istringstream stream(line); + std::string key; + stream >> key; + std::string numberStr; + if(stream >> numberStr) { + try { + int value = std::stoi(numberStr); + return value; + } catch (std::invalid_argument& e) { + throw std::runtime_error("Failed to parse value from line"); + } catch (std::out_of_range& e) { + throw std::runtime_error("Value out of range for type"); + } + } + throw std::runtime_error("Failed to parse value from line"); +}; + +bool read_number_in_line_bool(const std::string& line){ + std::istringstream stream(line); + std::string key, value; + stream >> key >> value; + + + if(value == "true"){ + return true; + } + else if(value == "false"){ + return false; + } + else{ + throw std::runtime_error("Failed to parse value from line"); + } }; diff --git a/core/PhysiCell_phenotype.h b/core/PhysiCell_phenotype.h index ebbd39843..b4c5c1a74 100644 --- a/core/PhysiCell_phenotype.h +++ b/core/PhysiCell_phenotype.h @@ -72,6 +72,7 @@ #include #include #include +#include #include "../BioFVM/BioFVM.h" @@ -115,6 +116,9 @@ class Phase void (*entry_function)( Cell* pCell, Phenotype& phenotype, double dt ); Phase(); // done + + friend std::ostream& operator<<(std::ostream& os, const Phase& phase); + friend std::istream& operator>>(std::istream& is, Phase& phase); }; class Phase_Link @@ -132,6 +136,9 @@ class Phase_Link // function to be excecuted when completing the phase transition Phase_Link(); // done + + friend std::ostream& operator<<(std::ostream& os, const Phase_Link& phase_link); + friend std::istream& operator>>(std::istream& is, Phase_Link& phase_link); }; class Cycle_Data @@ -169,6 +176,8 @@ class Cycle_Data double& exit_rate(int phase_index ); // This returns the first transition rate out of // phase # phase_index. It is only relevant if the phase has only one phase link // (true for many cycle models). + friend std::ostream& operator<<(std::ostream& os, const Cycle_Data& cycleData); + friend std::istream& operator>>(std::istream& is, Cycle_Data& cycleData); }; class Cycle_Model @@ -211,6 +220,9 @@ class Cycle_Model Phase_Link& phase_link(int start_index,int end_index ); // done std::ostream& display( std::ostream& os ); // done + + void save_data(std::ostream& os ); + void reset_data(std::istream& is ); }; class Cycle @@ -230,6 +242,8 @@ class Cycle int& current_phase_index( void ); // done void sync_to_cycle_model( Cycle_Model& cm ); // done + friend std::ostream& operator<<(std::ostream& os, const Cycle& cycle_params); + friend std::istream& operator>>(std::istream& is, Cycle& cycle_params); }; class Death_Parameters @@ -248,6 +262,9 @@ class Death_Parameters double relative_rupture_volume; Death_Parameters(); // done + + friend std::ostream& operator<<(std::ostream& os, const Death_Parameters& DParameters); + friend std::istream& operator>>(std::istream& is, Death_Parameters& DParameters); }; class Death @@ -278,6 +295,9 @@ class Death // ease of access double& apoptosis_rate(void); double& necrosis_rate(void); + + friend std::ostream& operator<<(std::ostream& os, const Death& deathparams); + friend std::istream& operator>>(std::istream& is, Death& deathparams); }; class Volume @@ -336,6 +356,8 @@ class Volume void divide( void ); // done void multiply_by_ratio(double); // done + friend std::ostream& operator<<(std::ostream& os, const Volume& volumeparams); + friend std::istream& operator>>(std::istream& is, Volume& volumeparams); }; class Geometry @@ -354,6 +376,8 @@ class Geometry void update_surface_area( Cell* pCell, Phenotype& phenotype, double dt ); // done void update( Cell* pCell, Phenotype& phenotype, double dt ); // done + friend std::ostream& operator<<(std::ostream& os, const Geometry& geometryparams); + friend std::istream& operator>>(std::istream& is, Geometry& geometryparams); }; class Mechanics @@ -397,7 +421,8 @@ class Mechanics void set_absolute_equilibrium_distance( Phenotype& phenotype, double new_value ); // done - + friend std::ostream& operator<<(std::ostream& os, const Mechanics& mechanicsparams); + friend std::istream& operator>>(std::istream& is, Mechanics& mechanicsparams); }; class Motility @@ -432,6 +457,9 @@ class Motility Motility(); // done + + friend std::ostream& operator<<(std::ostream& os, const Motility& motilityparams); + friend std::istream& operator>>(std::istream& is, Motility& motilityparams); }; class Secretion @@ -467,7 +495,10 @@ class Secretion double& secretion_rate( std::string name ); double& uptake_rate( std::string name ); double& saturation_density( std::string name ); - double& net_export_rate( std::string name ); + double& net_export_rate( std::string name ); + + friend std::ostream& operator<<(std::ostream& os, const Secretion& secretionparams); + friend std::istream& operator>>(std::istream& is, Secretion& secretionparams); }; class Cell_Functions @@ -509,7 +540,9 @@ class Cell_Functions void (*plot_agent_SVG)(std::ofstream& os, Cell* pCell, double z_slice, std::vector (*cell_coloring_function)(Cell*), double X_lower, double Y_lower); void (*plot_agent_legend)(std::ofstream& os, Cell_Definition* cell_def, double& cursor_x, double& cursor_y, std::vector (*cell_coloring_function)(Cell*), double temp_cell_radius); - + friend std::ostream& operator<<(std::ostream& os, const Cell_Functions& cellFunctions); + friend std::istream& operator>>(std::istream& is, Cell_Functions& cellFunctions); + Cell_Functions(); // done }; @@ -591,7 +624,10 @@ class Molecular void sync_to_cell( Basic_Agent* pCell ); // ease of access - double& internalized_total_substrate( std::string name ); + double& internalized_total_substrate( std::string name ); + + friend std::ostream& operator<<(std::ostream& os, const Molecular& molecular); + friend std::istream& operator>>(std::istream& is, Molecular& molecular); }; @@ -642,9 +678,16 @@ class Intracellular virtual bool has_variable(std::string name) = 0; virtual bool get_boolean_variable_value(std::string name) = 0; virtual void set_boolean_variable_value(std::string name, bool value) = 0; + virtual int get_number_of_nodes() = 0; // virtual bool get_double_variable_value(std::string name) = 0; // virtual void set_double_variable_value(std::string name, bool value) = 0; virtual void print_current_nodes() = 0; + virtual void save_current_nodes(std::ostream& out_stream) = 0; + virtual void save_current_parameters(std::ostream& out_stream) = 0; + virtual void read_current_parameter(std::ifstream& in_stream) = 0; + virtual void save_current_parameters_maboss(std::ostream& out_stream) = 0; + virtual void read_current_parameter_maboss(std::ifstream& in_stream) = 0; + virtual void reinit_maboss(std::string networkFile, std::string configFile) = 0; // ================ specific to "roadrunner" ================ @@ -697,7 +740,10 @@ class Cell_Interactions double& immunogenicity( std::string type_name ); // done // automated cell phagocytosis, attack, and fusion -// void perform_interactions( Cell* pCell, Phenotype& phenotype, double dt ); +// void perform_interactions( Cell* pCell, Phenotype& phenotype, double dt ); + + friend std::ostream& operator<<(std::ostream& os, const Cell_Interactions& cell_interactions); + friend std::istream& operator>>(std::istream& is, Cell_Interactions& cell_interactions); }; class Cell_Transformations @@ -716,6 +762,9 @@ class Cell_Transformations // automated cell transformations // void perform_transformations( Cell* pCell, Phenotype& phenotype, double dt ); + + friend std::ostream& operator<<(std::ostream& os, const Cell_Transformations& cell_transformations); + friend std::istream& operator>>(std::istream& is, Cell_Transformations& cell_transformations); }; // pre-beta functionality in 1.10.3 @@ -747,6 +796,9 @@ class Cell_Integrity Cell_Integrity(); void advance_damage( double dt ); + + friend std::ostream& operator<<(std::ostream& os, const Cell_Integrity& integrity); + friend std::istream& operator>>(std::istream& is, Cell_Integrity& integrity); }; class Phenotype @@ -786,8 +838,13 @@ class Phenotype // make sure cycle, death, etc. are synced to the defaults. void sync_to_default_functions( void ); // done + + friend std::ostream& operator<<(std::ostream& os, const Phenotype& pheno_params); }; }; #endif +double read_number_in_line(const std::string& line); +int read_number_in_line_int(const std::string& line); +bool read_number_in_line_bool(const std::string& line); diff --git a/core/PhysiCell_utilities.cpp b/core/PhysiCell_utilities.cpp index d50fa812d..1e2b2e2c3 100644 --- a/core/PhysiCell_utilities.cpp +++ b/core/PhysiCell_utilities.cpp @@ -72,6 +72,10 @@ namespace PhysiCell{ +int counter_normal_random = 0; +int counter_int_random = 0; +int counter_double_random = 0; + thread_local std::mt19937_64 physicell_PRNG_generator; thread_local bool local_pnrg_setup_done = false; @@ -359,4 +363,51 @@ int choose_event( std::vector& probabilities ) return probabilities.size(); } +void save_counters(std::ostream& out_stream) +{ + out_stream << "counter_double_random: " << counter_double_random << std::endl; + out_stream << "counter_int_random: " << counter_int_random << std::endl; + out_stream << "counter_normal_random: " << counter_normal_random << std::endl; +} + +void print_counters() +{ + std::cout << "counter_double_random: " << counter_double_random << std::endl; + std::cout << "counter_int_random: " << counter_int_random << std::endl; + std::cout << "counter_normal_random: " << counter_normal_random << std::endl; +} + +void set_counter_double_random(int value) +{ + if (counter_double_random > value){ + std::cout << "UniformRandom counter still greater than value" << std::endl; + return; + } + while (counter_double_random != value){ + UniformRandom(); + } +} + +void set_counter_int_random(int value) +{ + if (counter_int_random > value){ + std::cout << "UniformInt counter still greater than value" << std::endl; + return; + } + while (counter_int_random != value){ + UniformInt(); + } +} + +void set_counter_normal_random(int value) +{ + if (counter_normal_random > value){ + std::cout << "NormalRandom counter still greater than value" << std::endl; + return; + } + while (counter_normal_random != value){ + NormalRandom(0.5, 1); + } +} + }; diff --git a/core/PhysiCell_utilities.h b/core/PhysiCell_utilities.h index 7f83aaf5f..e1cadb151 100644 --- a/core/PhysiCell_utilities.h +++ b/core/PhysiCell_utilities.h @@ -111,6 +111,16 @@ void add_software_citation( std::string name , std::string version, std::string int choose_event( std::vector& probabilities ); +void save_counters(std::ostream& out_stream); + +void set_counter_double_random(int value); + +void set_counter_int_random(int value); + +void set_counter_normal_random(int value); + +void print_counters(); + }; #endif diff --git a/custom_modules/custom.cpp b/custom_modules/custom.cpp new file mode 100644 index 000000000..a79a5dd2c --- /dev/null +++ b/custom_modules/custom.cpp @@ -0,0 +1,551 @@ +/* +############################################################################### +# If you use PhysiCell in your project, please cite PhysiCell and the version # +# number, such as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1]. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# See VERSION.txt or call get_PhysiCell_version() to get the current version # +# x.y.z. Call display_citations() to get detailed information on all cite-# +# able software used in your PhysiCell application. # +# # +# Because PhysiCell extensively uses BioFVM, we suggest you also cite BioFVM # +# as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1], # +# with BioFVM [2] to solve the transport equations. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# [2] A Ghaffarizadeh, SH Friedman, and P Macklin, BioFVM: an efficient para- # +# llelized diffusive transport solver for 3-D biological simulations, # +# Bioinformatics 32(8): 1256-8, 2016. DOI: 10.1093/bioinformatics/btv730 # +# # +############################################################################### +# # +# BSD 3-Clause License (see https://opensource.org/licenses/BSD-3-Clause) # +# # +# Copyright (c) 2015-2018, Paul Macklin and the PhysiCell Project # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are met: # +# # +# 1. Redistributions of source code must retain the above copyright notice, # +# this list of conditions and the following disclaimer. # +# # +# 2. Redistributions in binary form must reproduce the above copyright # +# notice, this list of conditions and the following disclaimer in the # +# documentation and/or other materials provided with the distribution. # +# # +# 3. Neither the name of the copyright holder nor the names of its # +# contributors may be used to endorse or promote products derived from this # +# software without specific prior written permission. # +# # +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # +# POSSIBILITY OF SUCH DAMAGE. # +# # +############################################################################### +*/ + +#include "./custom.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +// declare cell definitions here +void create_cell_types(void) +{ + SeedRandom(); + + initialize_default_cell_definition(); + + /* This parses the cell definitions in the XML config file. */ + initialize_cell_definitions_from_pugixml(); + + // This sets the pre and post intracellular update functions + cell_defaults.functions.pre_update_intracellular = update_boolean_model_inputs; + cell_defaults.functions.post_update_intracellular = update_behaviors; + cell_defaults.functions.update_phenotype = NULL; + + // This initializes the the TNF receptor model + tnf_receptor_model_setup(); + tnf_boolean_model_interface_setup(); + submodel_registry.display(std::cout); + + // Needs to initialize one of the receptor state to the total receptor value + cell_defaults.custom_data["unbound_external_TNFR"] = cell_defaults.custom_data["TNFR_receptors_per_cell"]; + cell_defaults.custom_data["bound_external_TNFR"] = 0; + cell_defaults.custom_data["bound_internal_TNFR"] = 0; + + build_cell_definitions_maps(); + + setup_signal_behavior_dictionaries(); + + display_cell_definitions(std::cout); + + return; +} + + +void setup_microenvironment(void) +{ + initialize_microenvironment(); + return; +} + +void setup_tissue(void) +{ + std::vector> positions; + + if ( parameters.bools("read_init") ) + { + std::string csv_fname = parameters.strings("init_cells_filename"); + positions = read_cells_positions(csv_fname, '\t', true); + + } + else + { + double cell_radius = cell_defaults.phenotype.geometry.radius; + double tumor_radius = parameters.doubles("tumor_radius"); + if (default_microenvironment_options.simulate_2D == true) + positions = create_cell_disc_positions(cell_radius,tumor_radius); + else + positions = create_cell_sphere_positions(cell_radius,tumor_radius); + + } + + Cell* pCell = NULL; + for (int i = 0; i < positions.size(); i++) + { + pCell = create_cell(get_cell_definition("default")); + pCell->assign_position(positions[i]); + + static int idx_bind_rate = pCell->custom_data.find_variable_index( "TNFR_binding_rate" ); + static float mean_bind_rate = pCell->custom_data[idx_bind_rate]; + static float std_bind_rate = parameters.doubles("TNFR_binding_rate_std"); + static float min_bind_rate = parameters.doubles("TNFR_binding_rate_min"); + static float max_bind_rate = parameters.doubles("TNFR_binding_rate_max"); + + if(std_bind_rate > 0 ) + { + pCell->custom_data[idx_bind_rate] = NormalRandom(mean_bind_rate, std_bind_rate); + if (pCell->custom_data[idx_bind_rate] < min_bind_rate) + { pCell->custom_data[idx_bind_rate] = min_bind_rate; } + if (pCell->custom_data[idx_bind_rate] > max_bind_rate) + { pCell->custom_data[idx_bind_rate] = max_bind_rate; } + } + + + static int idx_endo_rate = pCell->custom_data.find_variable_index( "TNFR_endocytosis_rate" ); + static float mean_endo_rate = pCell->custom_data[idx_endo_rate]; + static float std_endo_rate = parameters.doubles("TNFR_endocytosis_rate_std"); + static float min_endo_rate = parameters.doubles("TNFR_endocytosis_rate_min"); + static float max_endo_rate = parameters.doubles("TNFR_endocytosis_rate_max"); + + if(std_endo_rate > 0) + { + pCell->custom_data[idx_endo_rate] = NormalRandom(mean_endo_rate, std_endo_rate); + if (pCell->custom_data[idx_endo_rate] < min_endo_rate) + { pCell->custom_data[idx_endo_rate] = min_endo_rate; } + if (pCell->custom_data[idx_endo_rate] > max_endo_rate) + { pCell->custom_data[idx_endo_rate] = max_endo_rate; } + } + + static int idx_recycle_rate = pCell->custom_data.find_variable_index( "TNFR_recycling_rate" ); + static float mean_recycle_rate = pCell->custom_data[idx_recycle_rate]; + static float std_recycle_rate = parameters.doubles("TNFR_recycling_rate_std"); + static float min_recycle_rate = parameters.doubles("TNFR_recycling_rate_min"); + static float max_recycle_rate = parameters.doubles("TNFR_recycling_rate_max"); + + if(std_recycle_rate > 0) + { + pCell->custom_data[idx_recycle_rate] = NormalRandom(mean_recycle_rate, std_recycle_rate); + if (pCell->custom_data[idx_recycle_rate] < min_recycle_rate) + { pCell->custom_data[idx_recycle_rate] = min_recycle_rate; } + if (pCell->custom_data[idx_recycle_rate] > max_recycle_rate) + { pCell->custom_data[idx_recycle_rate] = max_recycle_rate; } + } + + update_monitor_variables(pCell); + } + + return; +} + +void update_variables_monitor() +{ + for (int i = 0; i < (*all_cells).size(); i++) + { + // Access the current cell + Cell *pCell = (*all_cells)[i]; + + update_monitor_variables(pCell); + } + + +} + +std::vector> read_cells_positions(std::string filename, char delimiter, bool header) +{ + // File pointer + std::fstream fin; + std::vector> positions; + + // Open an existing file + fin.open(filename, std::ios::in); + + // Read the Data from the file + // as String Vector + std::vector row; + std::string line, word; + + if (header) + { getline(fin, line); } + + do + { + row.clear(); + + // read an entire row and + // store it in a string variable 'line' + getline(fin, line); + + // used for breaking words + std::stringstream s(line); + + while (getline(s, word, delimiter)) + { + row.push_back(word); + } + + std::vector tempPoint(3,0.0); + tempPoint[0]= std::stof(row[0]); + tempPoint[1]= std::stof(row[1]); + tempPoint[2]= std::stof(row[2]); + + positions.push_back(tempPoint); + } while (!fin.eof()); + + return positions; +} + +std::vector> create_cell_sphere_positions(double cell_radius, double sphere_radius) +{ + std::vector> cells; + int xc=0,yc=0,zc=0; + double x_spacing= cell_radius*sqrt(3); + double y_spacing= cell_radius*2; + double z_spacing= cell_radius*sqrt(3); + + std::vector tempPoint(3,0.0); + // std::vector cylinder_center(3,0.0); + + for(double z=-sphere_radius;z> create_cell_disc_positions(double cell_radius, double disc_radius) +{ + double cell_spacing = 0.95 * 2.0 * cell_radius; + + double x = 0.0; + double y = 0.0; + double x_outer = 0.0; + + std::vector> positions; + std::vector tempPoint(3,0.0); + + int n = 0; + while( y < disc_radius ) + { + x = 0.0; + if( n % 2 == 1 ) + { x = 0.5 * cell_spacing; } + x_outer = sqrt( disc_radius*disc_radius - y*y ); + + while( x < x_outer ) + { + tempPoint[0]= x; tempPoint[1]= y; tempPoint[2]= 0.0; + positions.push_back(tempPoint); + if( fabs( y ) > 0.01 ) + { + tempPoint[0]= x; tempPoint[1]= -y; tempPoint[2]= 0.0; + positions.push_back(tempPoint); + } + if( fabs( x ) > 0.01 ) + { + tempPoint[0]= -x; tempPoint[1]= y; tempPoint[2]= 0.0; + positions.push_back(tempPoint); + if( fabs( y ) > 0.01 ) + { + tempPoint[0]= -x; tempPoint[1]= -y; tempPoint[2]= 0.0; + positions.push_back(tempPoint); + } + } + x += cell_spacing; + } + y += cell_spacing * sqrt(3.0)/2.0; + n++; + } + return positions; +} + +void inject_density_sphere(int density_index, double concentration, double membrane_lenght) +{ + // Inject given concentration on the extremities only + #pragma omp parallel for + for (int n = 0; n < microenvironment.number_of_voxels(); n++) + { + auto current_voxel = microenvironment.voxels(n); + std::vector cent = {current_voxel.center[0], current_voxel.center[1], current_voxel.center[2]}; + + if ((membrane_lenght - norm(cent)) <= 0) + microenvironment.density_vector(n)[density_index] = concentration; + } +} + +void remove_density(int density_index) +{ + for (int n = 0; n < microenvironment.number_of_voxels(); n++) + microenvironment.density_vector(n)[density_index] = 0; +} + +std::vector my_coloring_function(Cell *pCell) +{ + // start with live coloring + std::vector output = false_cell_coloring_live_dead(pCell); + + // dead cells + if (pCell->phenotype.death.dead == false) + { + static int nR_EB = pCell->custom_data.find_variable_index("bound external TNFR"); + float activation_threshold = pCell->custom_data.find_variable_index("TNFR activation threshold"); + + int bounded_tnf = (int)round((pCell->custom_data[nR_EB] / activation_threshold) * 255.0); + if (bounded_tnf > 0) + { + char szTempString[128]; + sprintf(szTempString, "rgb(%u,%u,%u)", bounded_tnf, bounded_tnf, 255 - bounded_tnf); + output[0].assign("black"); + output[1].assign(szTempString); + output[2].assign("black"); + output[3].assign(szTempString); + } + } + + return output; +} + + +double total_live_cell_count() +{ + double out = 0.0; + + for( int i=0; i < (*all_cells).size() ; i++ ) + { + if( (*all_cells)[i]->phenotype.death.dead == false && (*all_cells)[i]->type == 0 ) + { out += 1.0; } + } + + return out; +} + +double total_dead_cell_count() +{ + double out = 0.0; + + for( int i=0; i < (*all_cells).size() ; i++ ) + { + if( (*all_cells)[i]->phenotype.death.dead == true && (*all_cells)[i]->phenotype.death.current_death_model_index == 0 ) + { out += 1.0; } + } + + return out; +} + +double total_necrosis_cell_count() +{ + double out = 0.0; + + for( int i=0; i < (*all_cells).size() ; i++ ) + { + if( (*all_cells)[i]->phenotype.death.dead == true && (*all_cells)[i]->phenotype.death.current_death_model_index == 1 ) + { out += 1.0; } + } + + return out; +} + +using namespace std; + +vector vector_alives; + +bool auto_stop_resistance(int alive_cells, int resistant_cells) { + // Define stable states and nodes as vectors instead of unordered_sets + + vector_alives.push_back(alive_cells); + std::cout << "Steps: " << vector_alives.size() << std::endl; + + double threshold = 0.8; + double percentage_of_resistant = static_cast(resistant_cells) / alive_cells; + std::cout << "Number of resistant: " << resistant_cells << std::endl; + + bool stop; + bool condition = false; + if (vector_alives.size() >= 4){ + condition = percentage_of_resistant >= threshold; + } + + if (condition) { + stop = true; + } else { + stop = false; + } + return stop; +} + +bool auto_stop_alive(int alive_cells) { + //concatenate the number of alive cells to the vector + vector_alives.push_back(alive_cells); + std::cout << "Steps: " << vector_alives.size() << std::endl; + + bool condition = false; + // check the number of elements inside the vector to decide if process it and compute the derivative + if (vector_alives.size() >= 8) { + std::vector derivative; + + // compute the derivative only for the last three steps + for (size_t i = vector_alives.size() - 4; i < vector_alives.size(); ++i) { + double slope = vector_alives[i] - vector_alives[i - 1]; + derivative.push_back(slope); + } + + condition = true; + for (double slope : derivative) { + // if the slope is less than or equal to zero, set condition to false + if (slope < 0) { + condition = false; + break; + } + } + + } else { + condition = false; + } + + bool stop; + + if (condition) { + stop = true; + } else { + stop = false; + } + return stop; +} + +int save_resistant_cells(ofstream& file_resistant){ + //count the number of resistant cells for the plots + vector> stable_states = { + {"TNF", "TNFR", "RIP1", "RIP1ub", "RIP1K", "IKK", "NFkB", "BCL2", "ATP", "cIAP", "XIAP", "cFLIP", "Survival"}, + {"FASL", "TNF", "TNFR", "RIP1", "RIP1ub", "RIP1K", "IKK", "NFkB", "BCL2", "ATP", "cIAP", "XIAP", "cFLIP", "Survival"}, + {"TNF", "TNFR", "DISC-TNF", "FADD", "RIP1", "RIP1ub", "RIP1K", "IKK", "NFkB", "BCL2", "ATP", "cIAP", "XIAP", "cFLIP", "Survival"}, + {"FASL", "DISC-FAS", "FADD", "RIP1", "RIP1ub", "RIP1K", "IKK", "NFkB", "BCL2", "ATP", "cIAP", "XIAP", "cFLIP", "Survival"}, + {"FASL", "TNF", "TNFR", "DISC-TNF", "DISC-TNF", "FADD", "RIP1", "RIP1ub", "RIP1K", "IKK", "NFkB", "BCL2", "ATP", "cIAP", "XIAP", "cFLIP", "Survival"} + }; + + // Read the bool_data.txt file + ifstream file("start_and_stop_saving_files/bool_data.txt"); + if (!file.is_open()) { + cerr << "Error opening file." << endl; + exit(1); + } + + string line; + int counter_stable = 0; + while (getline(file, line)) { + istringstream iss(line); + string node; + vector nodes; // Define nodes as a vector + while (iss >> node) { + size_t pos = node.find('='); + if (pos != string::npos) { + string key = node.substr(0, pos); + string value = node.substr(pos + 1); + if (value == "1") { + nodes.push_back(key); // Push key to nodes vector + } + } + } + + sort(nodes.begin(), nodes.end()); // Sort nodes vector + + // Loop through stable_states vectors + for (auto& state : stable_states) { + sort(state.begin(), state.end()); // Sort each stable state vector + if (includes(nodes.begin(), nodes.end(), state.begin(), state.end())) { + counter_stable++; + break; + } + } + } + // save the number of resistant cells on a file + + file_resistant << counter_stable << endl; + + + return counter_stable; +} + +bool auto_stop() { + + bool condition = false; + bool stop; + // impèlement here your condition to stop the simulation + + if (condition) { + stop = true; + } else { + stop = false; + } + return stop; +} diff --git a/custom_modules/custom.h b/custom_modules/custom.h new file mode 100644 index 000000000..f13008543 --- /dev/null +++ b/custom_modules/custom.h @@ -0,0 +1,126 @@ +/* +############################################################################### +# If you use PhysiCell in your project, please cite PhysiCell and the version # +# number, such as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1]. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# See VERSION.txt or call get_PhysiCell_version() to get the current version # +# x.y.z. Call display_citations() to get detailed information on all cite-# +# able software used in your PhysiCell application. # +# # +# Because PhysiCell extensively uses BioFVM, we suggest you also cite BioFVM # +# as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1], # +# with BioFVM [2] to solve the transport equations. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# [2] A Ghaffarizadeh, SH Friedman, and P Macklin, BioFVM: an efficient para- # +# llelized diffusive transport solver for 3-D biological simulations, # +# Bioinformatics 32(8): 1256-8, 2016. DOI: 10.1093/bioinformatics/btv730 # +# # +############################################################################### +# # +# BSD 3-Clause License (see https://opensource.org/licenses/BSD-3-Clause) # +# # +# Copyright (c) 2015-2018, Paul Macklin and the PhysiCell Project # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are met: # +# # +# 1. Redistributions of source code must retain the above copyright notice, # +# this list of conditions and the following disclaimer. # +# # +# 2. Redistributions in binary form must reproduce the above copyright # +# notice, this list of conditions and the following disclaimer in the # +# documentation and/or other materials provided with the distribution. # +# # +# 3. Neither the name of the copyright holder nor the names of its # +# contributors may be used to endorse or promote products derived from this # +# software without specific prior written permission. # +# # +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # +# POSSIBILITY OF SUCH DAMAGE. # +# # +############################################################################### +*/ + +#include + +#include "../core/PhysiCell.h" +#include "../modules/PhysiCell_standard_modules.h" + +#include "./tnf_receptor_dynamics.h" +#include "./tnf_boolean_model_interface.h" +#include "../addons/start_and_stop/start_and_stop.h" + +using namespace BioFVM; +using namespace PhysiCell; + +// setup functions to help us along +void create_cell_types( void ); +void setup_tissue( void ); +void setup_tissue_input(void); + +// set up the BioFVM microenvironment +void setup_microenvironment( void ); + +// helper function to read init files +std::vector> read_cells_positions(std::string filename, char delimiter, bool header); + +// helper function to create a sphere of cells of a given radius +std::vector> create_cell_sphere_positions(double cell_radius, double sphere_radius); + +// helper function to create a disc of cells of a given radius +std::vector> create_cell_disc_positions(double cell_radius, double disc_radius); + +// helper function that calculates phere volume +inline float sphere_volume_from_radius(float radius) {return 4/3 * PhysiCell_constants::pi * std::pow(radius, 3);} + +// helper function to inject density surrounding a spheroid +void inject_density_sphere(int density_index, double concentration, double membrane_lenght); + +// helper function to remove a density +void remove_density( int density_index ); + +// custom pathology coloring function +std::vector my_coloring_function( Cell* ); + +double total_live_cell_count(); + +// count the number of total dead cells at current time step +double total_dead_cell_count(); + +// count the number of necrotic cells at current time step +double total_necrosis_cell_count(); + +// function to auto stop the simulation +bool auto_stop_resistance(int alive_cells, int resistant_cells); +bool auto_stop_alive(int alive_cells); +int save_resistant_cells(std::ofstream& file_resistant); +void update_variables_monitor(); +bool auto_stop(); + + + + diff --git a/custom_modules/submodel_data_structures.cpp b/custom_modules/submodel_data_structures.cpp new file mode 100644 index 000000000..22630e3f8 --- /dev/null +++ b/custom_modules/submodel_data_structures.cpp @@ -0,0 +1,114 @@ +/* + * submodel_data_structures.cpp + * + * Created on: ? + * Author: Paul Macklin + * + * Description: + * Auxiliary class to manage submodels + * + * Source: https://github.com/pc4covid19/COVID19/blob/master/PhysiCell/custom_modules/submodel_data_structures.cpp +*/ + +#include "./submodel_data_structures.h" + +using namespace PhysiCell; + +Submodel_Registry submodel_registry; + +Submodel_Information::Submodel_Information( void ) +{ + name = "none"; + version = "-1"; + main_function = NULL; + + microenvironment_variables.resize(0); + cell_variables.resize(0); // custom data + + return; +} + +void Submodel_Information::register_model( void ) +{ + // make sure the cell defaults "know" about each custom variable + // Make sure it's there, or add if it's not. + + for( int n = 0 ; n < cell_variables.size() ; n++ ) + { + // let's do this a bit manually (and inefficiently), but safely. + bool found_it = false; + for( unsigned int i=0; i < cell_defaults.custom_data.variables.size() ; i++ ) + { + if( cell_defaults.custom_data.variables[i].name == cell_variables[n] ) + { found_it = true; } + } + if( found_it == false ) + { + cell_defaults.custom_data.add_variable( cell_variables[n] , "none", 0.0 ); + } + + } + + // add the model to the registry of submodels + + submodel_registry.register_model( *this ); +} + +void Submodel_Information::display( std::ostream& os ) +{ + os << "Submodel: " << name << " (Version " << version << ")" << std::endl ; + + os << "\tcell variables: " << std::endl; + for( int n = 0 ; n < cell_variables.size(); n++ ) + { + os << "\t\t" << cell_variables[n] << std::endl; + } + + os << "\tfunction: " ; + if( main_function ) + { os << (long long int) main_function; } + else + { os << "NULL"; } + os << std::endl; + + return; +} + +void Submodel_Registry::register_model( Submodel_Information& model ) +{ + #pragma omp critical + { + // already registered? + bool found = false; + for( int n = 0; n < submodels.size() ; n++ ) + { + if( submodels[n] == &model ) + { found = true; } + } + + if( found == false ) + { + submodels.push_back( &model ); +// add_software_citation(); +// void add_software_citation( std::string name , std::string version, std::string DOI , std::string URL ) + } + } + + return; +} + +void Submodel_Registry::display( std::ostream& os ) +{ + os << "The following submodels are registered: " << std::endl; + os << "=======================================" << std::endl; + for( int n = 0 ; n < submodels.size(); n++ ) + { + submodels[n]->display( os ); + } + os << std::endl; + + return; +} + + + diff --git a/custom_modules/submodel_data_structures.h b/custom_modules/submodel_data_structures.h new file mode 100644 index 000000000..f69e34102 --- /dev/null +++ b/custom_modules/submodel_data_structures.h @@ -0,0 +1,53 @@ +/* + * submodel_data_structures.h + * + * Created on: ? + * Author: Paul Macklin + * + * Description: + * Auxiliary class to manage submodels + * + * Source: https://github.com/pc4covid19/COVID19/blob/master/PhysiCell/custom_modules/submodel_data_structures.cpp +*/ + + +#include "../core/PhysiCell.h" +#include "../modules/PhysiCell_standard_modules.h" + +using namespace BioFVM; +using namespace PhysiCell; + +#ifndef __submodel_data__ +#define __submodel_data__ + +class Submodel_Information +{ + private: + public: + std::string name; + std::string version; + void(*main_function)(Cell*,Phenotype&,double); + + std::vector< std::string > microenvironment_variables; + std::vector< std::string > cell_variables; // custom data + + Submodel_Information( void ); + + void register_model( void ); + + void display( std::ostream& os ); +}; + +class Submodel_Registry +{ + private: + std::vector submodels; + public: + void register_model( Submodel_Information& model ); + void display( std::ostream& os ); + +}; + +extern Submodel_Registry submodel_registry; + +#endif \ No newline at end of file diff --git a/custom_modules/tnf_boolean_model_interface.cpp b/custom_modules/tnf_boolean_model_interface.cpp new file mode 100644 index 000000000..2a4f4abaa --- /dev/null +++ b/custom_modules/tnf_boolean_model_interface.cpp @@ -0,0 +1,189 @@ +/* + * tnf_boolean_model_interface.cpp + * + * Created on: 15 jun. 2020 + * Author: Miguel Ponce-de-Leon (miguel.ponce@bsc.es) + * Contributor: Gerard Pradas + * Contributor: Arnau Montagud + * Contributor: Thalia Diniaco + * Cite as: arXiv:2103.14132 [q-bio.QM] + * Description: + * Submodel that work as an interface + * between the Boolean Network (BN) and PhysiCell (PC). + * The submodel run the following steps: + * 1- updates BN input nodes based on custom cell variables (see receptor model) + * 2- updates the BN intracellular model by running MaBoSS + * 3- updates cell state/behaviour based on the state of the BN readout nodes + * + * The update_monitor_variables funtion is just used to keep track of some relevand + * BN nodes' values that are stored as custom variables + */ + + +#include "./tnf_boolean_model_interface.h" + +using namespace PhysiCell; + +Submodel_Information tnf_bm_interface_info; + +void tnf_boolean_model_interface_setup() +{ + tnf_bm_interface_info.name = "TNF Boolean model interface"; + tnf_bm_interface_info.version = "0.2.0"; + + // tnf_bm_interface_info.main_function= update_phenotype_with_signaling; + + // These are just auxiliary variables to keep track of some BN nodes + tnf_bm_interface_info.cell_variables.push_back( "tnf_node" ); + tnf_bm_interface_info.cell_variables.push_back( "fadd_node" ); + tnf_bm_interface_info.cell_variables.push_back( "nfkb_node" ); + + tnf_bm_interface_info.register_model(); +} + +void update_boolean_model_inputs( Cell* pCell, Phenotype& phenotype, double dt ) +{ + static int nR_EB = pCell->custom_data.find_variable_index( "bound_external_TNFR" ); + static int nTNF_threshold = pCell->custom_data.find_variable_index( "TNFR_activation_threshold" ); + + // This if the step transfer function used to update the state of boolean model inputs + // using the state of the receptor dynamics model. The continuos value thresholded is + // the total TNF-recptor complex (doi:10.1016/j.cellsig.2010.08.016) + + if ( pCell->custom_data[nR_EB] >= pCell->custom_data[nTNF_threshold] ){ + + pCell->phenotype.intracellular->set_boolean_variable_value("TNF", 1);} + else + pCell->phenotype.intracellular->set_boolean_variable_value("TNF", 0); + + return; +} + + +/** +void update_cell_from_boolean_model(Cell* pCell, Phenotype& phenotype, double dt) +{ + static int nTNF_external = microenvironment.find_density_index( "tnf" ); + static int nTNF_export_rate = pCell->custom_data.find_variable_index( "TNF_net_production_rate" ); + + static int apoptosis_model_index = phenotype.death.find_death_model_index( "Apoptosis" ); + static int necrosis_model_index = phenotype.death.find_death_model_index( "Necrosis" ); + + // Getting the state of the boolean model readouts (Readout can be in the XML) + bool apoptosis = pCell->phenotype.intracellular->get_boolean_variable_value( "Apoptosis" ); + bool nonACD = pCell->phenotype.intracellular->get_boolean_variable_value( "NonACD" ); + bool survival = pCell->phenotype.intracellular->get_boolean_variable_value( "Survival" ); + bool NFkB = pCell->phenotype.intracellular->get_boolean_variable_value( "NFkB" ); + + if ( apoptosis ) { + pCell->start_death(apoptosis_model_index); + return; + } + + if ( nonACD ) { + pCell->start_death(necrosis_model_index); + return; + } + + if ( survival && pCell->phenotype.cycle.current_phase_index() == PhysiCell_constants::Ki67_negative ) { + pCell->phenotype.cycle.advance_cycle(pCell, phenotype, dt); + } + + // If NFkB node is active produce some TNF + if ( NFkB ) { + double tnf_export_rate = pCell->custom_data[nTNF_export_rate]; + phenotype.secretion.net_export_rates[nTNF_external] = tnf_export_rate; + } else { + phenotype.secretion.net_export_rates[nTNF_external] = 0; + } + + return; +} +*/ + + + +void update_cell_from_boolean_model(Cell* pCell, Phenotype& phenotype, double dt) +{ + + + static int necrosis_index = phenotype.death.find_death_model_index( PhysiCell_constants::necrosis_death_model ); + static int apoptosis_index = phenotype.death.find_death_model_index( PhysiCell_constants::apoptosis_death_model ); + static int cycle_start_index = live.find_phase_index( PhysiCell_constants::live ); + static int cycle_end_index = live.find_phase_index( PhysiCell_constants::live ); + + static int nTNF_external = microenvironment.find_density_index( "tnf" ); + static int nTNF_export_rate = pCell->custom_data.find_variable_index( "TNF_net_production_rate" ); + static int death_decay_idx = pCell->custom_data.find_variable_index( "death_commitment_decay" ); + + + static float necrosis_rate = pCell->custom_data["necrosis_rate"]; + static float apoptosis_rate = pCell->custom_data["apoptosis_rate"]; + static float death_commitment_decay = pCell->custom_data["death_decay_idx"]; + + // Getting the state of the boolean model readouts (Readout can be in the XML) + bool apoptosis = pCell->phenotype.intracellular->get_boolean_variable_value( "Apoptosis" ); + bool nonACD = pCell->phenotype.intracellular->get_boolean_variable_value( "NonACD" ); + bool survival =pCell->phenotype.intracellular->get_boolean_variable_value( "Survival" ); + bool NFkB = pCell->phenotype.intracellular->get_boolean_variable_value( "NFkB" ); + + + if ( apoptosis ) { + // pCell->start_death(apoptosis_index); + phenotype.death.rates[apoptosis_index] = apoptosis_rate; + } else { + phenotype.death.rates[apoptosis_index] -= apoptosis_rate * death_commitment_decay; + if (phenotype.death.rates[apoptosis_index] < 0) + phenotype.death.rates[apoptosis_index] = 0; + } + + if ( nonACD ) { + //myCounter++; + // pCell->start_death(necrosis_index); + phenotype.death.rates[necrosis_index] = necrosis_rate; + } + else { + phenotype.death.rates[necrosis_index] -= necrosis_rate * death_commitment_decay; + if (phenotype.death.rates[necrosis_index] < 0) + phenotype.death.rates[necrosis_index] = 0; + } + + if ( survival && pCell->phenotype.cycle.current_phase_index() == PhysiCell_constants::Ki67_negative ) + { + pCell->phenotype.cycle.advance_cycle(pCell, phenotype, dt); + } + + // If NFkB node is active produce some TNF + if ( NFkB ) + { + phenotype.secretion.net_export_rates[nTNF_external] = pCell->custom_data[nTNF_export_rate]; + } else + { + phenotype.secretion.net_export_rates[nTNF_external] = 0; + } + // update_cell_and_death_parameters_O2_based(pCell, phenotype, dt); + return; +} + + +void update_behaviors(Cell* pCell, Phenotype& phenotype, double dt) +{ + // update the cell fate based on the boolean outputs + update_cell_from_boolean_model(pCell, phenotype, dt); + + // Get track of some boolean node values for debugging + update_monitor_variables(pCell); +} + +void update_monitor_variables(Cell* pCell ) +{ + static int index_tnf_node = pCell->custom_data.find_variable_index("tnf_node"); + static int index_fadd_node = pCell->custom_data.find_variable_index("fadd_node"); + static int index_nfkb_node = pCell->custom_data.find_variable_index("nfkb_node"); + + pCell->custom_data[index_tnf_node] = pCell->phenotype.intracellular->get_boolean_variable_value("TNF"); + pCell->custom_data[index_fadd_node] = pCell->phenotype.intracellular->get_boolean_variable_value("FADD"); + pCell->custom_data[index_nfkb_node] = pCell->phenotype.intracellular->get_boolean_variable_value( "NFkB" ); + + return; +} diff --git a/custom_modules/tnf_boolean_model_interface.h b/custom_modules/tnf_boolean_model_interface.h new file mode 100644 index 000000000..9f1432b32 --- /dev/null +++ b/custom_modules/tnf_boolean_model_interface.h @@ -0,0 +1,42 @@ +/* + * tnf_boolean_model_interface.cpp + * + * Created on: 15 jun. 2020 + * Author: Miguel Ponce-de-Leon (miguel.ponce@bsc.es) + * Contributor: Gerard Pradas + * Contributor: Arnau Montagud + * Contributor: Thalia Diniaco + * Cite as: arXiv:2103.14132 [q-bio.QM] + * Description: + * Submodel that work as an interface + * between the Boolean Network (BN) and PhysiCell (PC). + * The submodel run the following steps: + * 1- updates BN input nodes based on custom cell variables (see receptor model) + * 2- updates the BN intracellular model by running MaBoSS + * 3- updates cell state/behaviour based on the state of the BN readout nodes + * + * The update_monitor_variables funtion is just used to keep track of some relevand + * BN nodes' values that are stored as custom variables + */ + +#include "../core/PhysiCell.h" +#include "../modules/PhysiCell_standard_modules.h" +#include "../addons/PhysiBoSS/src/maboss_intracellular.h" + +using namespace BioFVM; +using namespace PhysiCell; + +#include "./submodel_data_structures.h" + +void tnf_boolean_model_interface_setup(); + +void update_boolean_model_inputs( Cell* pCell, Phenotype& phenotype, double dt ); + +void update_behaviors(Cell* pCell, Phenotype& phenotype, double dt); + +void update_cell_from_boolean_model(Cell* pCell, Phenotype& phenotype, double dt); + +// helper function to keep updated some cell custom variables +void update_monitor_variables( Cell* pCell ); + +extern int myCounter; diff --git a/custom_modules/tnf_receptor_dynamics.cpp b/custom_modules/tnf_receptor_dynamics.cpp new file mode 100644 index 000000000..438095bbb --- /dev/null +++ b/custom_modules/tnf_receptor_dynamics.cpp @@ -0,0 +1,143 @@ +/* + * tnf_receptor_dynamics.cpp + * + * Created on: 15 jun. 2020 + * Author: Miguel Ponce-de-Leon (miguel.ponce@bsc.es) + * Contributor: Gerard Pradas + * Contributor: Arnau Montagud + * Contributor: Thalia Diniaco + * Cite as: arXiv:2103.14132 [q-bio.QM] + * Description: + * Simplified model of the TNF receptor (TNFR) dynamics. The models has threed states: + * 1- TNFR unbounded (exposed to the extracellular space) + * 2- TNFR with a TNF bounded + * 3- TNFR with a TNF bounded internalized to be recycled by removeing the TNF ligand. + * + * It is an ODE-based model that has the following equations + * d[unbound_external_TNFR]/dt = TNFR_recycling_rate * [bound_internal_TNFR] - TNFR_binding_rate * [unbound_external_TNFR] * [TNF] + * d[bound_external_TNFR]/dt = NFR_binding_rate * [unbound_external_TNFR] * [TNF] - TNFR_endocytosis_rate * [bound_external_TNFR] + * d[bound_internal_TNFR]/dt = TNFR_endocytosis_rate * [bound_external_TNFR] - TNFR_recycling_rate * [bound_internal_TNFR] + */ + +#include "./tnf_receptor_dynamics.h" + +using namespace PhysiCell; + +Submodel_Information tnf_receptor_info; + +void tnf_receptor_model_setup() +{ + tnf_receptor_info.name = "TNF trasnporter model"; + tnf_receptor_info.version = "0.1.0"; + + tnf_receptor_info.main_function = tnf_receptor_model; + + // what custom data do I need? + tnf_receptor_info.cell_variables.push_back( "TNFR_activation_threshold" ); + + tnf_receptor_info.cell_variables.push_back( "unbound_external_TNFR" ); + tnf_receptor_info.cell_variables.push_back( "bound_external_TNFR" ); + tnf_receptor_info.cell_variables.push_back( "bound_internal_TNFR" ); + + tnf_receptor_info.cell_variables.push_back( "TNFR_binding_rate" ); + tnf_receptor_info.cell_variables.push_back( "TNFR_endocytosis_rate" ); + tnf_receptor_info.cell_variables.push_back( "TNFR_recycling_rate" ); + tnf_receptor_info.cell_variables.push_back( "TNF_net_production_rate" ); + + tnf_receptor_info.register_model(); + + return; +} + +void tnf_receptor_model( Cell* pCell, Phenotype& phenotype, double dt ) +{ + static int nTNF_external = microenvironment.find_density_index( "tnf" ); + + static int nR_EU = pCell->custom_data.find_variable_index( "unbound_external_TNFR" ); + static int nR_EB = pCell->custom_data.find_variable_index( "bound_external_TNFR" ); + static int nR_IB = pCell->custom_data.find_variable_index( "bound_internal_TNFR" ); + + static int nR_bind = pCell->custom_data.find_variable_index( "TNFR_binding_rate" ); + static double R_binding_rate = pCell->custom_data[nR_bind]; + + static int nR_endo = pCell->custom_data.find_variable_index( "TNFR_endocytosis_rate" ); + static double R_endo_rate = pCell->custom_data[nR_endo]; + + static int nR_recycle = pCell->custom_data.find_variable_index( "TNFR_recycling_rate" ); + static double R_recyc_rate = pCell->custom_data[nR_recycle]; + + + if( phenotype.death.dead == true ) + { return; } + + // internalized TNF tells us how many have recently bound to receptors + // TNF is internalized at: + // phenotype.secretion.uptake_rates[nTNF_external] = + // pCell->custom_data[nR_bind] * pCell->custom_data[nR_EU]; + + // The internalization is only used to track the TNF + // The following part of the code takes care of correcly managed + double dR_EB = phenotype.molecular.internalized_total_substrates[nTNF_external]; + //std::cout << "nTNF_external: " << nTNF_external << std::endl; + //std::cout << "dR_EB: " << dR_EB << std::endl; + + // if it tries to bind more TNF than there are receptors, compensate + if( dR_EB > pCell->custom_data[nR_EU] ) + { + double excess_binding = dR_EB - pCell->custom_data[nR_EU]; + dR_EB = pCell->custom_data[nR_EU]; + // dump any excess back into the microenvironment + static double to_density = 1.0 / microenvironment.mesh.dV; + // this needs omp critical because 2 cells writing to 1 voxel is not thread safe + #pragma omp critical + { pCell->nearest_density_vector()[nTNF_external] += excess_binding * to_density; } + } + + // Remove all the internalized TNF from cell + phenotype.molecular.internalized_total_substrates[nTNF_external] = 0.0; + + // Endocytosis + // The bounded receptor is internalized at a rate R_endo_rate + double dR_IB = dt * R_endo_rate * pCell->custom_data[nR_EB]; + if( dR_IB > pCell->custom_data[nR_EB] ) + { dR_IB = pCell->custom_data[nR_EB]; } + + // Recylcing + // The internalized bounded TNFR release the TNF + // The TNF is instantaneously degraded by the cell + // The TNF receptor is recycled as an unbounded external receptor + double dR_EU = dt * R_recyc_rate * pCell->custom_data[nR_IB]; + if( dR_EU > pCell->custom_data[nR_IB] ) + { dR_EU = pCell->custom_data[nR_IB]; } + + pCell->custom_data[nR_EU] -= dR_EB; // remove newly bound receptor from R_EU + pCell->custom_data[nR_EB] += dR_EB; // add newly bound receptor to R_EB + + pCell->custom_data[nR_EB] -= dR_IB; // move from external bound + pCell->custom_data[nR_IB] += dR_IB; // move to internal bound + + pCell->custom_data[nR_IB] -= dR_EU; // move from internal unbound + pCell->custom_data[nR_EU] += dR_EU; // move to external unbound + + // update the TNF uptake rate + //std::cout << "uptake_pre: " << phenotype.secretion.uptake_rates[nTNF_external] << std::endl; + phenotype.secretion.uptake_rates[nTNF_external] = R_binding_rate * pCell->custom_data[nR_EU]; + //std::cout << "uptake_post: " << phenotype.secretion.uptake_rates[nTNF_external] << std::endl; + + return; +} + +void tnf_receptor_model_main( double dt ) +{ + #pragma omp parallel for + for( int i=0; i < (*all_cells).size() ; i++ ) + { + Cell* pC = (*all_cells)[i]; + if ( pC->is_out_of_domain ) + { continue; } + if( pC->phenotype.death.dead ) + { continue; } + tnf_receptor_model( pC, pC->phenotype , dt ); + } + return; +} \ No newline at end of file diff --git a/custom_modules/tnf_receptor_dynamics.h b/custom_modules/tnf_receptor_dynamics.h new file mode 100644 index 000000000..962ff19bc --- /dev/null +++ b/custom_modules/tnf_receptor_dynamics.h @@ -0,0 +1,39 @@ +/* + * tnf_receptor_dynamics.cpp + * + * Created on: 15 jun. 2020 + * Author: Miguel Ponce-de-Leon + * Contributor: Thalia Diniaco + * Created on: 15 jun. 2020 + * Author: Miguel Ponce-de-Leon (miguel.ponce@bsc.es) + * Contributor: Gerard Pradas + * Contributor: Arnau Montagud + * Contributor: Thalia Diniaco + * Cite as: arXiv:2103.14132 [q-bio.QM] + * Description: + * SSimplified model of the TNF receptor (TNFR) dynamics. The models has threed states: + * 1- TNFR unbounded (exposed to the extracellular space) + * 2- TNFR with a TNF bounded + * 3- TNFR with a TNF bounded internalized to be recycled by removeing the TNF ligand. + * + * It is an ODE-based model that has the following equations + * d[unbound_external_TNFR]/dt = TNFR_recycling_rate * [bound_internal_TNFR] - TNFR_binding_rate * [unbound_external_TNFR] * [TNF] + * d[bound_external_TNFR]/dt = NFR_binding_rate * [unbound_external_TNFR] * [TNF] - TNFR_endocytosis_rate * [bound_external_TNFR] + * d[bound_internal_TNFR]/dt = TNFR_endocytosis_rate * [bound_external_TNFR] - TNFR_recycling_rate * [bound_internal_TNFR] + * + * Cite as: arXiv:2103.14132 [q-bio.QM] + */ + +#include "../core/PhysiCell.h" +#include "../modules/PhysiCell_standard_modules.h" + +using namespace BioFVM; +using namespace PhysiCell; + +#include "./submodel_data_structures.h" + +void tnf_receptor_model_setup(); + +void tnf_receptor_model( Cell* pCell, Phenotype& phenotype, double dt ); + +void tnf_receptor_model_main( double dt ); diff --git a/output/empty.txt b/main-backup.cpp similarity index 100% rename from output/empty.txt rename to main-backup.cpp diff --git a/main.cpp b/main.cpp new file mode 100644 index 000000000..29f2d6d7a --- /dev/null +++ b/main.cpp @@ -0,0 +1,393 @@ +/* +############################################################################### +# If you use PhysiCell in your project, please cite PhysiCell and the version # +# number, such as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1]. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# See VERSION.txt or call get_PhysiCell_version() to get the current version # +# x.y.z. Call display_citations() to get detailed information on all cite-# +# able software used in your PhysiCell application. # +# # +# Because PhysiCell extensively uses BioFVM, we suggest you also cite BioFVM # +# as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1], # +# with BioFVM [2] to solve the transport equations. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# [2] A Ghaffarizadeh, SH Friedman, and P Macklin, BioFVM: an efficient para- # +# llelized diffusive transport solver for 3-D biological simulations, # +# Bioinformatics 32(8): 1256-8, 2016. DOI: 10.1093/bioinformatics/btv730 # +# # +############################################################################### +# # +# BSD 3-Clause License (see https://opensource.org/licenses/BSD-3-Clause) # +# # +# Copyright (c) 2015-2018, Paul Macklin and the PhysiCell Project # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are met: # +# # +# 1. Redistributions of source code must retain the above copyright notice, # +# this list of conditions and the following disclaimer. # +# # +# 2. Redistributions in binary form must reproduce the above copyright # +# notice, this list of conditions and the following disclaimer in the # +# documentation and/or other materials provided with the distribution. # +# # +# 3. Neither the name of the copyright holder nor the names of its # +# contributors may be used to endorse or promote products derived from this # +# software without specific prior written permission. # +# # +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # +# POSSIBILITY OF SUCH DAMAGE. # +# # +############################################################################### +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "./core/PhysiCell.h" +#include "./core/PhysiCell_utilities.h" +#include "./modules/PhysiCell_standard_modules.h" +#include "./addons/PhysiBoSS/src/maboss_intracellular.h" +#include "./custom_modules/custom.h" + +using namespace BioFVM; +using namespace PhysiCell; + +int main( int argc, char* argv[] ) +{ + // load and parse settings file(s) + std::ofstream file_resistant("output/resistant_cells.txt", std::ios::app); + + bool XML_status = false; + char copy_command [1024]; + if( argc > 1 ) + { + XML_status = load_PhysiCell_config_file( argv[1] ); + sprintf( copy_command , "cp %s %s" , argv[1] , PhysiCell_settings.folder.c_str() ); + } + else + { + XML_status = load_PhysiCell_config_file( "./config/PhysiCell_settings.xml" ); + sprintf( copy_command , "cp ./config/PhysiCell_settings.xml %s" , PhysiCell_settings.folder.c_str() ); + } + if( !XML_status ) + { exit(-1); } + + // copy config file to output directry + system( copy_command ); + + // OpenMP setup + omp_set_num_threads(PhysiCell_settings.omp_num_threads); + + // PNRG setup + SeedRandom(); // or specify a seed here + + // time setup + std::string time_units = "min"; + + /* Microenvironment setup */ + + setup_microenvironment(); // modify this in the custom code + + bool start_stop = parameters.bools("start_stop"); + if( start_stop ){ + + // reset microenvironment and cells as they were in the previous simulation + reset_microenv(); + } + + + // User parameters + + double tnf_pulse_period = parameters.doubles("tnf_pulse_period"); + double tnf_pulse_duration = parameters.doubles("tnf_pulse_duration"); + double tnf_pulse_concentration = parameters.doubles("tnf_pulse_concentration"); + double time_remove_tnf = parameters.doubles("time_remove_tnf"); + double membrane_lenght = parameters.doubles("membrane_length"); // radious around which the tnf pulse is injected + + + double tnf_pulse_timer = tnf_pulse_period; + double tnf_pulse_injection_timer = tnf_pulse_duration; // tnf_pulse_duration; // -1; + static int tnf_idx = microenvironment.find_density_index("tnf"); + + + /* PhysiCell setup */ + + // set mechanics voxel size, and match the data structure to BioFVM + double mechanics_voxel_size = 30; + Cell_Container* cell_container = create_cell_container_for_microenvironment( microenvironment, mechanics_voxel_size ); + + /* Users typically start modifying here. START USERMODS */ + create_cell_types(); + + + if( start_stop ){ + + + parameters.bools("read_init") = true; + + // reset cells as they were in the previous simulation + setup_tissue(); + + reset_cell(cell_container->last_cell_cycle_time); + + //exit(-1); + + + reset_global_parameters(cell_container); + + update_variables_monitor(); + + + } else{ + setup_tissue(); //death model index = 1 == necrotic...= 0 == apoptotic. + } + + + // check if we want to start injecting tnf + if(parameters.bools("if_start_inj")){ + + tnf_pulse_timer = PhysiCell_globals.current_time; + + }else{ + + tnf_pulse_timer = PhysiCell_globals.current_time + tnf_pulse_period; + } + + + // set MultiCellDS save options + + set_save_biofvm_mesh_as_matlab( true ); + set_save_biofvm_data_as_matlab( true ); + set_save_biofvm_cell_data( true ); + set_save_biofvm_cell_data_as_custom_matlab( true ); + + // save a simulation snapshot + + char filename[1024]; + sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); + + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); + + sprintf( filename , "%s/states_initial.csv", PhysiCell_settings.folder.c_str()); + MaBoSSIntracellular::save(filename); + + // save a quick SVG cross section through z = 0, after setting its + // length bar to 200 microns + + PhysiCell_SVG_options.length_bar = 200; + + // for simplicity, set a pathology coloring function + + std::vector (*cell_coloring_function)(Cell*) = my_coloring_function; + + sprintf( filename , "%s/initial.svg" , PhysiCell_settings.folder.c_str() ); + SVG_plot( filename , microenvironment, 0.0 , PhysiCell_globals.current_time, cell_coloring_function ); + + sprintf( filename , "%s/legend.svg" , PhysiCell_settings.folder.c_str() ); + create_plot_legend( filename , cell_coloring_function ); + + add_software_citation( "PhysiBoSS" , PhysiBoSS_Version , PhysiBoSS_DOI, PhysiBoSS_URL); + + display_citations(); + + // set the performance timers + BioFVM::RUNTIME_TIC(); + BioFVM::TIC(); + + std::ofstream report_file; + if( PhysiCell_settings.enable_legacy_saves == true ) + { + sprintf( filename , "%s/simulation_report.txt" , PhysiCell_settings.folder.c_str() ); + + report_file.open(filename); // create the data log file + report_file<<"simulated time\tnum cells\tnum division\tnum death\twall time"<= tnf_pulse_timer ) + { + tnf_pulse_injection_timer = PhysiCell_globals.current_time + tnf_pulse_duration; + tnf_pulse_timer += tnf_pulse_period; + } + + if ( PhysiCell_globals.current_time <= tnf_pulse_injection_timer ) + { + + inject_density_sphere(tnf_idx, tnf_pulse_concentration, membrane_lenght); + + } + + if ( PhysiCell_globals.current_time >= time_remove_tnf ) + { + + remove_density(tnf_idx); + time_remove_tnf += PhysiCell_settings.max_time; + } + + + + // update the microenvironment + microenvironment.simulate_diffusion_decay( diffusion_dt ); + + // update te TNF receptor model of each cell + tnf_receptor_model_main( diffusion_dt ); + + // run PhysiCell + ((Cell_Container *)microenvironment.agent_container)->update_all_cells( PhysiCell_globals.current_time ); + + PhysiCell_globals.current_time += diffusion_dt; + } + + if( PhysiCell_settings.enable_legacy_saves == true ) + { + log_output(PhysiCell_globals.current_time, PhysiCell_globals.full_output_index, microenvironment, report_file); + report_file.close(); + } + } + catch( const std::exception& e ) + { // reference to the base of a polymorphic object + std::cout << e.what(); // information from length_error printed + } + + // save a final simulation snapshot + + sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); + + sprintf( filename , "%s/states_final.csv", PhysiCell_settings.folder.c_str()); + MaBoSSIntracellular::save(filename); + + sprintf( filename , "%s/final.svg" , PhysiCell_settings.folder.c_str() ); + SVG_plot( filename , microenvironment, 0.0 , PhysiCell_globals.current_time, cell_coloring_function ); + + + // timer + + std::cout << std::endl << "Total simulation runtime: " << std::endl; + BioFVM::display_stopwatch_value( std::cout , BioFVM::runtime_stopwatch_value() ); + + file_resistant.close(); + + return 0; +} diff --git a/sample_projects/Makefile-default b/sample_projects/Makefile-default index 440b03cf0..2a6b2d82a 100644 --- a/sample_projects/Makefile-default +++ b/sample_projects/Makefile-default @@ -76,7 +76,7 @@ list-projects: @echo " worm-sample interaction-sample mechano-sample rules-sample physimess-sample custom-division-sample" @echo "" @echo "Sample intracellular projects: template_BM ode-energy-sample physiboss-cell-lines-sample" - @echo " cancer-metabolism-sample physiboss-tutorial physiboss-tutorial-invasion" + @echo " physiboss-tnf-model cancer-metabolism-sample physiboss-tutorial physiboss-tutorial-invasion" @echo "" template: @@ -226,6 +226,16 @@ physiboss-cell-lines-sample: cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml cp ./sample_projects_intracellular/boolean/physiboss_cell_lines/config/* ./config/ +physiboss-tnf-model: + cp ./sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/* ./custom_modules/ + touch main.cpp && cp main.cpp main-backup.cpp + cp ./sample_projects_intracellular/boolean/spheroid_tnf_model/main-spheroid_TNF.cpp ./main.cpp + cp Makefile Makefile-backup + cp ./sample_projects_intracellular/boolean/spheroid_tnf_model/Makefile . + cp ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml + cp ./sample_projects_intracellular/boolean/spheroid_tnf_model/config/* ./config/ + cp -r ./sample_projects_intracellular/boolean/spheroid_tnf_model/scripts ./ + physiboss-tutorial: cp ./sample_projects_intracellular/boolean/tutorial/custom_modules/* ./custom_modules/ touch main.cpp && cp main.cpp main-backup.cpp diff --git a/sample_projects/biorobots/Makefile b/sample_projects/biorobots/Makefile index 26314225c..4f149880b 100644 --- a/sample_projects/biorobots/Makefile +++ b/sample_projects/biorobots/Makefile @@ -62,8 +62,10 @@ PhysiCell_custom_module_OBJECTS := custom.o pugixml_OBJECTS := pugixml.o +start_and_stop_OBJECTS := start_and_stop.o + PhysiCell_OBJECTS := $(BioFVM_OBJECTS) $(pugixml_OBJECTS) $(PhysiCell_core_OBJECTS) $(PhysiCell_module_OBJECTS) -ALL_OBJECTS := $(PhysiCell_OBJECTS) $(PhysiCell_custom_module_OBJECTS) +ALL_OBJECTS := $(PhysiCell_OBJECTS) $(PhysiCell_custom_module_OBJECTS) $(start_and_stop_OBJECTS) # compile the project @@ -165,7 +167,11 @@ PhysiCell_basic_signaling.o: ./core/PhysiCell_basic_signaling.cpp PhysiCell_geometry.o: ./modules/PhysiCell_geometry.cpp $(COMPILE_COMMAND) -c ./modules/PhysiCell_geometry.cpp - + +# start_and_stop +start_and_stop.o: ./addons/start_and_stop/start_and_stop.cpp + $(COMPILE_COMMAND) $(INC) -c ./addons/start_and_stop/start_and_stop.cpp + # user-defined PhysiCell modules custom.o: ./custom_modules/custom.cpp diff --git a/sample_projects/biorobots/config/PhysiCell_settings.xml b/sample_projects/biorobots/config/PhysiCell_settings.xml index 2d5f7e46b..b07e98b55 100644 --- a/sample_projects/biorobots/config/PhysiCell_settings.xml +++ b/sample_projects/biorobots/config/PhysiCell_settings.xml @@ -551,6 +551,7 @@ + true 0 0 red diff --git a/sample_projects/biorobots/custom_modules/custom.h b/sample_projects/biorobots/custom_modules/custom.h index 13c67b857..294027d16 100644 --- a/sample_projects/biorobots/custom_modules/custom.h +++ b/sample_projects/biorobots/custom_modules/custom.h @@ -67,6 +67,8 @@ #include "../core/PhysiCell.h" #include "../modules/PhysiCell_standard_modules.h" +//include the start and stop add-on +#include "../addons/start_and_stop/start_and_stop.h" using namespace BioFVM; using namespace PhysiCell; diff --git a/sample_projects/biorobots/main.cpp b/sample_projects/biorobots/main.cpp index 214399ebb..83c146e0e 100644 --- a/sample_projects/biorobots/main.cpp +++ b/sample_projects/biorobots/main.cpp @@ -115,6 +115,15 @@ int main( int argc, char* argv[] ) setup_microenvironment(); // modify this in the custom code + bool start_stop = parameters.bools("start_stop"); + if( start_stop ){ + + // reset microenvironment and cells as they were in the previous simulation + reset_microenv(); + } + + + /* PhysiCell setup */ // set mechanics voxel size, and match the data structure to BioFVM @@ -125,7 +134,19 @@ int main( int argc, char* argv[] ) create_cell_types(); - setup_tissue(); + if( start_stop ){ + + // reset cells as they were in the previous simulation + setup_tissue(); + + reset_cell(cell_container->last_cell_cycle_time); + //exit(-1); + + reset_global_parameters(cell_container); + + } else{ + setup_tissue(); //death model index = 1 == necrotic...= 0 == apoptotic. + } /* Users typically stop modifying here. END USERMODS */ @@ -173,6 +194,9 @@ int main( int argc, char* argv[] ) report_file<<"simulated time\tnum cells\tnum division\tnum death\twall time"< + false 0 C diff --git a/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.h b/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.h index 44cd833d9..006c3b409 100644 --- a/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.h +++ b/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.h @@ -70,6 +70,8 @@ #include "../core/PhysiCell.h" #include "../modules/PhysiCell_standard_modules.h" +#include "../addons/start_and_stop/start_and_stop.h" + using namespace BioFVM; using namespace PhysiCell; diff --git a/sample_projects_intracellular/boolean/physiboss_cell_lines/main.cpp b/sample_projects_intracellular/boolean/physiboss_cell_lines/main.cpp index a3d872462..6da7cca3b 100644 --- a/sample_projects_intracellular/boolean/physiboss_cell_lines/main.cpp +++ b/sample_projects_intracellular/boolean/physiboss_cell_lines/main.cpp @@ -118,6 +118,13 @@ int main( int argc, char* argv[] ) setup_microenvironment(); // modify this in the custom code + bool start_stop = parameters.bools("start_stop"); + if( start_stop ){ + + // reset microenvironment and cells as they were in the previous simulation + reset_microenv(); + } + /* PhysiCell setup */ // set mechanics voxel size, and match the data structure to BioFVM @@ -128,7 +135,19 @@ int main( int argc, char* argv[] ) create_cell_types(); - setup_tissue(); + if( start_stop ){ + + // reset cells as they were in the previous simulation + setup_tissue(); + + reset_cell(cell_container->last_cell_cycle_time); + //exit(-1); + + reset_global_parameters(cell_container); + + } else{ + setup_tissue(); //death model index = 1 == necrotic...= 0 == apoptotic. + } /* Users typically stop modifying here. END USERMODS */ @@ -182,6 +201,10 @@ int main( int argc, char* argv[] ) report_file<<"simulated time\tnum cells\tnum division\tnum death\twall time"< 64, change lib path +ifeq ($(shell expr $(MABOSS_MAX_NODES) '>' 64), 1) +LIB := -L$(CUR_DIR)/$(MABOSS_DIR)/lib -lMaBoSS_$(MABOSS_MAX_NODES)n-static $(LDL_FLAG) +endif + +ARCH := native # best auto-tuning +# ARCH := core2 # a reasonably safe default for most CPUs since 2007 +# ARCH := corei7 +# ARCH := corei7-avx # earlier i7 +# ARCH := core-avx-i # i7 ivy bridge or newer +# ARCH := core-avx2 # i7 with Haswell or newer +# ARCH := nehalem +# ARCH := westmere +# ARCH := sandybridge # circa 2011 +# ARCH := ivybridge # circa 2012 +# ARCH := haswell # circa 2013 +# ARCH := broadwell # circa 2014 +# ARCH := skylake # circa 2015 +# ARCH := bonnell +# ARCH := silvermont +# ARCH := skylake-avx512 +# ARCH := nocona #64-bit pentium 4 or later + +# CFLAGS := -march=$(ARCH) -Ofast -s -fomit-frame-pointer -mfpmath=both -fopenmp -m64 -std=c++11 +CFLAGS := -march=$(ARCH) -O3 -fomit-frame-pointer -mfpmath=both -fopenmp -m64 -std=c++11 + +ifeq ($(OS),Windows_NT) +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Darwin) + UNAME_P := $(shell uname -p) + var := $(shell which $(CC) | xargs file) + ifeq ($(lastword $(var)),arm64) + CFLAGS := -march=$(ARCH) -O3 -fomit-frame-pointer -fopenmp -m64 -std=c++11 + endif + endif +endif + +COMPILE_COMMAND := $(CC) $(CFLAGS) + +BioFVM_OBJECTS := BioFVM_vector.o BioFVM_mesh.o BioFVM_microenvironment.o BioFVM_solvers.o BioFVM_matlab.o \ +BioFVM_utilities.o BioFVM_basic_agent.o BioFVM_MultiCellDS.o BioFVM_agent_container.o + +PhysiCell_core_OBJECTS := PhysiCell_phenotype.o PhysiCell_cell_container.o PhysiCell_standard_models.o \ +PhysiCell_cell.o PhysiCell_custom.o PhysiCell_utilities.o PhysiCell_constants.o PhysiCell_basic_signaling.o \ +PhysiCell_signal_behavior.o PhysiCell_rules.o + +PhysiCell_module_OBJECTS := PhysiCell_SVG.o PhysiCell_pathology.o PhysiCell_MultiCellDS.o PhysiCell_various_outputs.o \ +PhysiCell_pugixml.o PhysiCell_settings.o PhysiCell_geometry.o + +# put your custom objects here (they should be in the custom_modules directory) +MaBoSS := ./addons/PhysiBoSS/MaBoSS/engine/src/BooleanNetwork.h + +PhysiBoSS_OBJECTS := maboss_network.o maboss_intracellular.o + +PhysiCell_custom_module_OBJECTS := custom.o submodel_data_structures.o tnf_receptor_dynamics.o tnf_boolean_model_interface.o + +pugixml_OBJECTS := pugixml.o + +PhysiCell_OBJECTS := $(BioFVM_OBJECTS) $(pugixml_OBJECTS) $(PhysiCell_core_OBJECTS) $(PhysiCell_module_OBJECTS) + +start_and_stop_OBJECTS := start_and_stop.o +ALL_OBJECTS := $(PhysiCell_OBJECTS) $(PhysiCell_custom_module_OBJECTS) $(PhysiBoSS_OBJECTS) $(PhysiBoSS_module_OBJECTS) $(start_and_stop_OBJECTS) + +# compile the project + +all: main.cpp $(ALL_OBJECTS) $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -o $(PROGRAM_NAME) $(ALL_OBJECTS) main.cpp $(LIB) + @echo "" + @echo "check for $(PROGRAM_NAME)" + +# PhysiCell core components + +PhysiCell_phenotype.o: ./core/PhysiCell_phenotype.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_phenotype.cpp + +PhysiCell_digital_cell_line.o: ./core/PhysiCell_digital_cell_line.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_digital_cell_line.cpp + +PhysiCell_cell.o: ./core/PhysiCell_cell.cpp $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -c ./core/PhysiCell_cell.cpp + +PhysiCell_cell_container.o: ./core/PhysiCell_cell_container.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_cell_container.cpp + +PhysiCell_standard_models.o: ./core/PhysiCell_standard_models.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_standard_models.cpp + +PhysiCell_utilities.o: ./core/PhysiCell_utilities.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_utilities.cpp + +PhysiCell_custom.o: ./core/PhysiCell_custom.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_custom.cpp + +PhysiCell_constants.o: ./core/PhysiCell_constants.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_constants.cpp + +PhysiCell_signal_behavior.o: ./core/PhysiCell_signal_behavior.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_signal_behavior.cpp + +PhysiCell_rules.o: ./core/PhysiCell_rules.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_rules.cpp + +# BioFVM core components (needed by PhysiCell) + +BioFVM_vector.o: ./BioFVM/BioFVM_vector.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_vector.cpp + +BioFVM_agent_container.o: ./BioFVM/BioFVM_agent_container.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_agent_container.cpp + +BioFVM_mesh.o: ./BioFVM/BioFVM_mesh.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_mesh.cpp + +BioFVM_microenvironment.o: ./BioFVM/BioFVM_microenvironment.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_microenvironment.cpp + +BioFVM_solvers.o: ./BioFVM/BioFVM_solvers.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_solvers.cpp + +BioFVM_utilities.o: ./BioFVM/BioFVM_utilities.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_utilities.cpp + +BioFVM_basic_agent.o: ./BioFVM/BioFVM_basic_agent.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_basic_agent.cpp + +BioFVM_matlab.o: ./BioFVM/BioFVM_matlab.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_matlab.cpp + +BioFVM_MultiCellDS.o: ./BioFVM/BioFVM_MultiCellDS.cpp + $(COMPILE_COMMAND) -c ./BioFVM/BioFVM_MultiCellDS.cpp + +pugixml.o: ./BioFVM/pugixml.cpp + $(COMPILE_COMMAND) -c ./BioFVM/pugixml.cpp + +# standard PhysiCell modules + +PhysiCell_SVG.o: ./modules/PhysiCell_SVG.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_SVG.cpp + +PhysiCell_pathology.o: ./modules/PhysiCell_pathology.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_pathology.cpp + +PhysiCell_MultiCellDS.o: ./modules/PhysiCell_MultiCellDS.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_MultiCellDS.cpp + +PhysiCell_various_outputs.o: ./modules/PhysiCell_various_outputs.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_various_outputs.cpp + + +PhysiCell_pugixml.o: ./modules/PhysiCell_pugixml.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_pugixml.cpp + +PhysiCell_settings.o: ./modules/PhysiCell_settings.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_settings.cpp + +PhysiCell_basic_signaling.o: ./core/PhysiCell_basic_signaling.cpp + $(COMPILE_COMMAND) -c ./core/PhysiCell_basic_signaling.cpp + +PhysiCell_geometry.o: ./modules/PhysiCell_geometry.cpp + $(COMPILE_COMMAND) -c ./modules/PhysiCell_geometry.cpp + +# start_and_stop +start_and_stop.o: ./addons/start_and_stop/start_and_stop.cpp + $(COMPILE_COMMAND) $(INC) -c ./addons/start_and_stop/start_and_stop.cpp + +# user-defined PhysiCell modules + +Compile_MaBoSS: ./addons/PhysiBoSS/MaBoSS/engine/src/BooleanNetwork.h + cd ./addons/PhysiBoSS/MaBoSS/engine/src;make CXX=$(CC) install_alib;make clean; cd ../../../../.. + +$(MaBoSS): +ifeq ($(OS), Windows_NT) + python addons/PhysiBoSS/setup_libmaboss.py +else + python3 addons/PhysiBoSS/setup_libmaboss.py +endif + +maboss_network.o: ./addons/PhysiBoSS/src/maboss_network.cpp $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -c ./addons/PhysiBoSS/src/maboss_network.cpp + +maboss_intracellular.o: ./addons/PhysiBoSS/src/maboss_intracellular.cpp $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -c ./addons/PhysiBoSS/src/maboss_intracellular.cpp + +custom.o: ./custom_modules/custom.cpp $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -c ./custom_modules/custom.cpp + +submodel_data_structures.o: ./custom_modules/submodel_data_structures.cpp + $(COMPILE_COMMAND) $(INC) -c ./custom_modules/submodel_data_structures.cpp + +tnf_receptor_dynamics.o: ./custom_modules/tnf_receptor_dynamics.cpp + $(COMPILE_COMMAND) $(INC) -c ./custom_modules/tnf_receptor_dynamics.cpp + +tnf_boolean_model_interface.o: ./custom_modules/tnf_boolean_model_interface.cpp $(MaBoSS) + $(COMPILE_COMMAND) $(INC) -c ./custom_modules/tnf_boolean_model_interface.cpp + @echo "compiling" +# cleanup + +reset: + rm -f *.cpp + cp ./sample_projects/Makefile-default Makefile + rm -f ./custom_modules/* + touch ./custom_modules/empty.txt + rm ALL_CITATIONS.txt + rm -f ./config/PhysiCell_settings.xml + rm -f ./config/PhysiCell_settings_2D.xml + rm -f ./config/PhysiCell_settings_3D.xml + rm -f ./config/init.tsv + rm -f ./config/TNF_conf.cfg + rm -f ./config/TNF_nodes.bnd + rm -fr ./scripts + cp ./config/PhysiCell_settings-backup.xml ./config/PhysiCell_settings.xml + +MaBoSS-clean: + rm -fr addons/PhysiBoSS/MaBoSS + +clean: MaBoSS-clean + rm -f *.o + rm -f $(PROGRAM_NAME)* + +data-cleanup: + rm -f *.mat + rm -f *.xml + rm -f *.svg + rm -f ./output/* + touch ./output/empty.txt + +# archival + +checkpoint: + zip -r $$(date +%b_%d_%Y_%H%M).zip Makefile *.cpp *.h config/*.xml custom_modules/* + +zip: + zip -r latest.zip Makefile* *.cpp *.h BioFVM/* config/* core/* custom_modules/* matlab/* modules/* sample_projects/* + cp latest.zip $$(date +%b_%d_%Y_%H%M).zip + cp latest.zip VERSION_$(VERSION).zip + mv *.zip archives/ + +tar: + tar --ignore-failed-read -czf latest.tar Makefile* *.cpp *.h BioFVM/* config/* core/* custom_modules/* matlab/* modules/* sample_projects/* + cp latest.tar $$(date +%b_%d_%Y_%H%M).tar + cp latest.tar VERSION_$(VERSION).tar + mv *.tar archives/ + +unzip: + cp ./archives/latest.zip . + unzip latest.zip + +untar: + cp ./archives/latest.tar . + tar -xzf latest.tar diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings.xml b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings.xml new file mode 100644 index 000000000..a32e7c30d --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings.xml @@ -0,0 +1,225 @@ + + + -500 + 500 + -500 + 500 + -10 + 10 + 20 + 20 + 20 + true + + + + 180 + min + micron + 0.02 + 0.1 + 2 + + + + 8 + + + + output + + 30 + true + + + 30 + true + + + false + + + + + + + 100000.0 + .1 + + 38.0 + 38.0 + + + + + 1200.0 + .0275 + + 0.0 + 0.0 + + + + false + true + + + ./config/initial.mat + + + + ./config/dirichlet.mat + + + + + + + + + + + + 0.0011 + + + + + + 5.31667e-05 + + 516 + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + 0.0 + + 0 + 86400 + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + + 2494 + 0.75 + 540 + + 0.05 + 0.0045 + 0.0055 + + 0 + 0 + + 2.0 + + + + + 0 + 38 + 10 + 0 + + + 0 + 0 + 0 + 0 + + + + + + ./config/TNF_nodes.bnd + ./config/TNF_conf.cfg + + 10.0 + 0.01 + + + + + + 0.243 + 0.128 + 0.293 + + 0.50 + 1.0 + 0 + + + 0 + 0 + 0 + 0 + + + + 0.0035 + 0.0035 + 1.0 + + + + + + 0 + false + ./start_and_stop_saving_files/initial.tsv + 100 + + + 120 + + false + false + false + + true + 150 + 10 + 0.005 + 999999 + + + + 0.0 + 0.05 + 0.95 + + + 0.0 + 0.05 + 0.95 + + + 0.0 + 0.05 + 0.95 + + + + + + + \ No newline at end of file diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings_2D.xml b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings_2D.xml new file mode 100644 index 000000000..a6764a6f4 --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings_2D.xml @@ -0,0 +1,286 @@ + + + + + + + + -500 + 500 + -500 + 500 + -10 + 10 + 20 + 20 + 20 + true + + + + 1440 + min + micron + 0.02 + 0.1 + 2 + + + + 8 + + + + output + + 30 + true + + + 30 + true + + + false + + + + + + + 100000.0 + .1 + + 38.0 + 38.0 + + + + + 1200.0 + .0275 + + 0.0 + 0.0 + + + + false + true + + + ./config/initial.mat + + + + ./config/dirichlet.mat + + + + + + + + + + + + 0.00075 + + + + + + 5.31667e-05 + + 516 + + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + 0.0 + + 0 + 86400 + + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + + 2494 + 0.75 + 540 + + 0.05 + 0.0045 + 0.0055 + + 0 + 0 + + 2.0 + + + + + + 0 + 38 + 10 + 0 + + + 0 + 0 + 0 + 0 + + + + + + ./config/TNF_nodes.bnd + ./config/TNF_conf.cfg + + 10 + 1 + + + + + + 0.243 + 0.128 + 0.293 + + 0.50 + 1.0 + 0 + + + 0 + 0 + 0 + 0 + + + 0.0027 + 0.0055 + + + + + + 0 + false + ./config/init.tsv + 100.0 + + 0.0 + 0.05 + 0.95 + + 0.0 + 0.05 + 0.95 + + 0.0 + 0.05 + 0.95 + + 150.0 + 10.0 + 0.0015 + 999999 + 120 + + + + diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings_3D.xml b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings_3D.xml new file mode 100644 index 000000000..dab033eb4 --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/PhysiCell_settings_3D.xml @@ -0,0 +1,287 @@ + + + + + + + + -200 + 200 + -200 + 200 + -200 + 200 + 20 + 20 + 20 + false + + + + 2160 + min + micron + 0.02 + 0.1 + 2 + + + + 8 + + + + output + + 30 + true + + + 30 + true + + + false + + + + + + + 100000.0 + .1 + + 38.0 + 38.0 + + + + + 1200.0 + .0275 + + 0.0 + 0.0 + + + + false + true + + + ./config/initial.mat + + + + ./config/dirichlet.mat + + + + + + + + + + + + 0.00075 + + + + + + 5.31667e-05 + + 516 + + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + 0.0 + + 0 + 86400 + + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + + + 2494 + 0.75 + 540 + + 0.05 + 0.0045 + 0.0055 + + 0 + 0 + + 2.0 + + + + + + 0 + 38 + 10 + 0 + + + 0 + 0 + 0 + 0 + + + + + + ./config/TNF_nodes.bnd + ./config/TNF_conf.cfg + + 10 + 1 + + + + + + 0.243 + 0.128 + 0.293 + + 0.50 + 1.0 + 0 + + + 0 + 0 + 0 + 0 + + + 0.0027 + 0.0055 + 1e-7 + + + + + + 0 + ./config/init.tsv + false + 50.0 + + 0.0 + 0.05 + 0.95 + + 0.0 + 0.05 + 0.95 + + 0.0 + 0.05 + 0.95 + + 150.0 + 10.0 + 0.002 + 999999 + 80 + + + + \ No newline at end of file diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/config/TNF_conf.cfg b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/TNF_conf.cfg new file mode 100644 index 000000000..5e9c9892a --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/TNF_conf.cfg @@ -0,0 +1,101 @@ + +// input +FADD.istate = 0; +TNF.istate = 0; +FASL.istate = 0; + +// output +NonACD.istate = 0; +Apoptosis.istate = 0 ; +Survival.istate = 0 ; + +// specific state +ATP.istate = 1; +cIAP.istate = 1; + +TNFR.istate = 0 ; +DISC_TNF.istate = 0 ; +DISC_FAS.istate = 0 ; +RIP1.istate = 0 ; +RIP1ub.istate = 0 ; +RIP1K.istate = 0 ; +IKK.istate = 0 ; +NFkB.istate = 0 ; +CASP8.istate = 0 ; +BAX.istate = 0 ; +BCL2.istate = 0 ; +ROS.istate = 0 ; +mROS.istate = 0 ; +MPT.istate = 0 ; +MOMP.istate = 0 ; +SMAC.istate = 0 ; +mcIAP.istate = 0 ; +Cyt_c.istate = 0 ; +XIAP.istate = 0 ; +mXIAP.istate = 0 ; +apoptosome.istate = 0 ; +CASP3.istate = 0 ; +cFLIP.istate = 0 ; + +//$ProdTNF_NFkB = 1; +$TransRate = 1/24; +//$DivRate = 1/24; +//$Degr_TNF = 1/6; +//$TNF_induc = 0; + +//[TNF].istate = 1 [1] , 0 [0]; + + +//TNF.is_internal = TRUE ; +//ATP.is_internal = TRUE ; +//FADD.is_internal = TRUE ; +//cIAP.is_internal = TRUE ; +// +//FASL.is_internal = TRUE ; +//TNFR.is_internal = TRUE ; +//DISC_TNF.is_internal = TRUE ; +//DISC_FAS.is_internal = TRUE ; +//RIP1.is_internal = TRUE ; +//RIP1ub.is_internal = TRUE ; +//RIP1K.is_internal = TRUE ; +//IKK.is_internal = TRUE ; +//NFkB.is_internal = TRUE ; +//CASP8.is_internal = TRUE ; +//BAX.is_internal = TRUE ; +//BCL2.is_internal = TRUE ; +//ROS.is_internal = TRUE ; +//MPT.is_internal = TRUE ; +//MOMP.is_internal = TRUE ; +//SMAC.is_internal = TRUE ; +//Cyt_c.is_internal = TRUE ; +//XIAP.is_internal = TRUE ; +//apoptosome.is_internal = TRUE ; +//CASP3.is_internal = TRUE ; +//cFLIP.is_internal = TRUE ; + + +sample_count = 1; +max_time = 1; // 10 min: 1 in maboss = 10 min in Physicell +time_tick = .01; +discrete_time = 0; +use_physrandgen = FALSE; +seed_pseudorandom = 37; +display_traj = FALSE; + +thread_count = 1; + +statdist_traj_count = 1; +statdist_cluster_threshold = 0.8; + +$Low_CASP3 = 0.0; +$High_CASP3 = 0.0; +$High_Cytc = 0.0; +$Low_CASP8 = 0.0; +$High_CASP8 = 0.0; +$High_IKK = 0.0; +$High_cFLIP = 0.0; +$Low_cIAP = 0.0; +$High_mROS = 0.0; +$Low_RIP1 = 0.0; +$High_NFkB = 0.0; +$Low_NFkB = 0.0; diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/config/TNF_nodes.bnd b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/TNF_nodes.bnd new file mode 100644 index 000000000..d91d6f8dc --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/TNF_nodes.bnd @@ -0,0 +1,184 @@ +node FASL +{ + rate_up = 0.0; + rate_down = 0.0; +} +node TNF +{ + logic = TNF; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node TNFR +{ + logic = TNF; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node DISC_TNF +{ + logic = FADD & TNFR; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node DISC_FAS +{ + logic = FASL & FADD; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node FADD +{ + rate_up = 0.0; + rate_down = 0.0; +} +node RIP1 +{ + logic = (DISC_FAS | TNFR) & (!CASP8); + rate_up = ($Low_RIP1 ? 0.0 : ( @logic ? 1.0: 0.0 )); + rate_down = ($Low_RIP1 ? 1E+100 : ( @logic ? 0.0 : 1.0 )); +} +node RIP1ub +{ + logic = cIAP & RIP1; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node RIP1K +{ + logic = RIP1; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node IKK +{ + logic = RIP1ub; + rate_up = ($High_IKK ? 1E+100 : (@logic ? 1.0 : 0.0) ); + rate_down = ($High_IKK ? 0.0 : (@logic ? 0.0 : 1.0) ); +} +node NFkB +{ + logic = IKK & (!CASP3); + rate_up = ($Low_NFkB ? 0.0 : ($High_NFkB ? 1E+100 : ( @logic ? 1.0 : 0.0) )); + rate_down = ($Low_NFkB ? 1E+100 : ($High_NFkB ? 0.0 : (@logic ? 0.0 : 1.0) )); +} +node CASP8 +{ + logic = (DISC_TNF | (DISC_FAS | CASP3) ) & (!cFLIP); + rate_up = ($Low_CASP8 ? 0.0 : ( $High_CASP8 ? 1E+100 : ( @logic ? 1.0: 0.0 )) ); + rate_down = ($Low_CASP8 ? 1E+100 : ( $High_CASP8 ? 0.0 : (@logic ? 0.0 : 1.0 )) ); +} +node BAX +{ + logic = CASP8 & (!BCL2); + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node BCL2 +{ + logic = NFkB; + rate_up = (@logic ? $TransRate : 0.0); + rate_down = @logic ? 0.0 : 1.0; +} +node mROS +{ + logic = (!NFkB); + rate_up = ($High_mROS ? 1E+100 : (@logic ? $TransRate : 0.0) ); + rate_down = ($High_mROS ? 0.0: (@logic ? 0.0 : 1.0) ); +} +node ROS +{ + logic = (mROS) & (MPT | RIP1K ); + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node ATP +{ + logic = !MPT; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node MPT +{ + logic = (!BCL2) & ROS; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node MOMP +{ + logic = BAX | MPT; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node SMAC +{ + logic = MOMP; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node mcIAP +{ + logic = (NFkB); + rate_up = @logic ? $TransRate : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node cIAP +{ + logic = (mcIAP & (!SMAC)); + rate_up = ($Low_cIAP ? 0.0 : ( @logic ? $TransRate: 0.0 )); + rate_down = ($Low_cIAP ? 1E+100 : ( (SMAC) ? 1.0 : 0.0 )); +} +node Cyt_c +{ + logic = MOMP; + rate_up = ($High_Cytc ? 1E+100 : (@logic ? 1.0 : 0.0) ); + rate_down = ($High_Cytc ? 0.0 : (@logic ? 0.0 : 1.0) ); +} +node mXIAP +{ + logic = (NFkB); + rate_up = @logic ? $TransRate : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node XIAP +{ + logic = (!SMAC) & mXIAP; + rate_up = (@logic) ? 1.0 : 0.0; + rate_down = (@logic ? 0.0 : 1.0); +} +node apoptosome +{ + logic = Cyt_c & (ATP & (!XIAP)); + rate_up = (@logic) ? 1.0 : 0.0; + rate_down = (@logic ? 0.0 : 1.0); +} +node CASP3 +{ + logic = apoptosome & (!XIAP); + rate_up = ( $Low_CASP3 ? 0.0 : ($High_CASP3 ? 1E+100 : ((@logic ? 1.0 : 0.0)) ) ); + rate_down = ($Low_CASP3 ? 1E+100 : ($High_CASP3 ? 0.0 : ( @logic ? 0.0 : 1.0) ) ); +} +node cFLIP +{ + logic = NFkB ; + rate_up = ($High_cFLIP ? 1E+100 : ((@logic) ? $TransRate : 0.0) ); + rate_down = ($High_cFLIP ? 0.0 : (@logic ? 0.0 : 1.0) ); +} +node NonACD +{ + logic = !ATP; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node Apoptosis +{ + logic = CASP3; + rate_up = @logic ? 1.0 : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} +node Survival +{ + logic = NFkB; + rate_up = @logic ? $TransRate : 0.0; + rate_down = @logic ? 0.0 : 1.0; +} diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/config/init.tsv b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/init.tsv new file mode 100644 index 000000000..02e46f221 --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/config/init.tsv @@ -0,0 +1,126 @@ +x y z +-93.7351 -16.7883 0.0 +-95.7338 2.90696 0.0 +-95.9399 18.5505 0.0 +-79.8482 -55.7662 0.0 +-82.7174 -41.7014 0.0 +-80.7886 -22946 0.0 +-79.0268 -6.05337 0.0 +-82.0067 10.4321 0.0 +-80.6049 25.4132 0.0 +-82.8366 44.0516 0.0 +-78.9526 61124 0.0 +-64102 -65.5156 0.0 +-64.2225 -46.9066 0.0 +-68468 -33.3416 0.0 +-68.4907 -14.3586 0.0 +-67762 -0.0687358 0.0 +-64.3596 17.0034 0.0 +-65.1953 36802 0.0 +-65.7418 51.8249 0.0 +-64.8725 70.5213 0.0 +-49.7993 -75.1665 0.0 +-50.1662 -59.6431 0.0 +-51.6159 -42.4253 0.0 +-52.2097 -24.4339 0.0 +-49.6998 -5.49337 0.0 +-52.8067 10.2768 0.0 +-53.0525 25.5959 0.0 +-50.1145 42.8981 0.0 +-50.8895 63.7084 0.0 +-51.5362 77.8187 0.0 +-35.1206 -84.1124 0.0 +-39.0413 -67.4176 0.0 +-36.7631 -50.2966 0.0 +-35.5977 -32.8759 0.0 +-38.2835 -13.9819 0.0 +-36793 3.2073 0.0 +-38.2603 20.0752 0.0 +-38.5707 36.7987 0.0 +-35.5583 50.5694 0.0 +-35.4349 71.8035 0.0 +-34977 87.9757 0.0 +-20.4709 -93.9292 0.0 +-20396 -76.3795 0.0 +-23.7124 -57.6671 0.0 +-23908 -40.2429 0.0 +-21.0551 -22.9972 0.0 +-20.3947 -5.09517 0.0 +-20212 9.72254 0.0 +-24.1934 27.5216 0.0 +-19.9637 47.0325 0.0 +-22.1828 63.9466 0.0 +-22.5229 76.7938 0.0 +-23.5922 96.0568 0.0 +-7.4651 -98934 0.0 +-5.63692 -80.5666 0.0 +-9.19887 -66.9041 0.0 +-7.83299 -49.2237 0.0 +-7.58047 -29.8289 0.0 +-9.17806 -14.3046 0.0 +-8.47321 1.79866 0.0 +-6.22558 17232 0.0 +-6.1979 34592 0.0 +-6.06438 51.8374 0.0 +-7.99579 71.8464 0.0 +-9.34279 88.3144 0.0 +8.09689 -92.1459 0.0 +8.56241 -76.1541 0.0 +5.75799 -58.7743 0.0 +6.80561 -42.8107 0.0 +7.29498 -24.8781 0.0 +9.49315 -8.67633 0.0 +5.48934 10.7607 0.0 +7.48964 25.2213 0.0 +8.37825 44.0642 0.0 +6.63344 60.3534 0.0 +8.82467 76.4799 0.0 +5.50615 97.7667 0.0 +20.0973 -85.3025 0.0 +23.6045 -66.3319 0.0 +21.6682 -31.0106 0.0 +20.8476 -14.3643 0.0 +23354 4.3938 0.0 +23.2571 21.0108 0.0 +21.9115 37.8318 0.0 +23.0517 50.9854 0.0 +20875 68.0303 0.0 +37.9323 -76.0558 0.0 +38.8808 -59.6001 0.0 +34.7439 -39.8988 0.0 +34.7224 -26.0126 0.0 +38066 -8.93449 0.0 +36.8513 9.09404 0.0 +36.4099 27.3056 0.0 +35.4412 44.6587 0.0 +36.1567 62.8726 0.0 +37.3943 79938 0.0 +50.5785 -83.4395 0.0 +51.7827 -64.4546 0.0 +50186 -48.5523 0.0 +53.3226 -33.7905 0.0 +51.1424 -15.7653 0.0 +52.0446 1.17038 0.0 +52.8293 16.8413 0.0 +49.7305 34.3809 0.0 +51.0108 55.0179 0.0 +49.4942 67.6309 0.0 +68.0616 -56.1252 0.0 +67.5741 -38.8549 0.0 +64.4535 -24.3364 0.0 +67.9933 -6.46241 0.0 +65.0907 12.6911 0.0 +65.1839 25.4711 0.0 +66.8215 44.4639 0.0 +67.4613 60.1319 0.0 +82.3886 -46.9536 0.0 +82.0147 -33.4872 0.0 +81.3058 -15.8358 0.0 +79.4432 -0.165153 0.0 +81181 18.2513 0.0 +82.8324 35.9978 0.0 +82.6803 55.3748 0.0 +95.6087 -23.2664 0.0 +96.4069 -7.70411 0.0 +94.1872 12.5324 0.0 +93.7707 26.4937 0.0 diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/custom.cpp b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/custom.cpp new file mode 100644 index 000000000..a79a5dd2c --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/custom.cpp @@ -0,0 +1,551 @@ +/* +############################################################################### +# If you use PhysiCell in your project, please cite PhysiCell and the version # +# number, such as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1]. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# See VERSION.txt or call get_PhysiCell_version() to get the current version # +# x.y.z. Call display_citations() to get detailed information on all cite-# +# able software used in your PhysiCell application. # +# # +# Because PhysiCell extensively uses BioFVM, we suggest you also cite BioFVM # +# as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1], # +# with BioFVM [2] to solve the transport equations. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# [2] A Ghaffarizadeh, SH Friedman, and P Macklin, BioFVM: an efficient para- # +# llelized diffusive transport solver for 3-D biological simulations, # +# Bioinformatics 32(8): 1256-8, 2016. DOI: 10.1093/bioinformatics/btv730 # +# # +############################################################################### +# # +# BSD 3-Clause License (see https://opensource.org/licenses/BSD-3-Clause) # +# # +# Copyright (c) 2015-2018, Paul Macklin and the PhysiCell Project # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are met: # +# # +# 1. Redistributions of source code must retain the above copyright notice, # +# this list of conditions and the following disclaimer. # +# # +# 2. Redistributions in binary form must reproduce the above copyright # +# notice, this list of conditions and the following disclaimer in the # +# documentation and/or other materials provided with the distribution. # +# # +# 3. Neither the name of the copyright holder nor the names of its # +# contributors may be used to endorse or promote products derived from this # +# software without specific prior written permission. # +# # +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # +# POSSIBILITY OF SUCH DAMAGE. # +# # +############################################################################### +*/ + +#include "./custom.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +// declare cell definitions here +void create_cell_types(void) +{ + SeedRandom(); + + initialize_default_cell_definition(); + + /* This parses the cell definitions in the XML config file. */ + initialize_cell_definitions_from_pugixml(); + + // This sets the pre and post intracellular update functions + cell_defaults.functions.pre_update_intracellular = update_boolean_model_inputs; + cell_defaults.functions.post_update_intracellular = update_behaviors; + cell_defaults.functions.update_phenotype = NULL; + + // This initializes the the TNF receptor model + tnf_receptor_model_setup(); + tnf_boolean_model_interface_setup(); + submodel_registry.display(std::cout); + + // Needs to initialize one of the receptor state to the total receptor value + cell_defaults.custom_data["unbound_external_TNFR"] = cell_defaults.custom_data["TNFR_receptors_per_cell"]; + cell_defaults.custom_data["bound_external_TNFR"] = 0; + cell_defaults.custom_data["bound_internal_TNFR"] = 0; + + build_cell_definitions_maps(); + + setup_signal_behavior_dictionaries(); + + display_cell_definitions(std::cout); + + return; +} + + +void setup_microenvironment(void) +{ + initialize_microenvironment(); + return; +} + +void setup_tissue(void) +{ + std::vector> positions; + + if ( parameters.bools("read_init") ) + { + std::string csv_fname = parameters.strings("init_cells_filename"); + positions = read_cells_positions(csv_fname, '\t', true); + + } + else + { + double cell_radius = cell_defaults.phenotype.geometry.radius; + double tumor_radius = parameters.doubles("tumor_radius"); + if (default_microenvironment_options.simulate_2D == true) + positions = create_cell_disc_positions(cell_radius,tumor_radius); + else + positions = create_cell_sphere_positions(cell_radius,tumor_radius); + + } + + Cell* pCell = NULL; + for (int i = 0; i < positions.size(); i++) + { + pCell = create_cell(get_cell_definition("default")); + pCell->assign_position(positions[i]); + + static int idx_bind_rate = pCell->custom_data.find_variable_index( "TNFR_binding_rate" ); + static float mean_bind_rate = pCell->custom_data[idx_bind_rate]; + static float std_bind_rate = parameters.doubles("TNFR_binding_rate_std"); + static float min_bind_rate = parameters.doubles("TNFR_binding_rate_min"); + static float max_bind_rate = parameters.doubles("TNFR_binding_rate_max"); + + if(std_bind_rate > 0 ) + { + pCell->custom_data[idx_bind_rate] = NormalRandom(mean_bind_rate, std_bind_rate); + if (pCell->custom_data[idx_bind_rate] < min_bind_rate) + { pCell->custom_data[idx_bind_rate] = min_bind_rate; } + if (pCell->custom_data[idx_bind_rate] > max_bind_rate) + { pCell->custom_data[idx_bind_rate] = max_bind_rate; } + } + + + static int idx_endo_rate = pCell->custom_data.find_variable_index( "TNFR_endocytosis_rate" ); + static float mean_endo_rate = pCell->custom_data[idx_endo_rate]; + static float std_endo_rate = parameters.doubles("TNFR_endocytosis_rate_std"); + static float min_endo_rate = parameters.doubles("TNFR_endocytosis_rate_min"); + static float max_endo_rate = parameters.doubles("TNFR_endocytosis_rate_max"); + + if(std_endo_rate > 0) + { + pCell->custom_data[idx_endo_rate] = NormalRandom(mean_endo_rate, std_endo_rate); + if (pCell->custom_data[idx_endo_rate] < min_endo_rate) + { pCell->custom_data[idx_endo_rate] = min_endo_rate; } + if (pCell->custom_data[idx_endo_rate] > max_endo_rate) + { pCell->custom_data[idx_endo_rate] = max_endo_rate; } + } + + static int idx_recycle_rate = pCell->custom_data.find_variable_index( "TNFR_recycling_rate" ); + static float mean_recycle_rate = pCell->custom_data[idx_recycle_rate]; + static float std_recycle_rate = parameters.doubles("TNFR_recycling_rate_std"); + static float min_recycle_rate = parameters.doubles("TNFR_recycling_rate_min"); + static float max_recycle_rate = parameters.doubles("TNFR_recycling_rate_max"); + + if(std_recycle_rate > 0) + { + pCell->custom_data[idx_recycle_rate] = NormalRandom(mean_recycle_rate, std_recycle_rate); + if (pCell->custom_data[idx_recycle_rate] < min_recycle_rate) + { pCell->custom_data[idx_recycle_rate] = min_recycle_rate; } + if (pCell->custom_data[idx_recycle_rate] > max_recycle_rate) + { pCell->custom_data[idx_recycle_rate] = max_recycle_rate; } + } + + update_monitor_variables(pCell); + } + + return; +} + +void update_variables_monitor() +{ + for (int i = 0; i < (*all_cells).size(); i++) + { + // Access the current cell + Cell *pCell = (*all_cells)[i]; + + update_monitor_variables(pCell); + } + + +} + +std::vector> read_cells_positions(std::string filename, char delimiter, bool header) +{ + // File pointer + std::fstream fin; + std::vector> positions; + + // Open an existing file + fin.open(filename, std::ios::in); + + // Read the Data from the file + // as String Vector + std::vector row; + std::string line, word; + + if (header) + { getline(fin, line); } + + do + { + row.clear(); + + // read an entire row and + // store it in a string variable 'line' + getline(fin, line); + + // used for breaking words + std::stringstream s(line); + + while (getline(s, word, delimiter)) + { + row.push_back(word); + } + + std::vector tempPoint(3,0.0); + tempPoint[0]= std::stof(row[0]); + tempPoint[1]= std::stof(row[1]); + tempPoint[2]= std::stof(row[2]); + + positions.push_back(tempPoint); + } while (!fin.eof()); + + return positions; +} + +std::vector> create_cell_sphere_positions(double cell_radius, double sphere_radius) +{ + std::vector> cells; + int xc=0,yc=0,zc=0; + double x_spacing= cell_radius*sqrt(3); + double y_spacing= cell_radius*2; + double z_spacing= cell_radius*sqrt(3); + + std::vector tempPoint(3,0.0); + // std::vector cylinder_center(3,0.0); + + for(double z=-sphere_radius;z> create_cell_disc_positions(double cell_radius, double disc_radius) +{ + double cell_spacing = 0.95 * 2.0 * cell_radius; + + double x = 0.0; + double y = 0.0; + double x_outer = 0.0; + + std::vector> positions; + std::vector tempPoint(3,0.0); + + int n = 0; + while( y < disc_radius ) + { + x = 0.0; + if( n % 2 == 1 ) + { x = 0.5 * cell_spacing; } + x_outer = sqrt( disc_radius*disc_radius - y*y ); + + while( x < x_outer ) + { + tempPoint[0]= x; tempPoint[1]= y; tempPoint[2]= 0.0; + positions.push_back(tempPoint); + if( fabs( y ) > 0.01 ) + { + tempPoint[0]= x; tempPoint[1]= -y; tempPoint[2]= 0.0; + positions.push_back(tempPoint); + } + if( fabs( x ) > 0.01 ) + { + tempPoint[0]= -x; tempPoint[1]= y; tempPoint[2]= 0.0; + positions.push_back(tempPoint); + if( fabs( y ) > 0.01 ) + { + tempPoint[0]= -x; tempPoint[1]= -y; tempPoint[2]= 0.0; + positions.push_back(tempPoint); + } + } + x += cell_spacing; + } + y += cell_spacing * sqrt(3.0)/2.0; + n++; + } + return positions; +} + +void inject_density_sphere(int density_index, double concentration, double membrane_lenght) +{ + // Inject given concentration on the extremities only + #pragma omp parallel for + for (int n = 0; n < microenvironment.number_of_voxels(); n++) + { + auto current_voxel = microenvironment.voxels(n); + std::vector cent = {current_voxel.center[0], current_voxel.center[1], current_voxel.center[2]}; + + if ((membrane_lenght - norm(cent)) <= 0) + microenvironment.density_vector(n)[density_index] = concentration; + } +} + +void remove_density(int density_index) +{ + for (int n = 0; n < microenvironment.number_of_voxels(); n++) + microenvironment.density_vector(n)[density_index] = 0; +} + +std::vector my_coloring_function(Cell *pCell) +{ + // start with live coloring + std::vector output = false_cell_coloring_live_dead(pCell); + + // dead cells + if (pCell->phenotype.death.dead == false) + { + static int nR_EB = pCell->custom_data.find_variable_index("bound external TNFR"); + float activation_threshold = pCell->custom_data.find_variable_index("TNFR activation threshold"); + + int bounded_tnf = (int)round((pCell->custom_data[nR_EB] / activation_threshold) * 255.0); + if (bounded_tnf > 0) + { + char szTempString[128]; + sprintf(szTempString, "rgb(%u,%u,%u)", bounded_tnf, bounded_tnf, 255 - bounded_tnf); + output[0].assign("black"); + output[1].assign(szTempString); + output[2].assign("black"); + output[3].assign(szTempString); + } + } + + return output; +} + + +double total_live_cell_count() +{ + double out = 0.0; + + for( int i=0; i < (*all_cells).size() ; i++ ) + { + if( (*all_cells)[i]->phenotype.death.dead == false && (*all_cells)[i]->type == 0 ) + { out += 1.0; } + } + + return out; +} + +double total_dead_cell_count() +{ + double out = 0.0; + + for( int i=0; i < (*all_cells).size() ; i++ ) + { + if( (*all_cells)[i]->phenotype.death.dead == true && (*all_cells)[i]->phenotype.death.current_death_model_index == 0 ) + { out += 1.0; } + } + + return out; +} + +double total_necrosis_cell_count() +{ + double out = 0.0; + + for( int i=0; i < (*all_cells).size() ; i++ ) + { + if( (*all_cells)[i]->phenotype.death.dead == true && (*all_cells)[i]->phenotype.death.current_death_model_index == 1 ) + { out += 1.0; } + } + + return out; +} + +using namespace std; + +vector vector_alives; + +bool auto_stop_resistance(int alive_cells, int resistant_cells) { + // Define stable states and nodes as vectors instead of unordered_sets + + vector_alives.push_back(alive_cells); + std::cout << "Steps: " << vector_alives.size() << std::endl; + + double threshold = 0.8; + double percentage_of_resistant = static_cast(resistant_cells) / alive_cells; + std::cout << "Number of resistant: " << resistant_cells << std::endl; + + bool stop; + bool condition = false; + if (vector_alives.size() >= 4){ + condition = percentage_of_resistant >= threshold; + } + + if (condition) { + stop = true; + } else { + stop = false; + } + return stop; +} + +bool auto_stop_alive(int alive_cells) { + //concatenate the number of alive cells to the vector + vector_alives.push_back(alive_cells); + std::cout << "Steps: " << vector_alives.size() << std::endl; + + bool condition = false; + // check the number of elements inside the vector to decide if process it and compute the derivative + if (vector_alives.size() >= 8) { + std::vector derivative; + + // compute the derivative only for the last three steps + for (size_t i = vector_alives.size() - 4; i < vector_alives.size(); ++i) { + double slope = vector_alives[i] - vector_alives[i - 1]; + derivative.push_back(slope); + } + + condition = true; + for (double slope : derivative) { + // if the slope is less than or equal to zero, set condition to false + if (slope < 0) { + condition = false; + break; + } + } + + } else { + condition = false; + } + + bool stop; + + if (condition) { + stop = true; + } else { + stop = false; + } + return stop; +} + +int save_resistant_cells(ofstream& file_resistant){ + //count the number of resistant cells for the plots + vector> stable_states = { + {"TNF", "TNFR", "RIP1", "RIP1ub", "RIP1K", "IKK", "NFkB", "BCL2", "ATP", "cIAP", "XIAP", "cFLIP", "Survival"}, + {"FASL", "TNF", "TNFR", "RIP1", "RIP1ub", "RIP1K", "IKK", "NFkB", "BCL2", "ATP", "cIAP", "XIAP", "cFLIP", "Survival"}, + {"TNF", "TNFR", "DISC-TNF", "FADD", "RIP1", "RIP1ub", "RIP1K", "IKK", "NFkB", "BCL2", "ATP", "cIAP", "XIAP", "cFLIP", "Survival"}, + {"FASL", "DISC-FAS", "FADD", "RIP1", "RIP1ub", "RIP1K", "IKK", "NFkB", "BCL2", "ATP", "cIAP", "XIAP", "cFLIP", "Survival"}, + {"FASL", "TNF", "TNFR", "DISC-TNF", "DISC-TNF", "FADD", "RIP1", "RIP1ub", "RIP1K", "IKK", "NFkB", "BCL2", "ATP", "cIAP", "XIAP", "cFLIP", "Survival"} + }; + + // Read the bool_data.txt file + ifstream file("start_and_stop_saving_files/bool_data.txt"); + if (!file.is_open()) { + cerr << "Error opening file." << endl; + exit(1); + } + + string line; + int counter_stable = 0; + while (getline(file, line)) { + istringstream iss(line); + string node; + vector nodes; // Define nodes as a vector + while (iss >> node) { + size_t pos = node.find('='); + if (pos != string::npos) { + string key = node.substr(0, pos); + string value = node.substr(pos + 1); + if (value == "1") { + nodes.push_back(key); // Push key to nodes vector + } + } + } + + sort(nodes.begin(), nodes.end()); // Sort nodes vector + + // Loop through stable_states vectors + for (auto& state : stable_states) { + sort(state.begin(), state.end()); // Sort each stable state vector + if (includes(nodes.begin(), nodes.end(), state.begin(), state.end())) { + counter_stable++; + break; + } + } + } + // save the number of resistant cells on a file + + file_resistant << counter_stable << endl; + + + return counter_stable; +} + +bool auto_stop() { + + bool condition = false; + bool stop; + // impèlement here your condition to stop the simulation + + if (condition) { + stop = true; + } else { + stop = false; + } + return stop; +} diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/custom.h b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/custom.h new file mode 100644 index 000000000..f13008543 --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/custom.h @@ -0,0 +1,126 @@ +/* +############################################################################### +# If you use PhysiCell in your project, please cite PhysiCell and the version # +# number, such as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1]. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# See VERSION.txt or call get_PhysiCell_version() to get the current version # +# x.y.z. Call display_citations() to get detailed information on all cite-# +# able software used in your PhysiCell application. # +# # +# Because PhysiCell extensively uses BioFVM, we suggest you also cite BioFVM # +# as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1], # +# with BioFVM [2] to solve the transport equations. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# [2] A Ghaffarizadeh, SH Friedman, and P Macklin, BioFVM: an efficient para- # +# llelized diffusive transport solver for 3-D biological simulations, # +# Bioinformatics 32(8): 1256-8, 2016. DOI: 10.1093/bioinformatics/btv730 # +# # +############################################################################### +# # +# BSD 3-Clause License (see https://opensource.org/licenses/BSD-3-Clause) # +# # +# Copyright (c) 2015-2018, Paul Macklin and the PhysiCell Project # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are met: # +# # +# 1. Redistributions of source code must retain the above copyright notice, # +# this list of conditions and the following disclaimer. # +# # +# 2. Redistributions in binary form must reproduce the above copyright # +# notice, this list of conditions and the following disclaimer in the # +# documentation and/or other materials provided with the distribution. # +# # +# 3. Neither the name of the copyright holder nor the names of its # +# contributors may be used to endorse or promote products derived from this # +# software without specific prior written permission. # +# # +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # +# POSSIBILITY OF SUCH DAMAGE. # +# # +############################################################################### +*/ + +#include + +#include "../core/PhysiCell.h" +#include "../modules/PhysiCell_standard_modules.h" + +#include "./tnf_receptor_dynamics.h" +#include "./tnf_boolean_model_interface.h" +#include "../addons/start_and_stop/start_and_stop.h" + +using namespace BioFVM; +using namespace PhysiCell; + +// setup functions to help us along +void create_cell_types( void ); +void setup_tissue( void ); +void setup_tissue_input(void); + +// set up the BioFVM microenvironment +void setup_microenvironment( void ); + +// helper function to read init files +std::vector> read_cells_positions(std::string filename, char delimiter, bool header); + +// helper function to create a sphere of cells of a given radius +std::vector> create_cell_sphere_positions(double cell_radius, double sphere_radius); + +// helper function to create a disc of cells of a given radius +std::vector> create_cell_disc_positions(double cell_radius, double disc_radius); + +// helper function that calculates phere volume +inline float sphere_volume_from_radius(float radius) {return 4/3 * PhysiCell_constants::pi * std::pow(radius, 3);} + +// helper function to inject density surrounding a spheroid +void inject_density_sphere(int density_index, double concentration, double membrane_lenght); + +// helper function to remove a density +void remove_density( int density_index ); + +// custom pathology coloring function +std::vector my_coloring_function( Cell* ); + +double total_live_cell_count(); + +// count the number of total dead cells at current time step +double total_dead_cell_count(); + +// count the number of necrotic cells at current time step +double total_necrosis_cell_count(); + +// function to auto stop the simulation +bool auto_stop_resistance(int alive_cells, int resistant_cells); +bool auto_stop_alive(int alive_cells); +int save_resistant_cells(std::ofstream& file_resistant); +void update_variables_monitor(); +bool auto_stop(); + + + + diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/submodel_data_structures.cpp b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/submodel_data_structures.cpp new file mode 100644 index 000000000..22630e3f8 --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/submodel_data_structures.cpp @@ -0,0 +1,114 @@ +/* + * submodel_data_structures.cpp + * + * Created on: ? + * Author: Paul Macklin + * + * Description: + * Auxiliary class to manage submodels + * + * Source: https://github.com/pc4covid19/COVID19/blob/master/PhysiCell/custom_modules/submodel_data_structures.cpp +*/ + +#include "./submodel_data_structures.h" + +using namespace PhysiCell; + +Submodel_Registry submodel_registry; + +Submodel_Information::Submodel_Information( void ) +{ + name = "none"; + version = "-1"; + main_function = NULL; + + microenvironment_variables.resize(0); + cell_variables.resize(0); // custom data + + return; +} + +void Submodel_Information::register_model( void ) +{ + // make sure the cell defaults "know" about each custom variable + // Make sure it's there, or add if it's not. + + for( int n = 0 ; n < cell_variables.size() ; n++ ) + { + // let's do this a bit manually (and inefficiently), but safely. + bool found_it = false; + for( unsigned int i=0; i < cell_defaults.custom_data.variables.size() ; i++ ) + { + if( cell_defaults.custom_data.variables[i].name == cell_variables[n] ) + { found_it = true; } + } + if( found_it == false ) + { + cell_defaults.custom_data.add_variable( cell_variables[n] , "none", 0.0 ); + } + + } + + // add the model to the registry of submodels + + submodel_registry.register_model( *this ); +} + +void Submodel_Information::display( std::ostream& os ) +{ + os << "Submodel: " << name << " (Version " << version << ")" << std::endl ; + + os << "\tcell variables: " << std::endl; + for( int n = 0 ; n < cell_variables.size(); n++ ) + { + os << "\t\t" << cell_variables[n] << std::endl; + } + + os << "\tfunction: " ; + if( main_function ) + { os << (long long int) main_function; } + else + { os << "NULL"; } + os << std::endl; + + return; +} + +void Submodel_Registry::register_model( Submodel_Information& model ) +{ + #pragma omp critical + { + // already registered? + bool found = false; + for( int n = 0; n < submodels.size() ; n++ ) + { + if( submodels[n] == &model ) + { found = true; } + } + + if( found == false ) + { + submodels.push_back( &model ); +// add_software_citation(); +// void add_software_citation( std::string name , std::string version, std::string DOI , std::string URL ) + } + } + + return; +} + +void Submodel_Registry::display( std::ostream& os ) +{ + os << "The following submodels are registered: " << std::endl; + os << "=======================================" << std::endl; + for( int n = 0 ; n < submodels.size(); n++ ) + { + submodels[n]->display( os ); + } + os << std::endl; + + return; +} + + + diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/submodel_data_structures.h b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/submodel_data_structures.h new file mode 100644 index 000000000..f69e34102 --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/submodel_data_structures.h @@ -0,0 +1,53 @@ +/* + * submodel_data_structures.h + * + * Created on: ? + * Author: Paul Macklin + * + * Description: + * Auxiliary class to manage submodels + * + * Source: https://github.com/pc4covid19/COVID19/blob/master/PhysiCell/custom_modules/submodel_data_structures.cpp +*/ + + +#include "../core/PhysiCell.h" +#include "../modules/PhysiCell_standard_modules.h" + +using namespace BioFVM; +using namespace PhysiCell; + +#ifndef __submodel_data__ +#define __submodel_data__ + +class Submodel_Information +{ + private: + public: + std::string name; + std::string version; + void(*main_function)(Cell*,Phenotype&,double); + + std::vector< std::string > microenvironment_variables; + std::vector< std::string > cell_variables; // custom data + + Submodel_Information( void ); + + void register_model( void ); + + void display( std::ostream& os ); +}; + +class Submodel_Registry +{ + private: + std::vector submodels; + public: + void register_model( Submodel_Information& model ); + void display( std::ostream& os ); + +}; + +extern Submodel_Registry submodel_registry; + +#endif \ No newline at end of file diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_boolean_model_interface.cpp b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_boolean_model_interface.cpp new file mode 100644 index 000000000..2a4f4abaa --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_boolean_model_interface.cpp @@ -0,0 +1,189 @@ +/* + * tnf_boolean_model_interface.cpp + * + * Created on: 15 jun. 2020 + * Author: Miguel Ponce-de-Leon (miguel.ponce@bsc.es) + * Contributor: Gerard Pradas + * Contributor: Arnau Montagud + * Contributor: Thalia Diniaco + * Cite as: arXiv:2103.14132 [q-bio.QM] + * Description: + * Submodel that work as an interface + * between the Boolean Network (BN) and PhysiCell (PC). + * The submodel run the following steps: + * 1- updates BN input nodes based on custom cell variables (see receptor model) + * 2- updates the BN intracellular model by running MaBoSS + * 3- updates cell state/behaviour based on the state of the BN readout nodes + * + * The update_monitor_variables funtion is just used to keep track of some relevand + * BN nodes' values that are stored as custom variables + */ + + +#include "./tnf_boolean_model_interface.h" + +using namespace PhysiCell; + +Submodel_Information tnf_bm_interface_info; + +void tnf_boolean_model_interface_setup() +{ + tnf_bm_interface_info.name = "TNF Boolean model interface"; + tnf_bm_interface_info.version = "0.2.0"; + + // tnf_bm_interface_info.main_function= update_phenotype_with_signaling; + + // These are just auxiliary variables to keep track of some BN nodes + tnf_bm_interface_info.cell_variables.push_back( "tnf_node" ); + tnf_bm_interface_info.cell_variables.push_back( "fadd_node" ); + tnf_bm_interface_info.cell_variables.push_back( "nfkb_node" ); + + tnf_bm_interface_info.register_model(); +} + +void update_boolean_model_inputs( Cell* pCell, Phenotype& phenotype, double dt ) +{ + static int nR_EB = pCell->custom_data.find_variable_index( "bound_external_TNFR" ); + static int nTNF_threshold = pCell->custom_data.find_variable_index( "TNFR_activation_threshold" ); + + // This if the step transfer function used to update the state of boolean model inputs + // using the state of the receptor dynamics model. The continuos value thresholded is + // the total TNF-recptor complex (doi:10.1016/j.cellsig.2010.08.016) + + if ( pCell->custom_data[nR_EB] >= pCell->custom_data[nTNF_threshold] ){ + + pCell->phenotype.intracellular->set_boolean_variable_value("TNF", 1);} + else + pCell->phenotype.intracellular->set_boolean_variable_value("TNF", 0); + + return; +} + + +/** +void update_cell_from_boolean_model(Cell* pCell, Phenotype& phenotype, double dt) +{ + static int nTNF_external = microenvironment.find_density_index( "tnf" ); + static int nTNF_export_rate = pCell->custom_data.find_variable_index( "TNF_net_production_rate" ); + + static int apoptosis_model_index = phenotype.death.find_death_model_index( "Apoptosis" ); + static int necrosis_model_index = phenotype.death.find_death_model_index( "Necrosis" ); + + // Getting the state of the boolean model readouts (Readout can be in the XML) + bool apoptosis = pCell->phenotype.intracellular->get_boolean_variable_value( "Apoptosis" ); + bool nonACD = pCell->phenotype.intracellular->get_boolean_variable_value( "NonACD" ); + bool survival = pCell->phenotype.intracellular->get_boolean_variable_value( "Survival" ); + bool NFkB = pCell->phenotype.intracellular->get_boolean_variable_value( "NFkB" ); + + if ( apoptosis ) { + pCell->start_death(apoptosis_model_index); + return; + } + + if ( nonACD ) { + pCell->start_death(necrosis_model_index); + return; + } + + if ( survival && pCell->phenotype.cycle.current_phase_index() == PhysiCell_constants::Ki67_negative ) { + pCell->phenotype.cycle.advance_cycle(pCell, phenotype, dt); + } + + // If NFkB node is active produce some TNF + if ( NFkB ) { + double tnf_export_rate = pCell->custom_data[nTNF_export_rate]; + phenotype.secretion.net_export_rates[nTNF_external] = tnf_export_rate; + } else { + phenotype.secretion.net_export_rates[nTNF_external] = 0; + } + + return; +} +*/ + + + +void update_cell_from_boolean_model(Cell* pCell, Phenotype& phenotype, double dt) +{ + + + static int necrosis_index = phenotype.death.find_death_model_index( PhysiCell_constants::necrosis_death_model ); + static int apoptosis_index = phenotype.death.find_death_model_index( PhysiCell_constants::apoptosis_death_model ); + static int cycle_start_index = live.find_phase_index( PhysiCell_constants::live ); + static int cycle_end_index = live.find_phase_index( PhysiCell_constants::live ); + + static int nTNF_external = microenvironment.find_density_index( "tnf" ); + static int nTNF_export_rate = pCell->custom_data.find_variable_index( "TNF_net_production_rate" ); + static int death_decay_idx = pCell->custom_data.find_variable_index( "death_commitment_decay" ); + + + static float necrosis_rate = pCell->custom_data["necrosis_rate"]; + static float apoptosis_rate = pCell->custom_data["apoptosis_rate"]; + static float death_commitment_decay = pCell->custom_data["death_decay_idx"]; + + // Getting the state of the boolean model readouts (Readout can be in the XML) + bool apoptosis = pCell->phenotype.intracellular->get_boolean_variable_value( "Apoptosis" ); + bool nonACD = pCell->phenotype.intracellular->get_boolean_variable_value( "NonACD" ); + bool survival =pCell->phenotype.intracellular->get_boolean_variable_value( "Survival" ); + bool NFkB = pCell->phenotype.intracellular->get_boolean_variable_value( "NFkB" ); + + + if ( apoptosis ) { + // pCell->start_death(apoptosis_index); + phenotype.death.rates[apoptosis_index] = apoptosis_rate; + } else { + phenotype.death.rates[apoptosis_index] -= apoptosis_rate * death_commitment_decay; + if (phenotype.death.rates[apoptosis_index] < 0) + phenotype.death.rates[apoptosis_index] = 0; + } + + if ( nonACD ) { + //myCounter++; + // pCell->start_death(necrosis_index); + phenotype.death.rates[necrosis_index] = necrosis_rate; + } + else { + phenotype.death.rates[necrosis_index] -= necrosis_rate * death_commitment_decay; + if (phenotype.death.rates[necrosis_index] < 0) + phenotype.death.rates[necrosis_index] = 0; + } + + if ( survival && pCell->phenotype.cycle.current_phase_index() == PhysiCell_constants::Ki67_negative ) + { + pCell->phenotype.cycle.advance_cycle(pCell, phenotype, dt); + } + + // If NFkB node is active produce some TNF + if ( NFkB ) + { + phenotype.secretion.net_export_rates[nTNF_external] = pCell->custom_data[nTNF_export_rate]; + } else + { + phenotype.secretion.net_export_rates[nTNF_external] = 0; + } + // update_cell_and_death_parameters_O2_based(pCell, phenotype, dt); + return; +} + + +void update_behaviors(Cell* pCell, Phenotype& phenotype, double dt) +{ + // update the cell fate based on the boolean outputs + update_cell_from_boolean_model(pCell, phenotype, dt); + + // Get track of some boolean node values for debugging + update_monitor_variables(pCell); +} + +void update_monitor_variables(Cell* pCell ) +{ + static int index_tnf_node = pCell->custom_data.find_variable_index("tnf_node"); + static int index_fadd_node = pCell->custom_data.find_variable_index("fadd_node"); + static int index_nfkb_node = pCell->custom_data.find_variable_index("nfkb_node"); + + pCell->custom_data[index_tnf_node] = pCell->phenotype.intracellular->get_boolean_variable_value("TNF"); + pCell->custom_data[index_fadd_node] = pCell->phenotype.intracellular->get_boolean_variable_value("FADD"); + pCell->custom_data[index_nfkb_node] = pCell->phenotype.intracellular->get_boolean_variable_value( "NFkB" ); + + return; +} diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_boolean_model_interface.h b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_boolean_model_interface.h new file mode 100644 index 000000000..9f1432b32 --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_boolean_model_interface.h @@ -0,0 +1,42 @@ +/* + * tnf_boolean_model_interface.cpp + * + * Created on: 15 jun. 2020 + * Author: Miguel Ponce-de-Leon (miguel.ponce@bsc.es) + * Contributor: Gerard Pradas + * Contributor: Arnau Montagud + * Contributor: Thalia Diniaco + * Cite as: arXiv:2103.14132 [q-bio.QM] + * Description: + * Submodel that work as an interface + * between the Boolean Network (BN) and PhysiCell (PC). + * The submodel run the following steps: + * 1- updates BN input nodes based on custom cell variables (see receptor model) + * 2- updates the BN intracellular model by running MaBoSS + * 3- updates cell state/behaviour based on the state of the BN readout nodes + * + * The update_monitor_variables funtion is just used to keep track of some relevand + * BN nodes' values that are stored as custom variables + */ + +#include "../core/PhysiCell.h" +#include "../modules/PhysiCell_standard_modules.h" +#include "../addons/PhysiBoSS/src/maboss_intracellular.h" + +using namespace BioFVM; +using namespace PhysiCell; + +#include "./submodel_data_structures.h" + +void tnf_boolean_model_interface_setup(); + +void update_boolean_model_inputs( Cell* pCell, Phenotype& phenotype, double dt ); + +void update_behaviors(Cell* pCell, Phenotype& phenotype, double dt); + +void update_cell_from_boolean_model(Cell* pCell, Phenotype& phenotype, double dt); + +// helper function to keep updated some cell custom variables +void update_monitor_variables( Cell* pCell ); + +extern int myCounter; diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_receptor_dynamics.cpp b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_receptor_dynamics.cpp new file mode 100644 index 000000000..438095bbb --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_receptor_dynamics.cpp @@ -0,0 +1,143 @@ +/* + * tnf_receptor_dynamics.cpp + * + * Created on: 15 jun. 2020 + * Author: Miguel Ponce-de-Leon (miguel.ponce@bsc.es) + * Contributor: Gerard Pradas + * Contributor: Arnau Montagud + * Contributor: Thalia Diniaco + * Cite as: arXiv:2103.14132 [q-bio.QM] + * Description: + * Simplified model of the TNF receptor (TNFR) dynamics. The models has threed states: + * 1- TNFR unbounded (exposed to the extracellular space) + * 2- TNFR with a TNF bounded + * 3- TNFR with a TNF bounded internalized to be recycled by removeing the TNF ligand. + * + * It is an ODE-based model that has the following equations + * d[unbound_external_TNFR]/dt = TNFR_recycling_rate * [bound_internal_TNFR] - TNFR_binding_rate * [unbound_external_TNFR] * [TNF] + * d[bound_external_TNFR]/dt = NFR_binding_rate * [unbound_external_TNFR] * [TNF] - TNFR_endocytosis_rate * [bound_external_TNFR] + * d[bound_internal_TNFR]/dt = TNFR_endocytosis_rate * [bound_external_TNFR] - TNFR_recycling_rate * [bound_internal_TNFR] + */ + +#include "./tnf_receptor_dynamics.h" + +using namespace PhysiCell; + +Submodel_Information tnf_receptor_info; + +void tnf_receptor_model_setup() +{ + tnf_receptor_info.name = "TNF trasnporter model"; + tnf_receptor_info.version = "0.1.0"; + + tnf_receptor_info.main_function = tnf_receptor_model; + + // what custom data do I need? + tnf_receptor_info.cell_variables.push_back( "TNFR_activation_threshold" ); + + tnf_receptor_info.cell_variables.push_back( "unbound_external_TNFR" ); + tnf_receptor_info.cell_variables.push_back( "bound_external_TNFR" ); + tnf_receptor_info.cell_variables.push_back( "bound_internal_TNFR" ); + + tnf_receptor_info.cell_variables.push_back( "TNFR_binding_rate" ); + tnf_receptor_info.cell_variables.push_back( "TNFR_endocytosis_rate" ); + tnf_receptor_info.cell_variables.push_back( "TNFR_recycling_rate" ); + tnf_receptor_info.cell_variables.push_back( "TNF_net_production_rate" ); + + tnf_receptor_info.register_model(); + + return; +} + +void tnf_receptor_model( Cell* pCell, Phenotype& phenotype, double dt ) +{ + static int nTNF_external = microenvironment.find_density_index( "tnf" ); + + static int nR_EU = pCell->custom_data.find_variable_index( "unbound_external_TNFR" ); + static int nR_EB = pCell->custom_data.find_variable_index( "bound_external_TNFR" ); + static int nR_IB = pCell->custom_data.find_variable_index( "bound_internal_TNFR" ); + + static int nR_bind = pCell->custom_data.find_variable_index( "TNFR_binding_rate" ); + static double R_binding_rate = pCell->custom_data[nR_bind]; + + static int nR_endo = pCell->custom_data.find_variable_index( "TNFR_endocytosis_rate" ); + static double R_endo_rate = pCell->custom_data[nR_endo]; + + static int nR_recycle = pCell->custom_data.find_variable_index( "TNFR_recycling_rate" ); + static double R_recyc_rate = pCell->custom_data[nR_recycle]; + + + if( phenotype.death.dead == true ) + { return; } + + // internalized TNF tells us how many have recently bound to receptors + // TNF is internalized at: + // phenotype.secretion.uptake_rates[nTNF_external] = + // pCell->custom_data[nR_bind] * pCell->custom_data[nR_EU]; + + // The internalization is only used to track the TNF + // The following part of the code takes care of correcly managed + double dR_EB = phenotype.molecular.internalized_total_substrates[nTNF_external]; + //std::cout << "nTNF_external: " << nTNF_external << std::endl; + //std::cout << "dR_EB: " << dR_EB << std::endl; + + // if it tries to bind more TNF than there are receptors, compensate + if( dR_EB > pCell->custom_data[nR_EU] ) + { + double excess_binding = dR_EB - pCell->custom_data[nR_EU]; + dR_EB = pCell->custom_data[nR_EU]; + // dump any excess back into the microenvironment + static double to_density = 1.0 / microenvironment.mesh.dV; + // this needs omp critical because 2 cells writing to 1 voxel is not thread safe + #pragma omp critical + { pCell->nearest_density_vector()[nTNF_external] += excess_binding * to_density; } + } + + // Remove all the internalized TNF from cell + phenotype.molecular.internalized_total_substrates[nTNF_external] = 0.0; + + // Endocytosis + // The bounded receptor is internalized at a rate R_endo_rate + double dR_IB = dt * R_endo_rate * pCell->custom_data[nR_EB]; + if( dR_IB > pCell->custom_data[nR_EB] ) + { dR_IB = pCell->custom_data[nR_EB]; } + + // Recylcing + // The internalized bounded TNFR release the TNF + // The TNF is instantaneously degraded by the cell + // The TNF receptor is recycled as an unbounded external receptor + double dR_EU = dt * R_recyc_rate * pCell->custom_data[nR_IB]; + if( dR_EU > pCell->custom_data[nR_IB] ) + { dR_EU = pCell->custom_data[nR_IB]; } + + pCell->custom_data[nR_EU] -= dR_EB; // remove newly bound receptor from R_EU + pCell->custom_data[nR_EB] += dR_EB; // add newly bound receptor to R_EB + + pCell->custom_data[nR_EB] -= dR_IB; // move from external bound + pCell->custom_data[nR_IB] += dR_IB; // move to internal bound + + pCell->custom_data[nR_IB] -= dR_EU; // move from internal unbound + pCell->custom_data[nR_EU] += dR_EU; // move to external unbound + + // update the TNF uptake rate + //std::cout << "uptake_pre: " << phenotype.secretion.uptake_rates[nTNF_external] << std::endl; + phenotype.secretion.uptake_rates[nTNF_external] = R_binding_rate * pCell->custom_data[nR_EU]; + //std::cout << "uptake_post: " << phenotype.secretion.uptake_rates[nTNF_external] << std::endl; + + return; +} + +void tnf_receptor_model_main( double dt ) +{ + #pragma omp parallel for + for( int i=0; i < (*all_cells).size() ; i++ ) + { + Cell* pC = (*all_cells)[i]; + if ( pC->is_out_of_domain ) + { continue; } + if( pC->phenotype.death.dead ) + { continue; } + tnf_receptor_model( pC, pC->phenotype , dt ); + } + return; +} \ No newline at end of file diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_receptor_dynamics.h b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_receptor_dynamics.h new file mode 100644 index 000000000..962ff19bc --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/custom_modules/tnf_receptor_dynamics.h @@ -0,0 +1,39 @@ +/* + * tnf_receptor_dynamics.cpp + * + * Created on: 15 jun. 2020 + * Author: Miguel Ponce-de-Leon + * Contributor: Thalia Diniaco + * Created on: 15 jun. 2020 + * Author: Miguel Ponce-de-Leon (miguel.ponce@bsc.es) + * Contributor: Gerard Pradas + * Contributor: Arnau Montagud + * Contributor: Thalia Diniaco + * Cite as: arXiv:2103.14132 [q-bio.QM] + * Description: + * SSimplified model of the TNF receptor (TNFR) dynamics. The models has threed states: + * 1- TNFR unbounded (exposed to the extracellular space) + * 2- TNFR with a TNF bounded + * 3- TNFR with a TNF bounded internalized to be recycled by removeing the TNF ligand. + * + * It is an ODE-based model that has the following equations + * d[unbound_external_TNFR]/dt = TNFR_recycling_rate * [bound_internal_TNFR] - TNFR_binding_rate * [unbound_external_TNFR] * [TNF] + * d[bound_external_TNFR]/dt = NFR_binding_rate * [unbound_external_TNFR] * [TNF] - TNFR_endocytosis_rate * [bound_external_TNFR] + * d[bound_internal_TNFR]/dt = TNFR_endocytosis_rate * [bound_external_TNFR] - TNFR_recycling_rate * [bound_internal_TNFR] + * + * Cite as: arXiv:2103.14132 [q-bio.QM] + */ + +#include "../core/PhysiCell.h" +#include "../modules/PhysiCell_standard_modules.h" + +using namespace BioFVM; +using namespace PhysiCell; + +#include "./submodel_data_structures.h" + +void tnf_receptor_model_setup(); + +void tnf_receptor_model( Cell* pCell, Phenotype& phenotype, double dt ); + +void tnf_receptor_model_main( double dt ); diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/main-spheroid_TNF.cpp b/sample_projects_intracellular/boolean/spheroid_tnf_model/main-spheroid_TNF.cpp new file mode 100644 index 000000000..29f2d6d7a --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/main-spheroid_TNF.cpp @@ -0,0 +1,393 @@ +/* +############################################################################### +# If you use PhysiCell in your project, please cite PhysiCell and the version # +# number, such as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1]. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# See VERSION.txt or call get_PhysiCell_version() to get the current version # +# x.y.z. Call display_citations() to get detailed information on all cite-# +# able software used in your PhysiCell application. # +# # +# Because PhysiCell extensively uses BioFVM, we suggest you also cite BioFVM # +# as below: # +# # +# We implemented and solved the model using PhysiCell (Version x.y.z) [1], # +# with BioFVM [2] to solve the transport equations. # +# # +# [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, # +# PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- # +# lar Systems, PLoS Comput. Biol. 14(2): e1005991, 2018 # +# DOI: 10.1371/journal.pcbi.1005991 # +# # +# [2] A Ghaffarizadeh, SH Friedman, and P Macklin, BioFVM: an efficient para- # +# llelized diffusive transport solver for 3-D biological simulations, # +# Bioinformatics 32(8): 1256-8, 2016. DOI: 10.1093/bioinformatics/btv730 # +# # +############################################################################### +# # +# BSD 3-Clause License (see https://opensource.org/licenses/BSD-3-Clause) # +# # +# Copyright (c) 2015-2018, Paul Macklin and the PhysiCell Project # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are met: # +# # +# 1. Redistributions of source code must retain the above copyright notice, # +# this list of conditions and the following disclaimer. # +# # +# 2. Redistributions in binary form must reproduce the above copyright # +# notice, this list of conditions and the following disclaimer in the # +# documentation and/or other materials provided with the distribution. # +# # +# 3. Neither the name of the copyright holder nor the names of its # +# contributors may be used to endorse or promote products derived from this # +# software without specific prior written permission. # +# # +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # +# POSSIBILITY OF SUCH DAMAGE. # +# # +############################################################################### +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "./core/PhysiCell.h" +#include "./core/PhysiCell_utilities.h" +#include "./modules/PhysiCell_standard_modules.h" +#include "./addons/PhysiBoSS/src/maboss_intracellular.h" +#include "./custom_modules/custom.h" + +using namespace BioFVM; +using namespace PhysiCell; + +int main( int argc, char* argv[] ) +{ + // load and parse settings file(s) + std::ofstream file_resistant("output/resistant_cells.txt", std::ios::app); + + bool XML_status = false; + char copy_command [1024]; + if( argc > 1 ) + { + XML_status = load_PhysiCell_config_file( argv[1] ); + sprintf( copy_command , "cp %s %s" , argv[1] , PhysiCell_settings.folder.c_str() ); + } + else + { + XML_status = load_PhysiCell_config_file( "./config/PhysiCell_settings.xml" ); + sprintf( copy_command , "cp ./config/PhysiCell_settings.xml %s" , PhysiCell_settings.folder.c_str() ); + } + if( !XML_status ) + { exit(-1); } + + // copy config file to output directry + system( copy_command ); + + // OpenMP setup + omp_set_num_threads(PhysiCell_settings.omp_num_threads); + + // PNRG setup + SeedRandom(); // or specify a seed here + + // time setup + std::string time_units = "min"; + + /* Microenvironment setup */ + + setup_microenvironment(); // modify this in the custom code + + bool start_stop = parameters.bools("start_stop"); + if( start_stop ){ + + // reset microenvironment and cells as they were in the previous simulation + reset_microenv(); + } + + + // User parameters + + double tnf_pulse_period = parameters.doubles("tnf_pulse_period"); + double tnf_pulse_duration = parameters.doubles("tnf_pulse_duration"); + double tnf_pulse_concentration = parameters.doubles("tnf_pulse_concentration"); + double time_remove_tnf = parameters.doubles("time_remove_tnf"); + double membrane_lenght = parameters.doubles("membrane_length"); // radious around which the tnf pulse is injected + + + double tnf_pulse_timer = tnf_pulse_period; + double tnf_pulse_injection_timer = tnf_pulse_duration; // tnf_pulse_duration; // -1; + static int tnf_idx = microenvironment.find_density_index("tnf"); + + + /* PhysiCell setup */ + + // set mechanics voxel size, and match the data structure to BioFVM + double mechanics_voxel_size = 30; + Cell_Container* cell_container = create_cell_container_for_microenvironment( microenvironment, mechanics_voxel_size ); + + /* Users typically start modifying here. START USERMODS */ + create_cell_types(); + + + if( start_stop ){ + + + parameters.bools("read_init") = true; + + // reset cells as they were in the previous simulation + setup_tissue(); + + reset_cell(cell_container->last_cell_cycle_time); + + //exit(-1); + + + reset_global_parameters(cell_container); + + update_variables_monitor(); + + + } else{ + setup_tissue(); //death model index = 1 == necrotic...= 0 == apoptotic. + } + + + // check if we want to start injecting tnf + if(parameters.bools("if_start_inj")){ + + tnf_pulse_timer = PhysiCell_globals.current_time; + + }else{ + + tnf_pulse_timer = PhysiCell_globals.current_time + tnf_pulse_period; + } + + + // set MultiCellDS save options + + set_save_biofvm_mesh_as_matlab( true ); + set_save_biofvm_data_as_matlab( true ); + set_save_biofvm_cell_data( true ); + set_save_biofvm_cell_data_as_custom_matlab( true ); + + // save a simulation snapshot + + char filename[1024]; + sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); + + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); + + sprintf( filename , "%s/states_initial.csv", PhysiCell_settings.folder.c_str()); + MaBoSSIntracellular::save(filename); + + // save a quick SVG cross section through z = 0, after setting its + // length bar to 200 microns + + PhysiCell_SVG_options.length_bar = 200; + + // for simplicity, set a pathology coloring function + + std::vector (*cell_coloring_function)(Cell*) = my_coloring_function; + + sprintf( filename , "%s/initial.svg" , PhysiCell_settings.folder.c_str() ); + SVG_plot( filename , microenvironment, 0.0 , PhysiCell_globals.current_time, cell_coloring_function ); + + sprintf( filename , "%s/legend.svg" , PhysiCell_settings.folder.c_str() ); + create_plot_legend( filename , cell_coloring_function ); + + add_software_citation( "PhysiBoSS" , PhysiBoSS_Version , PhysiBoSS_DOI, PhysiBoSS_URL); + + display_citations(); + + // set the performance timers + BioFVM::RUNTIME_TIC(); + BioFVM::TIC(); + + std::ofstream report_file; + if( PhysiCell_settings.enable_legacy_saves == true ) + { + sprintf( filename , "%s/simulation_report.txt" , PhysiCell_settings.folder.c_str() ); + + report_file.open(filename); // create the data log file + report_file<<"simulated time\tnum cells\tnum division\tnum death\twall time"<= tnf_pulse_timer ) + { + tnf_pulse_injection_timer = PhysiCell_globals.current_time + tnf_pulse_duration; + tnf_pulse_timer += tnf_pulse_period; + } + + if ( PhysiCell_globals.current_time <= tnf_pulse_injection_timer ) + { + + inject_density_sphere(tnf_idx, tnf_pulse_concentration, membrane_lenght); + + } + + if ( PhysiCell_globals.current_time >= time_remove_tnf ) + { + + remove_density(tnf_idx); + time_remove_tnf += PhysiCell_settings.max_time; + } + + + + // update the microenvironment + microenvironment.simulate_diffusion_decay( diffusion_dt ); + + // update te TNF receptor model of each cell + tnf_receptor_model_main( diffusion_dt ); + + // run PhysiCell + ((Cell_Container *)microenvironment.agent_container)->update_all_cells( PhysiCell_globals.current_time ); + + PhysiCell_globals.current_time += diffusion_dt; + } + + if( PhysiCell_settings.enable_legacy_saves == true ) + { + log_output(PhysiCell_globals.current_time, PhysiCell_globals.full_output_index, microenvironment, report_file); + report_file.close(); + } + } + catch( const std::exception& e ) + { // reference to the base of a polymorphic object + std::cout << e.what(); // information from length_error printed + } + + // save a final simulation snapshot + + sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); + + sprintf( filename , "%s/states_final.csv", PhysiCell_settings.folder.c_str()); + MaBoSSIntracellular::save(filename); + + sprintf( filename , "%s/final.svg" , PhysiCell_settings.folder.c_str() ); + SVG_plot( filename , microenvironment, 0.0 , PhysiCell_globals.current_time, cell_coloring_function ); + + + // timer + + std::cout << std::endl << "Total simulation runtime: " << std::endl; + BioFVM::display_stopwatch_value( std::cout , BioFVM::runtime_stopwatch_value() ); + + file_resistant.close(); + + return 0; +} diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/params/cell_phases_dict.json b/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/params/cell_phases_dict.json new file mode 100644 index 000000000..cf11a01b2 --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/params/cell_phases_dict.json @@ -0,0 +1,23 @@ +{ + "0": "Ki67_positive_premitotic", + "1": "Ki67_positive_postmitotic", + "2": "Ki67_positive", + "3": "Ki67_negative", + "4": "G0G1_phase", + "5": "G0_phase", + "6": "G1_phase", + "7": "G1a_phase", + "8": "G1b_phase", + "9": "G1c_phase", + "10": "S_phase", + "11": "G2M_phase", + "12": "G2_phase", + "13": "M_phase", + "14": "live", + "100": "apoptotic", + "101": "necrotic_swelling", + "102": "necrotic_lysed", + "103": "necrotic", + "104": "debris" + } + \ No newline at end of file diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/params/phases_grouping_dict.json b/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/params/phases_grouping_dict.json new file mode 100644 index 000000000..665b84844 --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/params/phases_grouping_dict.json @@ -0,0 +1,20 @@ +{ + "Ki67_positive_premitotic": "alive", + "Ki67_positive_postmitotic": "alive", + "Ki67_positive": "alive", + "Ki67_negative": "alive", + "G0G1_phase": "alive", + "G0_phase": "alive", + "G1_phase": "alive", + "G1a_phase": "alive", + "G1b_phase": "alive", + "G1c_phase": "alive", + "S_phase": "alive", + "G2M_phase": "alive", + "G2_phase": "alive", + "M_phase": "alive", + "live": "alive", + "apoptotic": "apoptotic", + "necrotic_lysed": "necrotic", + "necrotic_swelling": "necrotic" +} diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/plot_time_course.py b/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/plot_time_course.py new file mode 100644 index 000000000..496a9e3ad --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/plot_time_course.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + + +import sys +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import seaborn as sns + + + + +from pctk.multicellds import MultiCellDS + + +def labelsubplot(ax, idx, xpos=-0.1, ypos=1.05, weight="bold", fontsize=12, color='#434343'): + a_ascci_idx = ord('a') + subplot_label = chr(a_ascci_idx+idx) + ')' + box_aspect = ax.get_box_aspect() + if box_aspect is not None and len(box_aspect) == 3: + ax.text2D(xpos, ypos, subplot_label, weight="bold", ha='left', va='center', + fontsize=fontsize, color=color, transform=ax.transAxes) + else: + ax.text(xpos, ypos, subplot_label, weight="bold", ha='left', va='center', + fontsize=fontsize, color=color, transform=ax.transAxes) + + + + +def get_timeserie_mean(mcds, filter_alive=True): + time = [] + values = [] + filter_alive = True + for t, df in mcds.cells_as_frames_iterator(): + time.append(t) + df = df.iloc[:,3:] + if filter_alive: + mask = df['current_phase'] <= 14 + df = df[mask] + values.append(df.mean(axis=0).values) + + cell_columns = df.columns.tolist() + df = pd.DataFrame(values, columns=cell_columns) + df['time'] = time + return df[['time'] + cell_columns] + + +def get_timeserie_density(mcds): + data = [] + for t,m in mcds.microenvironment_as_matrix_iterator(): + data.append((t, m[5,:].sum())) + df = pd.DataFrame(data=data, columns=['time', 'tnf']) + return df + +def plot_molecular_model(df_cell_variables, list_of_variables, ax1): + + for label in list_of_variables: + y = df_cell_variables[label] + time = df_cell_variables["time"] + ax1.plot(time, y, label="% " + label) + + ax1.set_ylabel("% X") + ax1.yaxis.grid(True) + ax1.set_xlim((0, time.values[-1])) + ax1.set_ylim((0, 1.05)) + + +def plot_cells(df_time_course, color_dict, ax): + + # Alive/Apoptotic/Necrotic vs Time + for k in color_dict: + ax.plot(df_time_course.time, df_time_course[k], "-", c=color_dict[k], label=k) + + # setting axes labels + # ax.set_xlabel("time (min)") + ax.set_ylabel("N of cells") + + # Showing legend + ax.legend() + ax.yaxis.grid(True) + + +def plot_time_course(df_time_course, df_time_tnf, df_cell_variables, list_of_variables): + fig, axes = plt.subplots(2, 1, figsize=(10,4), dpi=300, sharex=True) + + custom_palette = sns.color_palette("deep") + color_dict = {"live": custom_palette[2], "apoptotic": custom_palette[3], "necrotic":custom_palette[5]} + + plot_cells(df_time_course, color_dict, axes[0]) + + for i,ax in enumerate(axes): + labelsubplot(ax, i, xpos=-0.065) + + ax2 = axes[0].twinx() + ax2.plot(df_time_tnf.time, df_time_tnf['tnf'], 'lightgrey') + + ax2.set_yticks([]) + ax2.fill_between(df_time_tnf.time, df_time_tnf['tnf'], color='lightgrey', alpha=0.3) + + axes[0].set_zorder(ax2.get_zorder()+1) + axes[0].patch.set_visible(False) + + plot_molecular_model(df_cell_variables, list_of_variables, axes[1]) + threshold = 0.5 + + axes[1].hlines(threshold, 0, df_time_course.time.iloc[-1]) + axes[1].legend(loc="upper left") + axes[1].set_xlabel("Time (min)") + + + fig.tight_layout() + sns.despine(fig) + + return fig + +def load_datasets(instance_folder, labels_dict): + + + mcds = MultiCellDS(instance_folder) + + df_time_course = mcds.get_cells_summary_frame() + df_time_tnf = get_timeserie_density(mcds) + df_cell_variables = get_timeserie_mean(mcds) + df_cell_variables = df_cell_variables.rename(labels_dict, axis=1) + + if (df_time_course["live"] == 0).sum() > 0: + idx = df_time_course.index[df_time_course["live"] == 0][0] + df_time_course = df_time_course.iloc[:idx] + df_cell_variables = df_cell_variables.iloc[:idx] + df_time_tnf = df_time_tnf.iloc[:idx] + + return df_time_course, df_time_tnf, df_cell_variables + + +sns.set_style("white") +sns.set_palette("deep") + + +def main(): + if len(sys.argv) == 1: + output_folder = "output" + else: + output_folder = sys.argv[1] + + + labels_dict = {} + labels_dict['bound_external_TNFR'] = "TNFR-TNF[e]" + labels_dict['unbound_external_TNFR'] = "TNFR[e]" + labels_dict['bound_internal_TNFR'] = "TNFR-TNF[i]" + df_time_course, df_time_tnf, df_cell_variables = load_datasets(output_folder, labels_dict) + + list_of_variables = list(labels_dict.values()) + fig = plot_time_course(df_time_course, df_time_tnf, df_cell_variables, list_of_variables) + + fig.savefig(f"{output_folder}/Time_course.png") + + +main() \ No newline at end of file diff --git a/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/summarize_simulation.py b/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/summarize_simulation.py new file mode 100755 index 000000000..98a0a160f --- /dev/null +++ b/sample_projects_intracellular/boolean/spheroid_tnf_model/scripts/summarize_simulation.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# coding: utf-8 + +import re +import os +import sys +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + + +from pctk.multicellds import MultiCellDS + +def get_timeserie_mean(mcds, filter_alive=True): + time = [] + values = [] + filter_alive = True + for t, df in mcds.cells_as_frames_iterator(): + time.append(t) + df = df.iloc[:,3:] + if filter_alive: + mask = df['current_phase'] <= 14 + df = df[mask] + values.append(df.mean(axis=0).values) + + cell_columns = df.columns.tolist() + df = pd.DataFrame(values, columns=cell_columns) + df['time'] = time + return df[['time'] + cell_columns] + + +def get_timeserie_density(mcds): + data = [] + for t,m in mcds.microenvironment_as_matrix_iterator(): + data.append((t, m[5,:].sum())) + df = pd.DataFrame(data=data, columns=['time', 'tnf']) + return df + +def plot_molecular_model(df_cell_variables, list_of_variables, ax1): + + threshold = 0.5 + + for label in list_of_variables: + y = df_cell_variables[label] + time = df_cell_variables["time"] + ax1.plot(time, y, label="% X " + label) + + ax1.set_ylabel("% X") + ax1.yaxis.grid(True) + ax1.set_xlim((0,time.values[-1])) + ax1.set_ylim((0,1)) + # ax1.set_xlabel("time (min)") + +def plot_cells(df_time_course, color_dict, ax): + + # Alive/Apoptotic/Necrotic vs Time + for k in color_dict: + ax.plot(df_time_course.time, df_time_course[k], "-", c=color_dict[k], label=k) + + # setting axes labels + # ax.set_xlabel("time (min)") + ax.set_ylabel("Nº of cells") + + # Showing legend + ax.legend() + ax.yaxis.grid(True) + +def main(): + + color_dict = {"alive": "g", "apoptotic": "r", "necrotic":"k"} + + + output_folder = sys.argv[1] + + mcds = MultiCellDS(output_folder=output_folder) + + df_time_course = mcds.get_cells_summary_frame() + df_cell_variables = get_timeserie_mean(mcds) + df_time_tnf = get_timeserie_density(mcds) + + # df_time_course.to_csv(instance_folder + "time_course.tsv", sep="\t") + # df_cell_variables.to_csv(instance_folder + "cell_variables.tsv", sep="\t") + # df_time_tnf.to_csv(instance_folder + "tnf_time.tsv", sep="\t") + + fig, axes = plt.subplots(3, 1, figsize=(12,12), dpi=150, sharex=True) + plot_cells(df_time_course, color_dict, axes[0]) + + list_of_variables = ['bound_external_TNFR', 'unbound_external_TNFR', 'bound_internal_TNFR'] + plot_molecular_model(df_cell_variables, list_of_variables, axes[1]) + threshold = 0.5 + + axes[1].hlines(threshold, 0, df_time_course.time.iloc[-1], label="Activation threshold") + ax2 = axes[1].twinx() + ax2.plot(df_time_tnf.time, df_time_tnf['tnf'], 'r', label="[TNF]") + ax2.set_ylabel("[TNF]") + # ax2.set_ylim([0, 1000]) + axes[1].legend(loc="upper left") + ax2.legend(loc="upper right") + + list_of_variables = ['tnf_node', 'nfkb_node', 'fadd_node'] + plot_molecular_model(df_cell_variables, list_of_variables, axes[2]) + axes[2].set_xlabel("time (min)") + ax2 = axes[2].twinx() + ax2.plot(df_time_tnf.time, df_time_tnf['tnf'], 'r', label="[TNF]") + ax2.set_ylabel("[TNF]") + ax2.set_ylim([0, 1000]) + axes[2].legend(loc="upper left") + ax2.legend(loc="upper right") + + fig.tight_layout() + fig.savefig('variables_vs_time.png') + +main() diff --git a/scripts/params/cell_phases_dict.json b/scripts/params/cell_phases_dict.json new file mode 100644 index 000000000..cf11a01b2 --- /dev/null +++ b/scripts/params/cell_phases_dict.json @@ -0,0 +1,23 @@ +{ + "0": "Ki67_positive_premitotic", + "1": "Ki67_positive_postmitotic", + "2": "Ki67_positive", + "3": "Ki67_negative", + "4": "G0G1_phase", + "5": "G0_phase", + "6": "G1_phase", + "7": "G1a_phase", + "8": "G1b_phase", + "9": "G1c_phase", + "10": "S_phase", + "11": "G2M_phase", + "12": "G2_phase", + "13": "M_phase", + "14": "live", + "100": "apoptotic", + "101": "necrotic_swelling", + "102": "necrotic_lysed", + "103": "necrotic", + "104": "debris" + } + \ No newline at end of file diff --git a/scripts/params/phases_grouping_dict.json b/scripts/params/phases_grouping_dict.json new file mode 100644 index 000000000..665b84844 --- /dev/null +++ b/scripts/params/phases_grouping_dict.json @@ -0,0 +1,20 @@ +{ + "Ki67_positive_premitotic": "alive", + "Ki67_positive_postmitotic": "alive", + "Ki67_positive": "alive", + "Ki67_negative": "alive", + "G0G1_phase": "alive", + "G0_phase": "alive", + "G1_phase": "alive", + "G1a_phase": "alive", + "G1b_phase": "alive", + "G1c_phase": "alive", + "S_phase": "alive", + "G2M_phase": "alive", + "G2_phase": "alive", + "M_phase": "alive", + "live": "alive", + "apoptotic": "apoptotic", + "necrotic_lysed": "necrotic", + "necrotic_swelling": "necrotic" +} diff --git a/scripts/plot_time_course.py b/scripts/plot_time_course.py new file mode 100644 index 000000000..496a9e3ad --- /dev/null +++ b/scripts/plot_time_course.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + + +import sys +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import seaborn as sns + + + + +from pctk.multicellds import MultiCellDS + + +def labelsubplot(ax, idx, xpos=-0.1, ypos=1.05, weight="bold", fontsize=12, color='#434343'): + a_ascci_idx = ord('a') + subplot_label = chr(a_ascci_idx+idx) + ')' + box_aspect = ax.get_box_aspect() + if box_aspect is not None and len(box_aspect) == 3: + ax.text2D(xpos, ypos, subplot_label, weight="bold", ha='left', va='center', + fontsize=fontsize, color=color, transform=ax.transAxes) + else: + ax.text(xpos, ypos, subplot_label, weight="bold", ha='left', va='center', + fontsize=fontsize, color=color, transform=ax.transAxes) + + + + +def get_timeserie_mean(mcds, filter_alive=True): + time = [] + values = [] + filter_alive = True + for t, df in mcds.cells_as_frames_iterator(): + time.append(t) + df = df.iloc[:,3:] + if filter_alive: + mask = df['current_phase'] <= 14 + df = df[mask] + values.append(df.mean(axis=0).values) + + cell_columns = df.columns.tolist() + df = pd.DataFrame(values, columns=cell_columns) + df['time'] = time + return df[['time'] + cell_columns] + + +def get_timeserie_density(mcds): + data = [] + for t,m in mcds.microenvironment_as_matrix_iterator(): + data.append((t, m[5,:].sum())) + df = pd.DataFrame(data=data, columns=['time', 'tnf']) + return df + +def plot_molecular_model(df_cell_variables, list_of_variables, ax1): + + for label in list_of_variables: + y = df_cell_variables[label] + time = df_cell_variables["time"] + ax1.plot(time, y, label="% " + label) + + ax1.set_ylabel("% X") + ax1.yaxis.grid(True) + ax1.set_xlim((0, time.values[-1])) + ax1.set_ylim((0, 1.05)) + + +def plot_cells(df_time_course, color_dict, ax): + + # Alive/Apoptotic/Necrotic vs Time + for k in color_dict: + ax.plot(df_time_course.time, df_time_course[k], "-", c=color_dict[k], label=k) + + # setting axes labels + # ax.set_xlabel("time (min)") + ax.set_ylabel("N of cells") + + # Showing legend + ax.legend() + ax.yaxis.grid(True) + + +def plot_time_course(df_time_course, df_time_tnf, df_cell_variables, list_of_variables): + fig, axes = plt.subplots(2, 1, figsize=(10,4), dpi=300, sharex=True) + + custom_palette = sns.color_palette("deep") + color_dict = {"live": custom_palette[2], "apoptotic": custom_palette[3], "necrotic":custom_palette[5]} + + plot_cells(df_time_course, color_dict, axes[0]) + + for i,ax in enumerate(axes): + labelsubplot(ax, i, xpos=-0.065) + + ax2 = axes[0].twinx() + ax2.plot(df_time_tnf.time, df_time_tnf['tnf'], 'lightgrey') + + ax2.set_yticks([]) + ax2.fill_between(df_time_tnf.time, df_time_tnf['tnf'], color='lightgrey', alpha=0.3) + + axes[0].set_zorder(ax2.get_zorder()+1) + axes[0].patch.set_visible(False) + + plot_molecular_model(df_cell_variables, list_of_variables, axes[1]) + threshold = 0.5 + + axes[1].hlines(threshold, 0, df_time_course.time.iloc[-1]) + axes[1].legend(loc="upper left") + axes[1].set_xlabel("Time (min)") + + + fig.tight_layout() + sns.despine(fig) + + return fig + +def load_datasets(instance_folder, labels_dict): + + + mcds = MultiCellDS(instance_folder) + + df_time_course = mcds.get_cells_summary_frame() + df_time_tnf = get_timeserie_density(mcds) + df_cell_variables = get_timeserie_mean(mcds) + df_cell_variables = df_cell_variables.rename(labels_dict, axis=1) + + if (df_time_course["live"] == 0).sum() > 0: + idx = df_time_course.index[df_time_course["live"] == 0][0] + df_time_course = df_time_course.iloc[:idx] + df_cell_variables = df_cell_variables.iloc[:idx] + df_time_tnf = df_time_tnf.iloc[:idx] + + return df_time_course, df_time_tnf, df_cell_variables + + +sns.set_style("white") +sns.set_palette("deep") + + +def main(): + if len(sys.argv) == 1: + output_folder = "output" + else: + output_folder = sys.argv[1] + + + labels_dict = {} + labels_dict['bound_external_TNFR'] = "TNFR-TNF[e]" + labels_dict['unbound_external_TNFR'] = "TNFR[e]" + labels_dict['bound_internal_TNFR'] = "TNFR-TNF[i]" + df_time_course, df_time_tnf, df_cell_variables = load_datasets(output_folder, labels_dict) + + list_of_variables = list(labels_dict.values()) + fig = plot_time_course(df_time_course, df_time_tnf, df_cell_variables, list_of_variables) + + fig.savefig(f"{output_folder}/Time_course.png") + + +main() \ No newline at end of file diff --git a/scripts/summarize_simulation.py b/scripts/summarize_simulation.py new file mode 100755 index 000000000..98a0a160f --- /dev/null +++ b/scripts/summarize_simulation.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# coding: utf-8 + +import re +import os +import sys +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + + +from pctk.multicellds import MultiCellDS + +def get_timeserie_mean(mcds, filter_alive=True): + time = [] + values = [] + filter_alive = True + for t, df in mcds.cells_as_frames_iterator(): + time.append(t) + df = df.iloc[:,3:] + if filter_alive: + mask = df['current_phase'] <= 14 + df = df[mask] + values.append(df.mean(axis=0).values) + + cell_columns = df.columns.tolist() + df = pd.DataFrame(values, columns=cell_columns) + df['time'] = time + return df[['time'] + cell_columns] + + +def get_timeserie_density(mcds): + data = [] + for t,m in mcds.microenvironment_as_matrix_iterator(): + data.append((t, m[5,:].sum())) + df = pd.DataFrame(data=data, columns=['time', 'tnf']) + return df + +def plot_molecular_model(df_cell_variables, list_of_variables, ax1): + + threshold = 0.5 + + for label in list_of_variables: + y = df_cell_variables[label] + time = df_cell_variables["time"] + ax1.plot(time, y, label="% X " + label) + + ax1.set_ylabel("% X") + ax1.yaxis.grid(True) + ax1.set_xlim((0,time.values[-1])) + ax1.set_ylim((0,1)) + # ax1.set_xlabel("time (min)") + +def plot_cells(df_time_course, color_dict, ax): + + # Alive/Apoptotic/Necrotic vs Time + for k in color_dict: + ax.plot(df_time_course.time, df_time_course[k], "-", c=color_dict[k], label=k) + + # setting axes labels + # ax.set_xlabel("time (min)") + ax.set_ylabel("Nº of cells") + + # Showing legend + ax.legend() + ax.yaxis.grid(True) + +def main(): + + color_dict = {"alive": "g", "apoptotic": "r", "necrotic":"k"} + + + output_folder = sys.argv[1] + + mcds = MultiCellDS(output_folder=output_folder) + + df_time_course = mcds.get_cells_summary_frame() + df_cell_variables = get_timeserie_mean(mcds) + df_time_tnf = get_timeserie_density(mcds) + + # df_time_course.to_csv(instance_folder + "time_course.tsv", sep="\t") + # df_cell_variables.to_csv(instance_folder + "cell_variables.tsv", sep="\t") + # df_time_tnf.to_csv(instance_folder + "tnf_time.tsv", sep="\t") + + fig, axes = plt.subplots(3, 1, figsize=(12,12), dpi=150, sharex=True) + plot_cells(df_time_course, color_dict, axes[0]) + + list_of_variables = ['bound_external_TNFR', 'unbound_external_TNFR', 'bound_internal_TNFR'] + plot_molecular_model(df_cell_variables, list_of_variables, axes[1]) + threshold = 0.5 + + axes[1].hlines(threshold, 0, df_time_course.time.iloc[-1], label="Activation threshold") + ax2 = axes[1].twinx() + ax2.plot(df_time_tnf.time, df_time_tnf['tnf'], 'r', label="[TNF]") + ax2.set_ylabel("[TNF]") + # ax2.set_ylim([0, 1000]) + axes[1].legend(loc="upper left") + ax2.legend(loc="upper right") + + list_of_variables = ['tnf_node', 'nfkb_node', 'fadd_node'] + plot_molecular_model(df_cell_variables, list_of_variables, axes[2]) + axes[2].set_xlabel("time (min)") + ax2 = axes[2].twinx() + ax2.plot(df_time_tnf.time, df_time_tnf['tnf'], 'r', label="[TNF]") + ax2.set_ylabel("[TNF]") + ax2.set_ylim([0, 1000]) + axes[2].legend(loc="upper left") + ax2.legend(loc="upper right") + + fig.tight_layout() + fig.savefig('variables_vs_time.png') + +main() diff --git a/spheroid_TNF_model b/spheroid_TNF_model new file mode 100755 index 0000000000000000000000000000000000000000..bba6fcab30649ff33cad3c6a426a7d3898e3df28 GIT binary patch literal 2102640 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 z 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