Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 5 additions & 29 deletions modules/PhysiCell_MultiCellDS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1354,34 +1354,7 @@ int resume_from_MultiCellDS(std::string folder_path, std::string xml_filename, b
return -1;
}

// Let's confirm the last cell param, before the custom data vars, is what we expect.
// If/when this labels list is modified, this code will need to be updated.

std::string label_path = "//cellular_information//cell_populations//custom//simplified_data//labels//label[@index=99]";
std::cout << "\nreading " << label_path << std::endl;
// xpath_node = doc.select_node(label_path); // not allowed

// <label index="99" size="1" units="1/min">damage_repair_rate</label>
// <label index="100" size="1" units="dimensionless">sample</label>
// xpath_node = doc.select_node("//cellular_information//cell_populations//custom//simplified_data//labels//label[@index=99]");
// node = xpath_node.node();
// if (node)
// {
// std::cout << "\n Success!\n" << std::endl;
// }
// else
// {
// std::cout << "\n --- Error reading node\n" << std::endl;
// return -1;
// }
// std::string last_var = xml_get_my_string_value(node);
// std::cout << "last_var= " << last_var << std::endl;
// if (last_var != "damage_repair_rate")
// {
// std::cout << "\n Error: last var should be 'damage_repair_rate'\n" << std::endl;
// return -1;
// }

// read/skip over all labels until the last one, damage_repair_rate, so we can parse custom data vars
xpath_node = doc.select_node("//cellular_information//cell_populations//custom//simplified_data//labels//label[@index=0]");
node = xpath_node.node();
if (!node)
Expand Down Expand Up @@ -2173,7 +2146,10 @@ int recreate_sim_state(std::string filename, Microenvironment& M,
// if it exists, overwrite
if( idx_var > -1 )
{
pCell->custom_data.variables[idx_var].value = pair.second;
// pCell->custom_data.variables[idx_var].value = pair.second;
pCell->custom_data.variables[idx_var].value = dTemp;
if (debug_print)
{ std::cout << " ---- pCell->custom_data[" << pair.first << "] = " <<pCell->custom_data[pair.first] << std::endl; }
}
else
{
Expand Down
33 changes: 33 additions & 0 deletions unit_tests/resume_sim/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## Resume a simulation from a previous checkpoint

* provide a MultiCellDS file (output000*N.xml) as a starting point to continue a simulation
* does not handle intracellular model state
* does not currently recover "output*_graph.txt" data; rather relies on the next mechanics step to recreate the information
* if a model relies on global data generated in custom C++ code that is not captured in the MultiCellDS data, it cannot be recovered
* an agent's `is_movable` flag is not currently saved in the MultiCellDS (.mat), so it will not be recovered

Normal simulation:

```
project config/cycle_phase_3cells_custom_vecs.xml # writes output to /output
```


Resume a simulation:

```
Usage options:
- no args: will try to use ./config/PhysiCell_settings.xml
- 1 arg: will try to use it as the config file
- 5 args to resume a simulation:
<.xml config file> <resume_folder> <resume_file> <next_full_index> <next_svg_index>

e.g. project config/PhysiCell_settings.xml output output00000042.xml 43 43

```

```
project config/cycle_phase_3cells_custom_vecs.xml output output00000048.xml 49 49
```


314 changes: 314 additions & 0 deletions unit_tests/resume_sim/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
/*
###############################################################################
# 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-2023, 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 <cstdio>
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <cmath>
#include <omp.h>
#include <fstream>

#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];
bool resume_from_checkpoint = false;
std::string resume_from_dir;
std::string resume_from_file;
int next_full_index, next_svg_index;

std::cout << "argc = " << argc << ", argv[0]=" << argv[0] << std::endl;
if( argc == 6 )
{
resume_from_checkpoint = true;

XML_status = load_PhysiCell_config_file( argv[1] );
if( !XML_status )
{ exit(-1); }

sprintf( copy_command , "cp %s %s" , argv[1] , PhysiCell_settings.folder.c_str() );
// copy config file to output directry
system( copy_command );

resume_from_dir = argv[2];
resume_from_file = argv[3];

next_full_index = std::stoi(argv[4]);
next_svg_index = std::stoi(argv[5]);
}
else if( argc == 2 )
{
XML_status = load_PhysiCell_config_file( argv[1] );
sprintf( copy_command , "cp %s %s" , argv[1] , PhysiCell_settings.folder.c_str() );
}
else if ( argc < 2 )
{
XML_status = load_PhysiCell_config_file( "./config/PhysiCell_settings.xml" );
sprintf( copy_command , "cp ./config/PhysiCell_settings.xml %s" , PhysiCell_settings.folder.c_str() );
}
else
{
std::string err_msg = "\nIncorrect arguments. Usage options: \n"
"- no args: will try to use ./config/PhysiCell_settings.xml\n"
"- 1 arg: will try to use it as the config file\n"
"- 5 args to resume a simulation:\n"
" <.xml config file> <resume_folder> <resume_file> <next_full_index> <next_svg_index>\n";

std::cout << err_msg << std::endl;
std::cout << " e.g. config/PhysiCell_settings.xml output output00000042.xml 43 43\n" << std::endl;
exit(-1);
}

if( !XML_status )
{ exit(-1); }

// 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();


//---------
if ( !resume_from_checkpoint )
{
setup_tissue();
}
else
{
// read in and resume from a checkpoint file (replaces setup_tissue)

// This sets PhysiCell_globals.current_time to be that of resumed checkpoint
// resume_from_MultiCellDS_xml("output_test_resume_phases_custom_vec", "output00000072.xml");

// int resume_from_MultiCellDS(std::string folder_path, std::string xml_filename, bool create_cells = true, bool debug_print = false);
int retval = resume_from_MultiCellDS(resume_from_dir, resume_from_file);
// int retval = resume_from_MultiCellDS(resume_from_dir, resume_from_file, true, true);

// Another option: don't recreate state, but print out state of cells
// int retval = resume_from_MultiCellDS(resume_from_dir, resume_from_file, false, true);
if (retval < 0)
{
std::cout << "Error in resume_from_MultiCellDS, exiting" << std::endl;
exit(-1);
}

// Need to adjust these values
PhysiCell_globals.next_full_save_time = PhysiCell_globals.current_time + PhysiCell_settings.full_save_interval;
PhysiCell_globals.next_SVG_save_time = PhysiCell_globals.current_time + PhysiCell_settings.SVG_save_interval;

PhysiCell_globals.full_output_index = next_full_index;
PhysiCell_globals.SVG_output_index = next_svg_index;
}

// 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<std::string> (*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 );

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"<<std::endl;
}

try
{
while( PhysiCell_globals.current_time < PhysiCell_settings.max_time + 0.1*diffusion_dt )
{
// save data if it's time.
if( PhysiCell_globals.current_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 );

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 );

std::cout << std::endl << "Total simulation runtime: " << std::endl;
BioFVM::display_stopwatch_value( std::cout , BioFVM::runtime_stopwatch_value() );

return 0;
}
Loading