From c7860b40e39596db2160c0c26e5929d0bca25b6b Mon Sep 17 00:00:00 2001 From: drbergman Date: Sun, 2 Feb 2025 06:11:44 -0500 Subject: [PATCH 1/2] DC initialization from file provide a CSV file with similar structure to the substrate ICs csv header row: x,y,z,,,... where the list of substrates need not be all the substrates, only those with DCs being set each subsequent row is: ,,,,,... where the coords must be specified and the vals can either be empty (,,,...) or a number If empty, then nothing chagnes for the substrate in that column at that voxel If a number, then the DC activation for that voxel-substrate pairing is set to the number --- .gitignore | 1 + BioFVM/BioFVM_microenvironment.cpp | 307 +++++++++++++---- BioFVM/BioFVM_microenvironment.h | 16 +- BioFVM/BioFVM_vector.cpp | 55 +++ BioFVM/BioFVM_vector.h | 1 + Makefile | 10 +- modules/PhysiCell_settings.cpp | 15 + sample_projects/Makefile-default | 10 +- sample_projects/dirichlet_from_file/Makefile | 323 ++++++++++++++++++ .../config/PhysiCell_settings.xml | 276 +++++++++++++++ .../dirichlet_from_file/config/cell_rules.csv | 1 + .../dirichlet_from_file/config/cells.csv | 1 + .../dirichlet_from_file/config/dcs.csv | 81 +++++ .../custom_modules/custom.cpp | 214 ++++++++++++ .../custom_modules/custom.h | 92 +++++ sample_projects/dirichlet_from_file/main.cpp | 254 ++++++++++++++ 16 files changed, 1588 insertions(+), 69 deletions(-) create mode 100644 sample_projects/dirichlet_from_file/Makefile create mode 100644 sample_projects/dirichlet_from_file/config/PhysiCell_settings.xml create mode 100644 sample_projects/dirichlet_from_file/config/cell_rules.csv create mode 100644 sample_projects/dirichlet_from_file/config/cells.csv create mode 100644 sample_projects/dirichlet_from_file/config/dcs.csv create mode 100644 sample_projects/dirichlet_from_file/custom_modules/custom.cpp create mode 100644 sample_projects/dirichlet_from_file/custom_modules/custom.h create mode 100644 sample_projects/dirichlet_from_file/main.cpp diff --git a/.gitignore b/.gitignore index 765ccdc8c..63546c554 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ user_projects/* !user_projects/empty.txt Studio.zip /studio +.vscode \ No newline at end of file diff --git a/BioFVM/BioFVM_microenvironment.cpp b/BioFVM/BioFVM_microenvironment.cpp index e18c9ff43..17353d671 100644 --- a/BioFVM/BioFVM_microenvironment.cpp +++ b/BioFVM/BioFVM_microenvironment.cpp @@ -228,6 +228,12 @@ bool& Microenvironment::is_dirichlet_node( int voxel_index ) return mesh.voxels[voxel_index].is_Dirichlet; } +void Microenvironment::set_only_substrate_dirichlet_activation( int substrate_index , bool new_value ) +{ + dirichlet_activation_vector[substrate_index] = new_value; + return; +} + void Microenvironment::set_substrate_dirichlet_activation( int substrate_index , bool new_value ) { dirichlet_activation_vector[substrate_index] = new_value; @@ -1225,6 +1231,195 @@ void set_microenvironment_initial_condition( void ) { microenvironment.density_vector(n) = default_microenvironment_options.initial_condition_vector; } } + // set the dirichlet condition + set_dirichlet_initial_condition(); + + microenvironment.display_information(std::cout); + return; +} + +void load_initial_conditions_from_matlab(std::string filename) +{ + // The .mat file needs to contain exactly one matrix where each row corresponds to a single voxel. + // Each row is a vector of values as follows: [x coord, y coord, z coord, substrate id 0 value, substrate id 1 value, ...] + // Thus, your matrix should be of size #voxels x (3 + #densities) (rows x columns) + // M will be read in such that each element of M is one of these rows + std::vector< std::vector > M = read_matlab( filename ); + int num_mat_voxels = M.size(); + int num_mat_features = M[1].size(); + if (num_mat_voxels != microenvironment.number_of_voxels()) + { + std::cout << "ERROR : Wrong number of voxels supplied in the .mat file specifying BioFVM initial conditions." << std::endl + << "\tExpected: " << microenvironment.number_of_voxels() << std::endl + << "\tFound: " << num_mat_voxels << std::endl + << "\tRemember, save your matrix as a #voxels x (3 + #densities) matrix." << std::endl; + exit(-1); + } + if (num_mat_features != (microenvironment.number_of_densities() + 3)) + { + std::cout << "ERROR : Wrong number of density values supplied in the .mat file specifying BioFVM initial conditions." << std::endl + << "\tExpected: " << microenvironment.number_of_densities() << std::endl + << "\tFound: " << num_mat_features - 3 << std::endl + << "\tRemember, save your matrix as a #voxels x (3 + #densities) matrix." << std::endl; + exit(-1); + } + std::vector voxel_set = {}; // set to check that no voxel value is set twice + int voxel_ind; + std::vector position; + for (unsigned int i = 0; i < num_mat_voxels; i++) + { + position = {M[i][0], M[i][1], M[i][2]}; + voxel_ind = microenvironment.mesh.nearest_voxel_index(position); + for (unsigned int ci = 0; ci < microenvironment.number_of_densities(); ci++) + { + microenvironment.density_vector(voxel_ind)[ci] = M[i][ci+3]; + } + for (unsigned int j = 0; j < i; j++) + { + if (voxel_ind==voxel_set[j]) + { + std::cerr << "ERROR : the matlab-supplied initial conditions for BioFVM repeat the same voxel. Fix the .mat file and try again." << std::endl + << "\tPosition that was repeated: " << position << std::endl; + exit(-1); + } + } + voxel_set.push_back(voxel_ind); + } + + return; +} + +void load_initial_conditions_from_csv(std::string filename) +{ + // The .csv file needs to contain one row per voxel. + // Each row is a vector of values as follows: [x coord, y coord, z coord, substrate id 0 value, substrate id 1 value, ...] + // Thus, your table should be of size #voxels x (3 + #densities) (rows x columns) + + // open file + std::ifstream file( filename, std::ios::in ); + if( !file ) + { + std::cout << "ERROR: " << filename << " not found during cell loading. Quitting." << std::endl; + exit(-1); + } + + // determine if header row exists + std::string line; + std::getline( file , line ); + char c = line.c_str()[0]; + std::vector substrate_indices; + bool header_provided = false; + if( c == 'X' || c == 'x' ) + { + // do not support this with a header yet + if ((line.c_str()[2] != 'Y' && line.c_str()[2] != 'y') || (line.c_str()[4] != 'Z' && line.c_str()[4] != 'z')) + { + std::cout << "ERROR: Header row starts with x but then not y,z? What is this? Exiting now." << std::endl; + file.close(); + exit(-1); + } + std::vector< std::string> column_names; // this will include x,y,z (so make sure to skip those below) + std::stringstream stream(line); + std::string field; + + while (std::getline(stream, field, ',')) + { + column_names.push_back(field); + } + for (int i = 3; i voxel_set = {}; // set to check that no voxel value is set twice + + while (std::getline(file, line)) + { + get_row_from_substrate_initial_condition_csv(voxel_set, line, substrate_indices, header_provided); + } + + if (voxel_set.size() != microenvironment.number_of_voxels()) + { + std::cout << "ERROR : Wrong number of voxels supplied in the .csv file specifying BioFVM initial conditions." << std::endl + << "\tExpected: " << microenvironment.number_of_voxels() << std::endl + << "\tFound: " << voxel_set.size() << std::endl + << "\tRemember, your table should have dimensions #voxels x (3 + #densities)." << std::endl; + exit(-1); + } + + file.close(); + + return; +} + +void get_row_from_substrate_initial_condition_csv(std::vector &voxel_set, const std::string line, const std::vector substrate_indices, const bool header_provided) +{ + static bool warning_issued = false; + std::vector data; + csv_to_vector(line.c_str(), data); + + if (!(warning_issued) && !(header_provided) && (data.size() != (microenvironment.number_of_densities() + 3))) + { + std::cout << "WARNING: Wrong number of density values supplied in the .csv file specifying BioFVM initial conditions." << std::endl + << "\tExpected: " << microenvironment.number_of_voxels() << std::endl + << "\tFound: " << data.size() - 3 << std::endl + << "\tRemember, save your csv with columns as: x, y, z, substrate_0, substrate_1,...." << std::endl + << "\tThis could also be resolved by including a header row \"x,y,z,[substrate_i0,substrate_i1]\"" << std::endl; + warning_issued = true; + } + + std::vector position = {data[0], data[1], data[2]}; + int voxel_ind = microenvironment.mesh.nearest_voxel_index(position); + for (unsigned int ci = 0; ci < substrate_indices.size(); ci++) // column index, counting from the first substrate (or just the index of the vector substrate_indices) + { + microenvironment.density_vector(voxel_ind)[substrate_indices[ci]] = data[ci + 3]; + } + for (unsigned int j = 0; j < voxel_set.size(); j++) + { + if (voxel_ind == voxel_set[j]) + { + std::cout << "ERROR : the csv-supplied initial conditions for BioFVM repeat the same voxel. Fix the .csv file and try again." << std::endl + << "\tPosition that was repeated: " << position << std::endl; + exit(-1); + } + } + voxel_set.push_back(voxel_ind); +} + +void set_dirichlet_initial_condition( void ) +{ + set_dirichlet_boundaries_from_XML(); + set_dirichlet_boundaries_from_file(); +} + +void set_dirichlet_boundaries_from_XML( void ) +{ // now, figure out which sides have BCs (for at least one substrate): bool xmin = false; @@ -1391,70 +1586,48 @@ void set_microenvironment_initial_condition( void ) } } } - } - - microenvironment.display_information(std::cout); - return; } -void load_initial_conditions_from_matlab(std::string filename) +void set_dirichlet_boundaries_from_file( void ) { - // The .mat file needs to contain exactly one matrix where each row corresponds to a single voxel. - // Each row is a vector of values as follows: [x coord, y coord, z coord, substrate id 0 value, substrate id 1 value, ...] - // Thus, your matrix should be of size #voxels x (3 + #densities) (rows x columns) - // M will be read in such that each element of M is one of these rows - std::vector< std::vector > M = read_matlab( filename ); - int num_mat_voxels = M.size(); - int num_mat_features = M[1].size(); - if (num_mat_voxels != microenvironment.number_of_voxels()) + if (!default_microenvironment_options.dirichlet_condition_from_file_enabled) { - std::cout << "ERROR : Wrong number of voxels supplied in the .mat file specifying BioFVM initial conditions." << std::endl - << "\tExpected: " << microenvironment.number_of_voxels() << std::endl - << "\tFound: " << num_mat_voxels << std::endl - << "\tRemember, save your matrix as a #voxels x (3 + #densities) matrix." << std::endl; - exit(-1); + return; } - if (num_mat_features != (microenvironment.number_of_densities() + 3)) + std::string filetype = default_microenvironment_options.dirichlet_condition_file_type; + std::string filename = default_microenvironment_options.dirichlet_condition_file; + if (filetype == "matlab") { - std::cout << "ERROR : Wrong number of density values supplied in the .mat file specifying BioFVM initial conditions." << std::endl - << "\tExpected: " << microenvironment.number_of_densities() << std::endl - << "\tFound: " << num_mat_features - 3 << std::endl - << "\tRemember, save your matrix as a #voxels x (3 + #densities) matrix." << std::endl; - exit(-1); + load_dirichlet_conditions_from_matlab(filename); } - std::vector voxel_set = {}; // set to check that no voxel value is set twice - int voxel_ind; - std::vector position; - for (unsigned int i = 0; i < num_mat_voxels; i++) + else if (filetype == "csv" || filetype == "CSV") { - position = {M[i][0], M[i][1], M[i][2]}; - voxel_ind = microenvironment.mesh.nearest_voxel_index(position); - for (unsigned int ci = 0; ci < microenvironment.number_of_densities(); ci++) - { - microenvironment.density_vector(voxel_ind)[ci] = M[i][ci+3]; - } - for (unsigned int j = 0; j < i; j++) - { - if (voxel_ind==voxel_set[j]) - { - std::cout << "ERROR : the matlab-supplied initial conditions for BioFVM repeat the same voxel. Fix the .mat file and try again." << std::endl - << "\tPosition that was repeated: " << position << std::endl; - exit(-1); - } - } - voxel_set.push_back(voxel_ind); + load_dirichlet_conditions_from_csv(filename); + } + else // eventually can add other file types + { + std::cout << "ERROR : Load BioFVM dirichlet conditions from " << filetype << " not yet supported." << std::endl; + exit(-1); } - return; } -void load_initial_conditions_from_csv(std::string filename) +void load_dirichlet_conditions_from_matlab(std::string filename) +{ + std::cerr << "ERROR: Load BioFVM dirichlet conditions from MATLAB not yet supported." << std::endl; + exit(-1); +} + +void load_dirichlet_conditions_from_csv(std::string filename) { // The .csv file needs to contain one row per voxel. // Each row is a vector of values as follows: [x coord, y coord, z coord, substrate id 0 value, substrate id 1 value, ...] // Thus, your table should be of size #voxels x (3 + #densities) (rows x columns) - // Do not include a header row. + + // alternatively, include a header row that begins "x,y,z" and then lists the substrate names to have DC values set + + // In either case, an empty value in the table will be interpreted as not changing the DC condition for that voxel-substrate pair // open file std::ifstream file( filename, std::ios::in ); @@ -1470,6 +1643,7 @@ void load_initial_conditions_from_csv(std::string filename) char c = line.c_str()[0]; std::vector substrate_indices; bool header_provided = false; + int n_cols; if( c == 'X' || c == 'x' ) { // do not support this with a header yet @@ -1499,6 +1673,7 @@ void load_initial_conditions_from_csv(std::string filename) substrate_indices.push_back(microenvironment.find_density_index(column_names[i])); } header_provided = true; + n_cols = column_names.size(); } else // no column labels given; just assume that the first n substrates are supplied (n = # columns after x,y,z) { @@ -1512,42 +1687,38 @@ void load_initial_conditions_from_csv(std::string filename) i++; } // in this case, we want to read this first line, so close the file and re-open so that we start with this line + n_cols = 3 + substrate_indices.size(); file.close(); std::ifstream file(filename, std::ios::in); std::getline(file, line); } - std::cout << "Loading substrate initial conditions from CSV file " << filename << " ... " << std::endl; + std::cout << "Loading substrate dirichlet conditions from CSV file " << filename << " ... " << std::endl; std::vector voxel_set = {}; // set to check that no voxel value is set twice - + while (std::getline(file, line)) { - get_row_from_substrate_initial_condition_csv(voxel_set, line, substrate_indices, header_provided); - } - - if (voxel_set.size() != microenvironment.number_of_voxels()) - { - std::cout << "ERROR : Wrong number of voxels supplied in the .csv file specifying BioFVM initial conditions." << std::endl - << "\tExpected: " << microenvironment.number_of_voxels() << std::endl - << "\tFound: " << voxel_set.size() << std::endl - << "\tRemember, your table should have dimensions #voxels x (3 + #densities)." << std::endl; - exit(-1); + get_row_from_dirichlet_condition_csv(voxel_set, line, substrate_indices, header_provided, n_cols); } - file.close(); - + file.close(); + return; } -void get_row_from_substrate_initial_condition_csv(std::vector &voxel_set, const std::string line, const std::vector substrate_indices, const bool header_provided) +void get_row_from_dirichlet_condition_csv(std::vector &voxel_set, const std::string line, const std::vector substrate_indices, const bool header_provided, int n_cols) { static bool warning_issued = false; + std::vector is_missing; std::vector data; - csv_to_vector(line.c_str(), data); + is_missing.resize(n_cols); + data.resize(n_cols); + + dirichlet_csv_to_vector(line.c_str(), is_missing, data); if (!(warning_issued) && !(header_provided) && (data.size() != (microenvironment.number_of_densities() + 3))) { - std::cout << "WARNING: Wrong number of density values supplied in the .csv file specifying BioFVM initial conditions." << std::endl + std::cout << "WARNING: Wrong number of density data supplied in the .csv file specifying BioFVM dirichlet conditions." << std::endl << "\tExpected: " << microenvironment.number_of_voxels() << std::endl << "\tFound: " << data.size() - 3 << std::endl << "\tRemember, save your csv with columns as: x, y, z, substrate_0, substrate_1,...." << std::endl @@ -1559,13 +1730,17 @@ void get_row_from_substrate_initial_condition_csv(std::vector &voxel_set, c int voxel_ind = microenvironment.mesh.nearest_voxel_index(position); for (unsigned int ci = 0; ci < substrate_indices.size(); ci++) // column index, counting from the first substrate (or just the index of the vector substrate_indices) { - microenvironment.density_vector(voxel_ind)[substrate_indices[ci]] = data[ci + 3]; + if (!is_missing[ci + 3]) + { + microenvironment.update_dirichlet_node(voxel_ind, substrate_indices[ci], data[ci + 3]); + microenvironment.set_only_substrate_dirichlet_activation(substrate_indices[ci], true); + } } for (unsigned int j = 0; j < voxel_set.size(); j++) { if (voxel_ind == voxel_set[j]) { - std::cout << "ERROR : the csv-supplied initial conditions for BioFVM repeat the same voxel. Fix the .csv file and try again." << std::endl + std::cout << "ERROR : the csv-supplied dirichlet conditions for BioFVM repeat the same voxel. Fix the .csv file and try again." << std::endl << "\tPosition that was repeated: " << position << std::endl; exit(-1); } diff --git a/BioFVM/BioFVM_microenvironment.h b/BioFVM/BioFVM_microenvironment.h index 6fec93728..fb5d7354f 100644 --- a/BioFVM/BioFVM_microenvironment.h +++ b/BioFVM/BioFVM_microenvironment.h @@ -254,6 +254,9 @@ class Microenvironment void set_substrate_dirichlet_activation( int index, std::vector& new_value ); bool get_substrate_dirichlet_activation( int substrate_index, int index ); + // only change dirichlet_activation_vector, not the activation_vectors for each voxel + void set_only_substrate_dirichlet_activation( int substrate_index , bool new_value ); + double get_substrate_dirichlet_value( int substrate_index, int index ); bool& is_dirichlet_node( int voxel_index ); @@ -341,9 +344,13 @@ class Microenvironment_Options std::vector initial_condition_vector; - bool initial_condition_from_file_enabled; + bool initial_condition_from_file_enabled = false; std::string initial_condition_file_type; std::string initial_condition_file; + + bool dirichlet_condition_from_file_enabled = false; + std::string dirichlet_condition_file_type; + std::string dirichlet_condition_file; bool simulate_2D; std::vector X_range; @@ -368,6 +375,13 @@ void set_microenvironment_initial_condition( void ); void load_initial_conditions_from_matlab( std::string filename ); void load_initial_conditions_from_csv( std::string filename ); void get_row_from_substrate_initial_condition_csv(std::vector &voxel_set, const std::string line, const std::vector substrate_indices, const bool header_provided); + +void set_dirichlet_initial_condition( void ); +void set_dirichlet_boundaries_from_XML( void ); +void set_dirichlet_boundaries_from_file( void ); +void load_dirichlet_conditions_from_matlab( std::string filename ); +void load_dirichlet_conditions_from_csv(std::string filename); +void get_row_from_dirichlet_condition_csv(std::vector &voxel_set, const std::string line, const std::vector substrate_indices, const bool header_provided, int n_cols); }; #endif diff --git a/BioFVM/BioFVM_vector.cpp b/BioFVM/BioFVM_vector.cpp index e12a3672d..6981fef9d 100644 --- a/BioFVM/BioFVM_vector.cpp +++ b/BioFVM/BioFVM_vector.cpp @@ -376,6 +376,61 @@ void csv_to_vector( const char* buffer , std::vector& vect ) return; } +void dirichlet_csv_to_vector( const char* buffer , std::vector& is_missing , std::vector& data ) +{ + size_t ind = 0; + unsigned int i=0; + std::string entry; + while( i < strlen( buffer ) ) + { + if(buffer[i] == ',') + { + if(entry.empty()) + { + is_missing[ind] = true; + } + else + { + data[ind] = std::stod(entry); + is_missing[ind] = false; + } + entry.clear(); + ind++; + } + else + { + entry += buffer[i]; + } + i++; + } + // Handle the last entry + if(entry.empty()) + { + is_missing[ind] = true; + } + else + { + data[ind] = std::stod(entry); + is_missing[ind] = false; + } + + if (is_missing[0] || is_missing[1] || is_missing[2]) + { + std::cerr << "Error: x, y, and z data must be provided for each row in the .csv file specifying BioFVM dirichlet conditions." << std::endl; + exit(-1); + } + + if (ind < is_missing.size() - 1) + { + std::cerr << "Error: Wrong number of data supplied in a row of the .csv file specifying BioFVM dirichlet conditions." << std::endl; + std::cerr << "\tExpected: " << is_missing.size() << ". Found: " << ind + 1 << std::endl; + std::cerr << "\tRow: " << buffer << std::endl; + exit(-1); + } + return; +} + + char* vector_to_csv( const std::vector& vect ) { static int datum_size = 16; // format = %.7e, 1 (sign) + 1 (lead) + 1 (decimal) + 7 (figs) + 2 (e, sign) + 3 (exponent) + 1 (delimiter) = 16 diff --git a/BioFVM/BioFVM_vector.h b/BioFVM/BioFVM_vector.h index e3c36d449..881239061 100644 --- a/BioFVM/BioFVM_vector.h +++ b/BioFVM/BioFVM_vector.h @@ -130,6 +130,7 @@ void double_axpy_div( std::vector* y, std::vector& a1 , std::vec // turn a delimited character array (e.g., csv) into a vector of doubles void csv_to_vector( const char* buffer , std::vector& vect ); +void dirichlet_csv_to_vector( const char* buffer , std::vector& missings , std::vector& values ); char* vector_to_csv( const std::vector& vect ); void vector_to_csv_safe( const std::vector& vect , char*& buffer ); void vector_to_csv( const std::vector& vect , char*& buffer ); diff --git a/Makefile b/Makefile index 5d256d1c3..14a9523f5 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,7 @@ template: cp Makefile Makefile-backup cp ./sample_projects/template/Makefile . cp -r ./sample_projects/template/config/* ./config - + # sample projects # ---- non-intracellular projects @@ -233,6 +233,14 @@ episode-sample: cp ./sample_projects/episode/Makefile . cp -r ./sample_projects/episode/config/* ./config +dirichlet-from-file-sample: + cp -r ./sample_projects/dirichlet_from_file/custom_modules/* ./custom_modules/ + touch main.cpp && cp main.cpp main-backup.cpp + cp ./sample_projects/dirichlet_from_file/main.cpp ./main.cpp + cp Makefile Makefile-backup + cp ./sample_projects/dirichlet_from_file/Makefile . + cp -r ./sample_projects/dirichlet_from_file/config/* ./config + # ---- intracellular projects ode-energy-sample: cp ./sample_projects_intracellular/ode/ode_energy/custom_modules/* ./custom_modules/ diff --git a/modules/PhysiCell_settings.cpp b/modules/PhysiCell_settings.cpp index 538f6a8ea..5fcb6a505 100644 --- a/modules/PhysiCell_settings.cpp +++ b/modules/PhysiCell_settings.cpp @@ -965,6 +965,21 @@ bool setup_microenvironment_from_XML( pugi::xml_node root_node ) } } + node = xml_find_node( root_node , "microenvironment_setup" ); + node = xml_find_node( node , "options" ); + node = xml_find_node(node, "dirichlet_nodes"); + if (node) + { + default_microenvironment_options.dirichlet_condition_from_file_enabled = node.attribute("enabled").as_bool(); + if (default_microenvironment_options.dirichlet_condition_from_file_enabled) + { + default_microenvironment_options.dirichlet_condition_file_type = node.attribute("type").as_string(); + default_microenvironment_options.dirichlet_condition_file = xml_get_string_value(node, "filename"); + + copy_file_to_output(default_microenvironment_options.dirichlet_condition_file); + } + } + // not yet supported : read initial conditions /* // read in initial conditions from an external file diff --git a/sample_projects/Makefile-default b/sample_projects/Makefile-default index 5d256d1c3..14a9523f5 100644 --- a/sample_projects/Makefile-default +++ b/sample_projects/Makefile-default @@ -87,7 +87,7 @@ template: cp Makefile Makefile-backup cp ./sample_projects/template/Makefile . cp -r ./sample_projects/template/config/* ./config - + # sample projects # ---- non-intracellular projects @@ -233,6 +233,14 @@ episode-sample: cp ./sample_projects/episode/Makefile . cp -r ./sample_projects/episode/config/* ./config +dirichlet-from-file-sample: + cp -r ./sample_projects/dirichlet_from_file/custom_modules/* ./custom_modules/ + touch main.cpp && cp main.cpp main-backup.cpp + cp ./sample_projects/dirichlet_from_file/main.cpp ./main.cpp + cp Makefile Makefile-backup + cp ./sample_projects/dirichlet_from_file/Makefile . + cp -r ./sample_projects/dirichlet_from_file/config/* ./config + # ---- intracellular projects ode-energy-sample: cp ./sample_projects_intracellular/ode/ode_energy/custom_modules/* ./custom_modules/ diff --git a/sample_projects/dirichlet_from_file/Makefile b/sample_projects/dirichlet_from_file/Makefile new file mode 100644 index 000000000..7aa7d18d2 --- /dev/null +++ b/sample_projects/dirichlet_from_file/Makefile @@ -0,0 +1,323 @@ +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 + +ifndef STATIC_OPENMP + STATIC_OPENMP = -fopenmp +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 + +CFLAGS_LINK := $(shell echo $(CFLAGS) | sed -e "s/-fopenmp//g") +COMPILE_COMMAND := $(CC) $(CFLAGS) $(EXTRA_FLAGS) +LINK_COMMAND := $(CC) $(CFLAGS_LINK) $(EXTRA_FLAGS) + +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 := custom.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) + +# compile the project + +all: main.cpp $(ALL_OBJECTS) + $(COMPILE_COMMAND) -o $(PROGRAM_NAME) $(ALL_OBJECTS) main.cpp + make name + +static: main.cpp $(ALL_OBJECTS) $(MaBoSS) + $(LINK_COMMAND) $(INC) -o $(PROGRAM_NAME) $(ALL_OBJECTS) main.cpp $(LIB) -static-libgcc -static-libstdc++ $(STATIC_OPENMP) + +name: + @echo "" + @echo "Executable name is" $(PROGRAM_NAME) + @echo "" + +# 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 + +custom.o: ./custom_modules/custom.cpp + $(COMPILE_COMMAND) -c ./custom_modules/custom.cpp + +# cleanup + +reset: + rm -f *.cpp + cp ./sample_projects/Makefile-default Makefile + rm -f ./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 -f ./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 ./config/* ./user_projects/$(PROJ)/config + cp ./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 ./user_projects/$(PROJ)/config/* ./config/ + cp ./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!!' diff --git a/sample_projects/dirichlet_from_file/config/PhysiCell_settings.xml b/sample_projects/dirichlet_from_file/config/PhysiCell_settings.xml new file mode 100644 index 000000000..1aa7aff2a --- /dev/null +++ b/sample_projects/dirichlet_from_file/config/PhysiCell_settings.xml @@ -0,0 +1,276 @@ + + + + -500 + 500 + -500 + 500 + -10 + 10 + 20 + 20 + 20 + true + + + + 7200 + min + micron + 0.01 + 0.1 + 6 + + + + 6 + + + + output + + 60 + true + + + 60 + true + + substrate + YlOrRd + 0 + 1 + + + + false + + + + + false + true + false + 0 + + + + + + 0 + 10 + + 0 + 0 + + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0.0 + 0.0 + + 0.0 + 0.0 + + + + + + + + + + + + true + true + + ./config/initial.mat + + + ./config/dcs.csv + + + + + + + + + + 300.0 + 480.0 + 240.0 + 60.0 + + 1.0 + + + + 5.31667e-05 + + 516 + + + 0.05 + 0 + 1.66667e-02 + 5.83333e-03 + 0 + 2.0 + + + + 0.0 + + 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 + + 0.01 + 0.0 + 0.0 + 12 + + + + 1 + 1 + .5 + + false + true + + false + substrate + 1 + + + false + false + + 0.0 + 0.0 + + + + + + + + 0 + 1 + 0 + 0 + + + 0.0 + 1.0 + 0.0 + 0.0 + + + + + 0 + 0 + 0 + + 0 + + + + 0 + + + 1 + 0.1 + + 0 + + + + + + + 0 + + + + + 0.0 + 0.0 + + + + + 1.0 + + + Volume42100000apoptosis1e-61e-2 + + + + + + + ./config + cells.csv + + + + + + + ./config + cell_rules.csv + + + + + + + 5 + + \ No newline at end of file diff --git a/sample_projects/dirichlet_from_file/config/cell_rules.csv b/sample_projects/dirichlet_from_file/config/cell_rules.csv new file mode 100644 index 000000000..078426a60 --- /dev/null +++ b/sample_projects/dirichlet_from_file/config/cell_rules.csv @@ -0,0 +1 @@ +// \ No newline at end of file diff --git a/sample_projects/dirichlet_from_file/config/cells.csv b/sample_projects/dirichlet_from_file/config/cells.csv new file mode 100644 index 000000000..734bdc767 --- /dev/null +++ b/sample_projects/dirichlet_from_file/config/cells.csv @@ -0,0 +1 @@ +0,0,0,0 \ No newline at end of file diff --git a/sample_projects/dirichlet_from_file/config/dcs.csv b/sample_projects/dirichlet_from_file/config/dcs.csv new file mode 100644 index 000000000..ab5abfe3b --- /dev/null +++ b/sample_projects/dirichlet_from_file/config/dcs.csv @@ -0,0 +1,81 @@ +x,y,z,substrate,oxygen +-210,-390,0.0,78.0, +-210,-370,0.0,78.0, +-210,-350,0.0,78.0, +-210,-330,0.0,78.0, +-210,-310,0.0,78.0, +-210,-290,0.0,78.0, +-210,-270,0.0,78.0, +-210,-250,0.0,78.0, +-210,-230,0.0,78.0, +-210,-210,0.0,78.0, +-210,-190,0.0,78.0, +-210,-170,0.0,78.0, +-210,-150,0.0,78.0, +-210,-130,0.0,78.0, +-210,-110,0.0,78.0, +-210,-90,0.0,78.0, +-210,-70,0.0,78.0, +-210,-50,0.0,78.0, +-210,-30,0.0,78.0, +-210,-10,0.0,78.0, +-210,10,0.0,78.0, +-210,30,0.0,78.0, +-210,50,0.0,78.0, +-210,70,0.0,78.0, +-210,90,0.0,78.0, +-210,110,0.0,78.0, +-210,130,0.0,78.0, +-210,150,0.0,78.0, +-210,170,0.0,78.0, +-210,190,0.0,78.0, +-210,210,0.0,78.0, +-210,230,0.0,78.0, +-210,250,0.0,78.0, +-210,270,0.0,78.0, +-210,290,0.0,78.0, +-210,310,0.0,78.0, +-210,330,0.0,78.0, +-210,350,0.0,78.0, +-210,370,0.0,78.0, +-210,390,0.0,78.0, +210,-390,0.0,,16.0 +210,-370,0.0,,16.0 +210,-350,0.0,,16.0 +210,-330,0.0,,16.0 +210,-310,0.0,,16.0 +210,-290,0.0,,16.0 +210,-270,0.0,,16.0 +210,-250,0.0,,16.0 +210,-230,0.0,,16.0 +210,-210,0.0,,16.0 +210,-190,0.0,,16.0 +210,-170,0.0,,16.0 +210,-150,0.0,,16.0 +210,-130,0.0,,16.0 +210,-110,0.0,,16.0 +210,-90,0.0,,16.0 +210,-70,0.0,,16.0 +210,-50,0.0,,16.0 +210,-30,0.0,,16.0 +210,-10,0.0,,16.0 +210,10,0.0,,16.0 +210,30,0.0,,16.0 +210,50,0.0,,16.0 +210,70,0.0,,16.0 +210,90,0.0,,16.0 +210,110,0.0,,16.0 +210,130,0.0,,16.0 +210,150,0.0,,16.0 +210,170,0.0,,16.0 +210,190,0.0,,16.0 +210,210,0.0,,16.0 +210,230,0.0,,16.0 +210,250,0.0,,16.0 +210,270,0.0,,16.0 +210,290,0.0,,16.0 +210,310,0.0,,16.0 +210,330,0.0,,16.0 +210,350,0.0,,16.0 +210,370,0.0,,16.0 +210,390,0.0,,16.0 \ No newline at end of file diff --git a/sample_projects/dirichlet_from_file/custom_modules/custom.cpp b/sample_projects/dirichlet_from_file/custom_modules/custom.cpp new file mode 100644 index 000000000..59b23bd93 --- /dev/null +++ b/sample_projects/dirichlet_from_file/custom_modules/custom.cpp @@ -0,0 +1,214 @@ +/* +############################################################################### +# 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-2021, 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" + +void create_cell_types( void ) +{ + // set the random seed + if (parameters.ints.find_index("random_seed") != -1) + { + SeedRandom(parameters.ints("random_seed")); + } + + /* + Put any modifications to default cell definition here if you + want to have "inherited" by other cell types. + + This is a good place to set default functions. + */ + + initialize_default_cell_definition(); + cell_defaults.phenotype.secretion.sync_to_microenvironment( µenvironment ); + + cell_defaults.functions.volume_update_function = standard_volume_update_function; + cell_defaults.functions.update_velocity = standard_update_cell_velocity; + + cell_defaults.functions.update_migration_bias = NULL; + cell_defaults.functions.update_phenotype = NULL; // update_cell_and_death_parameters_O2_based; + cell_defaults.functions.custom_cell_rule = NULL; + cell_defaults.functions.contact_function = NULL; + + cell_defaults.functions.add_cell_basement_membrane_interactions = NULL; + cell_defaults.functions.calculate_distance_to_membrane = NULL; + + /* + This parses the cell definitions in the XML config file. + */ + + initialize_cell_definitions_from_pugixml(); + + /* + This builds the map of cell definitions and summarizes the setup. + */ + + build_cell_definitions_maps(); + + /* + This intializes cell signal and response dictionaries + */ + + setup_signal_behavior_dictionaries(); + + /* + Cell rule definitions + */ + + setup_cell_rules(); + + /* + Put any modifications to individual cell definitions here. + + This is a good place to set custom functions. + */ + + cell_defaults.functions.update_phenotype = phenotype_function; + cell_defaults.functions.custom_cell_rule = custom_function; + cell_defaults.functions.contact_function = contact_function; + + /* + This builds the map of cell definitions and summarizes the setup. + */ + + display_cell_definitions( std::cout ); + + return; +} + +void setup_microenvironment( void ) +{ + // set domain parameters + + // put any custom code to set non-homogeneous initial conditions or + // extra Dirichlet nodes here. + + // initialize BioFVM + + initialize_microenvironment(); + + return; +} + +void setup_tissue( void ) +{ + double Xmin = microenvironment.mesh.bounding_box[0]; + double Ymin = microenvironment.mesh.bounding_box[1]; + double Zmin = microenvironment.mesh.bounding_box[2]; + + double Xmax = microenvironment.mesh.bounding_box[3]; + double Ymax = microenvironment.mesh.bounding_box[4]; + double Zmax = microenvironment.mesh.bounding_box[5]; + + if( default_microenvironment_options.simulate_2D == true ) + { + Zmin = 0.0; + Zmax = 0.0; + } + + double Xrange = Xmax - Xmin; + double Yrange = Ymax - Ymin; + double Zrange = Zmax - Zmin; + + // create some of each type of cell + + Cell* pC; + + for( int k=0; k < cell_definitions_by_index.size() ; k++ ) + { + Cell_Definition* pCD = cell_definitions_by_index[k]; + std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; + for( int n = 0 ; n < parameters.ints("number_of_cells") ; n++ ) + { + std::vector position = {0,0,0}; + position[0] = Xmin + UniformRandom()*Xrange; + position[1] = Ymin + UniformRandom()*Yrange; + position[2] = Zmin + UniformRandom()*Zrange; + + pC = create_cell( *pCD ); + pC->assign_position( position ); + } + } + std::cout << std::endl; + + // load cells from your CSV file (if enabled) + load_cells_from_pugixml(); + set_parameters_from_distributions(); + + return; +} + +std::vector my_coloring_function( Cell* pCell ) +{ return paint_by_number_cell_coloring(pCell); } + +void phenotype_function( Cell* pCell, Phenotype& phenotype, double dt ) +{ return; } + +void custom_function( Cell* pCell, Phenotype& phenotype , double dt ) +{ return; } + +void contact_function( Cell* pMe, Phenotype& phenoMe , Cell* pOther, Phenotype& phenoOther , double dt ) +{ return; } \ No newline at end of file diff --git a/sample_projects/dirichlet_from_file/custom_modules/custom.h b/sample_projects/dirichlet_from_file/custom_modules/custom.h new file mode 100644 index 000000000..0e6df8d02 --- /dev/null +++ b/sample_projects/dirichlet_from_file/custom_modules/custom.h @@ -0,0 +1,92 @@ +/* +############################################################################### +# 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-2021, 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 "../core/PhysiCell.h" +#include "../modules/PhysiCell_standard_modules.h" + +using namespace BioFVM; +using namespace PhysiCell; + +// setup functions to help us along + +void create_cell_types( void ); +void setup_tissue( void ); + +// set up the BioFVM microenvironment +void setup_microenvironment( void ); + +// custom pathology coloring function + +std::vector my_coloring_function( Cell* ); + +// custom functions can go here + +void phenotype_function( Cell* pCell, Phenotype& phenotype, double dt ); +void custom_function( Cell* pCell, Phenotype& phenotype , double dt ); + +void contact_function( Cell* pMe, Phenotype& phenoMe , Cell* pOther, Phenotype& phenoOther , double dt ); + diff --git a/sample_projects/dirichlet_from_file/main.cpp b/sample_projects/dirichlet_from_file/main.cpp new file mode 100644 index 000000000..bf6e65d15 --- /dev/null +++ b/sample_projects/dirichlet_from_file/main.cpp @@ -0,0 +1,254 @@ +/* +############################################################################### +# 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-2022, 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 "./modules/PhysiCell_standard_modules.h" + +// put custom code modules here! + +#include "./custom_modules/custom.h" + +using namespace BioFVM; +using namespace PhysiCell; + +int main( int argc, char* argv[] ) +{ + // load and parse settings file(s) + + 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); + + // time setup + std::string time_units = "min"; + + /* Microenvironment setup */ + + setup_microenvironment(); // modify this in the custom code + + /* 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(); + + setup_tissue(); + + /* Users typically stop modifying here. END USERMODS */ + + // 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 ); + + // 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; + std::string (*substrate_coloring_function)(double, double, double) = paint_by_density_percentage; + + sprintf( filename , "%s/initial.svg" , PhysiCell_settings.folder.c_str() ); + SVG_plot( filename , microenvironment, 0.0 , PhysiCell_globals.current_time, cell_coloring_function, substrate_coloring_function ); + + sprintf( filename , "%s/legend.svg" , PhysiCell_settings.folder.c_str() ); + create_plot_legend( filename , cell_coloring_function ); + + 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"< PhysiCell_globals.next_full_save_time - 0.5 * diffusion_dt ) + { + display_simulation_status( std::cout ); + if( PhysiCell_settings.enable_legacy_saves == true ) + { + log_output( PhysiCell_globals.current_time , PhysiCell_globals.full_output_index, microenvironment, report_file); + } + + if( PhysiCell_settings.enable_full_saves == true ) + { + sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); + + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); + } + + PhysiCell_globals.full_output_index++; + PhysiCell_globals.next_full_save_time += PhysiCell_settings.full_save_interval; + } + + // save SVG plot if it's time + if( PhysiCell_globals.current_time > PhysiCell_globals.next_SVG_save_time - 0.5 * diffusion_dt ) + { + if( PhysiCell_settings.enable_SVG_saves == true ) + { + sprintf( filename , "%s/snapshot%08u.svg" , PhysiCell_settings.folder.c_str() , PhysiCell_globals.SVG_output_index ); + SVG_plot( filename , microenvironment, 0.0 , PhysiCell_globals.current_time, cell_coloring_function, substrate_coloring_function); + + PhysiCell_globals.SVG_output_index++; + PhysiCell_globals.next_SVG_save_time += PhysiCell_settings.SVG_save_interval; + } + } + + // update the microenvironment + microenvironment.simulate_diffusion_decay( diffusion_dt ); + + // run PhysiCell + ((Cell_Container *)microenvironment.agent_container)->update_all_cells( PhysiCell_globals.current_time ); + + /* + Custom add-ons could potentially go here. + */ + + 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/final.svg" , PhysiCell_settings.folder.c_str() ); + SVG_plot(filename, microenvironment, 0.0, PhysiCell_globals.current_time, cell_coloring_function, substrate_coloring_function); + + // timer + + std::cout << std::endl << "Total simulation runtime: " << std::endl; + BioFVM::display_stopwatch_value( std::cout , BioFVM::runtime_stopwatch_value() ); + + return 0; +} From 8f96226d62b0ba26158e398f44d567f86f89f940 Mon Sep 17 00:00:00 2001 From: Daniel Bergman Date: Thu, 22 May 2025 08:53:07 -0400 Subject: [PATCH 2/2] - fix logic reading in substrates.csv without a header --- BioFVM/BioFVM_microenvironment.cpp | 37 ++++++++++++++++-------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/BioFVM/BioFVM_microenvironment.cpp b/BioFVM/BioFVM_microenvironment.cpp index 17353d671..912f0d135 100644 --- a/BioFVM/BioFVM_microenvironment.cpp +++ b/BioFVM/BioFVM_microenvironment.cpp @@ -1309,6 +1309,7 @@ void load_initial_conditions_from_csv(std::string filename) char c = line.c_str()[0]; std::vector substrate_indices; bool header_provided = false; + std::vector voxel_set = {}; // set to check that no voxel value is set twice if( c == 'X' || c == 'x' ) { // do not support this with a header yet @@ -1343,21 +1344,18 @@ void load_initial_conditions_from_csv(std::string filename) { std::stringstream stream(line); std::string field; - int i = 0; + int i = -1; while (std::getline(stream, field, ',')) { + i++; if (i<3) {continue;} // skip (x,y,z) substrate_indices.push_back(i-3); // the substrate index is the column index - 3 (since x,y,z are the first 3 columns) - i++; } - // in this case, we want to read this first line, so close the file and re-open so that we start with this line - file.close(); - std::ifstream file(filename, std::ios::in); - std::getline(file, line); + // in this case, we want to read this first line, so read it now and the below logic will loop through the remaining lines + get_row_from_substrate_initial_condition_csv(voxel_set, line, substrate_indices, header_provided); } std::cout << "Loading substrate initial conditions from CSV file " << filename << " ... " << std::endl; - std::vector voxel_set = {}; // set to check that no voxel value is set twice while (std::getline(file, line)) { @@ -1615,7 +1613,7 @@ void set_dirichlet_boundaries_from_file( void ) void load_dirichlet_conditions_from_matlab(std::string filename) { - std::cerr << "ERROR: Load BioFVM dirichlet conditions from MATLAB not yet supported." << std::endl; + std::cerr << "ERROR: Load BioFVM dirichlet conditions from MATLAB not yet supported. Use a CSV file instead." << std::endl; exit(-1); } @@ -1644,6 +1642,7 @@ void load_dirichlet_conditions_from_csv(std::string filename) std::vector substrate_indices; bool header_provided = false; int n_cols; + std::vector voxel_set = {}; // set to check that no voxel value is set twice if( c == 'X' || c == 'x' ) { // do not support this with a header yet @@ -1679,23 +1678,27 @@ void load_dirichlet_conditions_from_csv(std::string filename) { std::stringstream stream(line); std::string field; - int i = 0; + int i = -1; while (std::getline(stream, field, ',')) { + i++; if (i<3) {continue;} // skip (x,y,z) substrate_indices.push_back(i-3); // the substrate index is the column index - 3 (since x,y,z are the first 3 columns) + } + // If the line ends with a comma, that implies a final empty field so no DC set at that voxel-substrate pair + if (!line.empty() && line.back() == ',') + { i++; + if (i >= 3) + { + substrate_indices.push_back(i - 3); + } } - // in this case, we want to read this first line, so close the file and re-open so that we start with this line n_cols = 3 + substrate_indices.size(); - file.close(); - std::ifstream file(filename, std::ios::in); - std::getline(file, line); + // in this case, we want to read this first line, so read it now and the below logic will loop through the remaining lines + get_row_from_dirichlet_condition_csv(voxel_set, line, substrate_indices, header_provided, n_cols); } - - std::cout << "Loading substrate dirichlet conditions from CSV file " << filename << " ... " << std::endl; - std::vector voxel_set = {}; // set to check that no voxel value is set twice - + while (std::getline(file, line)) { get_row_from_dirichlet_condition_csv(voxel_set, line, substrate_indices, header_provided, n_cols);