From 25fa5025cb155d8c379d087c50b53e8447f66969 Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Fri, 27 May 2022 10:41:11 -0400 Subject: [PATCH 01/38] minor changes to phenotype.mechanics. starting new section in changes.md --- changes.md | 323 ++++++++++++++++++++++++++++++++++- core/PhysiCell_phenotype.cpp | 16 +- core/PhysiCell_phenotype.h | 15 +- 3 files changed, 341 insertions(+), 13 deletions(-) diff --git a/changes.md b/changes.md index 288db1e70..26206273f 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,318 @@ # PhysiCell: an Open Source Physics-Based Cell Simulator for 3-D Multicellular Systems +**Version:** 1.10.3-beta + +**Release date:** ? June 2022 + +## Overview: +PhysiCell is a flexible open source framework for building agent-based multicellular models in 3-D tissue environments. + +**Reference:** A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellular Systems, PLoS Comput. Biol. 14(2): e1005991, 2018. DOI: [10.1371/journal.pcbi.1005991](https://dx.doi.org/10.1371/journal.pcbi.1005991) + +Visit http://MathCancer.org/blog for the latest tutorials and help. + +**Notable recognition:** ++ [2019 PLoS Computational Biology Research Prize for Public Impact](https://blogs.plos.org/biologue/2019/05/31/announcing-the-winners-of-the-2019-plos-computational-biology-research-prize/) + +### Key makefile rules: + +**`make`** : compiles the current project. If no + project has been defined, it first + populates the cancer heterogeneity 2D + sample project and compiles it + +**`make project-name`**: populates the indicated sample project. + Use "make" to compile it. + + * **`project-name`** choices: + * template + * biorobots-sample + * cancer-biorobots-sample + * cancer-immune-sample + * celltypes3-sample + * heterogeneity-sample + * pred-prey-farmer + * virus-macrophage-sample + * worm-sample + * ode-energy-sample + * physiboss-cell-lines-sample + * cancer-metabolism-sample + * interaction-sample + +**`make list-projects`** : list all available sample projects + +**`make clean`** : removes all .o files and the executable, so that the next "make" recompiles the entire project + +**`make data-cleanup`** : clears out all simulation data + +**`make reset`** : de-populates the sample project and returns to the original PhysiCell state. Use this when switching to a new PhysiCell sample project. + +**`make jpeg`** : uses ImageMagick to convert the SVG files in the output directory to JPG (with appropriate sizing to make movies). Supply `OUTPUT=foldername` to select a different folder. + +**`make movie`** : uses ffmpeg to convert the JPG files in the output directory an mp4 movie. Supply `OUTPUT=foldername` to select a different folder, or `FRAMERATE=framerate` to override the frame rate. + +**`make upgrade`** : fetch the latest release of PhysiCell and overwrite the core library and sample projects. + +### Key Links +**Homepage:** http://PhysiCell.MathCancer.org + +**Downloads:** http://PhysiCell.sf.net + +**Support:** https://sourceforge.net/p/physicell/tickets/ + +**Quick Start:** Look at QuickStart.md in the documentation folder. + +**User Guide:** Look at UserGuide.pdf in the documentation folder. + +**Tutorials:** http://www.mathcancer.org/blog/physicell-tutorials/ + +**Latest info:** follow [@PhysiCell](https://twitter.com/PhysiCell) on Twitter (http://twitter.com/PhysiCell) + +See changes.md for the full change log. + +* * * +## Release summary: +Version 1.10.3 ... + +The 1.10.0 release introduced major new phenotype functionality, including standardized support for cell-cell interactions (phagocytosis, cell attack that increases a tracked damage variable, and cell fusion), cell transformations, advanced chemotaxis, and cell adhesion affinities for preferential adhesion. This release also includes new, auto-generated "dictionaries" of signals and behaviors to facilitate writing cell behavioral models and intracellular models, as well as standardized Hill and linear response functions for use in intracellular models. Lastly, this release includes a number of bugfixes, most notably pseudorandom number generators with improved thread safety. + +A blog post and tutorial on the new phenotype elements can be found at http://www.mathcancer.org/blog/introducing-cell-interactions-and-transformations. + +A blog post and tutorial on the new signal and behavior dictionaries can be found at http://www.mathcancer.org/blog/introducing-cell-signal-and-behavior-dictionaries. + +**NOTE 1:** MacOS users need to define a PHYSICELL_CPP environment variable to specify their OpenMP-enabled g++. See the [Quickstart](documentation/Quickstart.md) for details. + +**NOTE 2:** Windows users need to follow an updated (from v1.8) MinGW64 installation procedure. This will install an updated version of g++, plus libraries that are needed for some of the intracellular models. See the [Quickstart](documentation/Quickstart.md) for details. + +### Major new features and changes in the 1.10.z versions +#### 1.10.3 ++ None in this version. See 1.10.0 +#### 1.10.2 ++ None in this version. See 1.10.0 +#### 1.10.1 ++ None in this version. See 1.10.0 +#### 1.10.0 ++ Created `Cell_Interactions` in `Phenotype` as a standard representation of essential cell-cell interactions, including phagocytosis, "attack", and fusion. + + Users can set phagocytosis rates for dead cells via `phenotype.cell_interactions.dead_phagocytosis_rate`. Cells automatically phagocytose live and dead neighbors at each mechancis time step based upon the phagocytosis rates. + + Users can set phagocytosis rates for each live cell type via `phenotype.cell_interactions.live_phagocytosis_rates`. There is one rate for each cell type in the simulation. Cells automatically phagocytose live and dead neighbors at each mechancis time step based upon the phagocytosis rates. Phagocytosis absorbs the target cell's volume and internal contents and flags the target for removal. The cell will eventually shrink back towards its target volume. + + For convenience, the phagocytosis rates can be accessed (read or written) via `phenotype.cell_interactions.live_phagocytosis_rate(name)` where `name` (a `std::string`) is the human-readable name of a cell type. + + Users can set attack rates for live cells via `phenotype.cell_interactions.attack_rates`. There is one rate for each cell type in the simulation. Cells automaticaly attack neighbors at each mechanics time step based upon the rates. An attack event increases the target cell's `cell.state.damage` by `damage_rate * dt_mechanics` and `cell.state.total_attack_time` by `dt_mechanics`. It is up to the scientist user to set additional hypotheses that increases cell death with accumulated damage or attack time. + + For convenience, the attack rates can be accessed via `phenotype.cell_interactions.attack_rate(name)` where `name` (a `std::string`) is the human-readable name of a cell type. + + Users can set fusion rates for live cells via `phenotype.cell_interactions.fusion_rates`. There is one rate for each cell type in the simulation. Cells automaticaly fuse with at each mechanics time step based upon the rates. Fusion will merge the two cells' volumes and internal contents, add their nuclei (recorded in `cell.state.number_of_nuclei`), and move the combine cell to the prior center of volume. The combined cell's new target volume is the sum of the two original cells' target volumes. + + For convenience, the fusion rates can be accessed via `phenotype.cell_interactions.fusion_rate(name)` where `name` (a `std::string`) is the human-readable name of a cell type. + ++ Created `Cell_Transformations` in `Phenotype` as a standard representation of cell transformations such as differentation or transdifferentiation. + + Users can set transformation rates for each live cell type via `phenotype.cell_transformations_transformation_rates`. There is one rate for each cell type in the simulation. Cells automatically attempt to transform to these types at each phenotype time step based upon the phagocytosis rates. + + For convenience, the transformation rates can be accessed (read or written) via `phenotype.cell_transformations.transformation_rate(name)` where `name` (a `std::string`) is the human-readable name of a cell type. + ++ Updated `Cell_State` to track the number of nuclei (for fusion), total damage (e.g., for cell attack) and total attack time. + ++ Added a new `advanced_chemotaxis` function with data stored in `phenotype.motility` to allow chemotaxis up a linear combination of gradients. + + `cell.phenotype.motility.chemotactic_sensitivities` is a vector of chemotactic sensitivies, one for each substrate in the environment. By default, these are all zero for backwards compatibility. A positive sensitivity denotes chemotaxis up a corresponding substrate's gradient (towards higher values), whereas a negative sensitivity gives chemotaxis against a gradient (towards lower values). + + For convenience, you can access (read and write) a substrate's chemotactic sensitivity via `phenotype.motility.chemotactic_sensitivity(name)`, where `name` is the human-readable name of a substrate in the simulation. + + If the user sets `cell.cell_functions.update_migration_bias = advanced_chemotaxis_function`, then these sensitivities are used to set the migration bias direction via `d_mot = sensitivity_0 * grad(rho_0) + sensitivity_1 * grad(rho_1) + ... + sensitivity_n * grad(rho_n)`. + + If the user sets `cell.cell_functions.update_migration_bias = advanced_chemotaxis_function_normalized`, then these sensitivities are used to set the migration bias direction via `d_mot = sensitivity_0 * |grad(rho_0)| + sensitivity_1 * |grad(rho_1)| + ... + sensitivity_n * |grad(rho_n)|.` + ++ Added a new `adhesion_affinities` to `phenotype.mechanics` to allow preferential adhesion. + + `cell.phenotype.mechanics.adhesion_affinities` is a vector of adhesive affinities, one for each cell type in the simulation. By default, these are all one for backwards compatibility. + + For convenience, you can access (read and write) a cell's adhesive affinity for a specific cell type via `phenotype.mechanics.adhesive_affinity(name)`, where `name` is the human-readable name of a cell type in the simulation. + + The standard mechanics function (based on potentials) uses this as follows. If cell `i` has an cell-cell adhesion strength `a_i` and an adhesive affinity `p_ij` to cell type `j` , and if cell `j` has a cell-cell adhesion strength of `a_j` and an adhesive affinity `p_ji` to cell type `i`, then the strength of their adhesion is `sqrt( a_i p_ij a_j p_ji )`. Notice that if `a_i = a_j` and `p_ij = p_ji`, then this reduces to `a_i a_pj`. + + The standard elastic spring function (`standard_elastic_contact_function`) uses this as follows. If cell `i` has an elastic constant `a_i` and an adhesive affinity `p_ij` to cell type `j` , and if cell `j` has an elastic constant `a_j` and an adhesive affinity `p_ji` to cell type `i`, then the strength of their adhesion is `sqrt( a_i p_ij a_j p_ji )`. Notice that if `a_i = a_j` and `p_ij = p_ji`, then this reduces to `a_i a_pj`. + ++ `PhysiCell_basic_signaling` now includes standard Hill and linear response functions: + + `Hill_response_function( double s, double half_max , double hill_power )` is a Hill function responding to signal `s` with a half-max of `half_max` and Hill coefficient of `hill_power`. We note that this function is an order of magnitude faster when the `hill_power` is an integer (e.g., 1 or 2) rather than a non-integer power (e.g., 1.4). + + `double linear_response_function( double s, double s_min , double s_max )` is a linear ramping from 0.0 (for inputs `s` below `s_min`) to 1.0 (for inputs `s` above `s_max`). The outputs are clamped to the range [0,1]. + + `double decreasing_linear_response_function( double s, double s_min , double s_max )` is a linear ramping from 1.0 (for inputs `s` below `s_min`) to 0.0 (for inputs `s` above `s_max`). The outputs are clamped to the range [0,1]. + ++ We introduced a "dictionary" of standard signals that can be used as inputs to intracellular and rule-based models. This dictionary is automatically constructed at the start of each simulation based upon the combinations of signaling substrates and cell types. + + Major classes of signals include: + + extracellular and intracellular substrate concentrations + + substrate gradients + + contact with dead cells + + contact with cells (of type X) + + damage + + pressure + + Use `display_signal_dictionary()` to quickly display a list of available signals. + + Substantial functionality to query signals + + `int find_signal_index( std::string signal_name )` : get the index of the named signal + + `std::vector find_signal_indices( std::vector signal_names );` get a vector of indices for a vector of named signals + + `std::string signal_name( int i );` display the name of the signal with the given index + + `std::vector get_signals( Cell* pCell );` get a vector of all known signals for the cell + + `std::vector get_cell_contact_signals( Cell* pCell );` get a vector of the cell contact associated signals for the cell + + `std::vector get_selected_signals( Cell* pCell , std::vector indices );` get a vector of signals for the cell, with the supplied indices + + `std::vector get_selected_signals( Cell* pCell , std::vector names );` get a vector of signals for the cell, with the supplied human-readable names of the signals + + `double get_single_signal( Cell* pCell, int index );` get a single signal for the cell with the indicated index + + `double get_single_signal( Cell* pCell, std::string name );` get a single signal for the cell with the indicated human-readable name + ++ We introduced a "dictionary" of standard behaviors that can be used as outputs to intracellular and rule-based models. This dictionary is automatically constructed at the start of each simulation based upon the combinations of signaling substrates and cell types. + + Major classes of behaviors include: + + secretion, secretion target, uptake, and export rates + + cycle progression + + death rates + + motility parameters + + chemotactic parameters + + cell-cell adhesion and repulsion parameters + + cell adhesion affinities + + cell-BM adhesion and repulsion parameters + + phagocytosis rates + + attack rates + + fusion rates + + transformation rates + + Use `display_behavior_dictionary()` to quickly see a list of posible behaviors. + + Substantial functionality to query and set behaviors + + `int find_behavior_index( std::string response_name )` : get the index of the named behavior + + `std::vector find_behavior_indices( std::vector behavior_names )` get the indices for the given vector of behavior names. + + `std::string behavior_name( int i );` get the name of the behavior with the given index + + `std::vector create_empty_behavior_vector();` create an empty vector for the full set of behaviors + + `void set_behaviors( Cell* pCell , std::vector parameters );` write the full set of behaviors to the cell's phentoype + + `void set_selected_behaviors( Cell* pCell , std::vector indices , std::vector parameters );` write the selected set of behaviors (with supplied indices) to the cell's phenotype + + `void set_selected_behaviors( Cell* pCell , std::vector names , std::vector parameters );` write the selected set of behaviors (with supplied names) to the cell's phenotype + + `void set_single_behavior( Cell* pCell, int index , double parameter );` write a single behavior (by index) to the cell phentoype + + `void set_single_behavior( Cell* pCell, std::string name , double parameter );` write a single behavior (by name) to the cell phentoype + + Substantial functionality to query the cell's current behavior + + `std::vector get_behaviors( Cell* pCell );` get all the cell's current behaviors + + `std::vector get_behaviors( Cell* pCell , std::vector indices );` get a subset of behaviors (with given indices) + + `std::vector get_behaviors( Cell* pCell , std::vector names );` get a subset of behaviors (with given names) + + `double get_single_behavior( Cell* pCell , int index );` get a single behavior (by index) + + `double get_single_behavior( Cell* pCell , std::string name );` get a single behavior (by name) + + Substantial functionality to query the cell's referece behaviors (from its cell definition) + + `std::vector get_base_behaviors( Cell* pCell );` get all the cell's base behaviors + + `std::vector get_base_behaviors( Cell* pCell , std::vector indices );` get a subset of base behaviors (with given indices) + + `std::vector get_base_behaviors( Cell* pCell , std::vector names );` get a subset of base behaviors (with given names) + + `double get_single_base_behavior( Cell* pCell , int index );` get a single base behavior (by index) + + `double get_single_base_behavior( Cell* pCell , std::string name );` get a single base behavior (by name) + ++ Created a new `interaction-sample` project to illustrate the new interactions and transformations: + + Blood vessels release resource + + Virulet bacteria colonize near vessels (by chemotaxis up towards a secreted quorum factor and resource) + + Stem cells divide and differentiate into differentiated cells + + Differentiated cells divide until experiencing elevated pressure (to detect confluence) + + Bacteria-secreted virulence factor kills stem and differentiated cells. Dead cells release debris. + + Macrophages chemotax towards quorum factor and debris and secrete pro-inflammatory factor in presence of dead cells or bacteria + + Macrophages phagocytose dead cells + + CD8+ T cells chemotax towards pro-inflamatory factor and attack bacteria + + Neutrophils chemotax towards pro-inflammatory factor and phagocytose live bacteria + + Accumulated damage kills bacteria. + + With default parameters, bacteria kill off cells ot form abscesses, until death attracts macrophages to activate immune response to kill the invaders, after which the tissue can regrow. + +### Minor new features and changes: +#### 1.10.3 ++ Added `attachment_rate` and `detachment_rate` to `phenotype.mechanics` for use in a future standard attachment and detachment model. + +#### 1.10.2 ++ Added `operator<<` for vectors of ints and vectors of strings. So that `std::cout << v << std::endl;` will work if `v` is `std::vector` of `std::vector`. It was truly annoying that these were missing, so sorry! ++ Added `dead` to the signals dictionaries, which returns 0.0 or 1.0 based on `phenotype.death.dead`. ++ Added `time` to the signals dictionaries, which returns the current simulation time based on `PhysiCell_Globals.current_time`. ++ Added a brief protocol on how to add new signals and behaviors to the dictionaries in the `/protocols` directory. ++ Added new functions `double& apoptosis_rate()` and `double& necrosis_rate()` to easily read and write these rates. Access via `cell.phenotype.death.apoptosis_rate()` and `cell.phenotype.death.necrosis_rate()`. ++ Added new ease of access functions for secretion: + + `double& Secretion::secretion_rate( std::string name )` allows you to easily read/write the secretion rate of a substrate by name. For example: + ```pCell->phenotype.secretion.secretion_rate("oxygen") = 0.1``` + + `double& Secretion::uptake_rate( std::string name )` allows you to easily read/write the uptake rate of a substrate by name. For example: + ```pCell->phenotype.secretion.uptake_rate("oxygen") = 0.1``` + + `double& Secretion::saturation_density( std::string name )` allows you to easily read/write the secretion target of a substrate by name. For example: + ```pCell->phenotype.secretion.saturation_density("oxygen") = 38``` + + `double& Secretion::net_export_rate( std::string name )` allows you to easily read/write the net export rate of a substrate by name. For example: + ```pCell->phenotype.secretion.net_export_rate("oxygen") = -100``` + ++ Added new ease of access function for internalized substrates: + + `double& Molecular::internalized_total_substrate( std::string name )` allows you to easily read/write the total amount of internalized substrate by name. For example: + ```pCell->phenotype.molecular.internalized_total_substrate( "oxygen" ) = 0.01`` + +#### 1.10.1 ++ None in this version. See 1.10.0. +#### 1.10.0 ++ All sample projects have a new rule "make name" to tell you the name of the executable. + ++ All sample projects output the executable name to screen for easier reference. + ++ `Cell_Definition` has a new Boolean `is_movable`, so that all cells of a type can be set to non-movable. (Default: `is_movable = true`;) This allows you to use agents as rigid objects or barriers. + ++ `create_cell( Cell_Definition )` now uses "`is_movable`" from the cell definition. + +### Beta features (not fully supported): +#### 1.10.3 ++ None in this version. See 1.10.0. +#### 1.10.2 ++ None in this version. See 1.10.0. +#### 1.10.1 + + None in this version. See 1.10.0. + #### 1.10.0 ++ Started writing a standardized set of functions for Hill functions and promoter/inhibitor signaling. + ++ [Model Builder Tool](https://github.com/PhysiCell-Tools/PhysiCell-model-builder/releases) + ++ Added a simple Qt GUI for plotting cells only (plot_cells.py and vis_tab_cells_only.py in /beta) + ++ Added a simple Qt GUI for plotting substrates and cells (plot_data.py and vis_tab.py in /beta) + ++ Added simple contour plotting of a substrate (anim_substrate2D.py in /beta; copy to /output) + +### Bugfixes: +#### 1.10.3 ++ None in this version. +#### 1.10.2 ++ Fixed error in `double get_single_behavior()` where the `cell-cell adhesion elastic constant` behavior was not found. + ++ Fixed error in `double get_single_base_behavior()` where the `cell-cell adhesion elastic constant` behavior was not found. + ++ Fixed bug in `add_PhysiCell_cells_to_open_xml_pugi()` that mistakenly used the wrong size (number of cell species rather than number of substrate species) when writing the chemotactic sensitivities. + ++ The cell `neighbors` list did not add non-adhesive cells within interaction distance. This is now fixed. + +#### 1.10.1 ++ XML parsing has been made more robust to "survive" using an incorrect substrate in the `chemotactic_sensitivities` section. + ++ Missing PhysiBoSS makefiles have been replaced. + ++ Fixed broken makefile for worms sample project. + +#### 1.10.0 ++ When the `cell_defaults` definition has been altered, new cell types may unwittingly copy nonzero parameter values from this default. Now, immediately after copying `cell_defaults`, the XML parsing will reset motility to off (with `NULL` function for bias direction), reset all secretion/uptake/export to zero, reset all cell interactions and transformations to zero. It will then continue to parse the XML file. Set `legacy_cell_defaults_copy = true` in the config file to override this bugfix. + ++ We refactored the pseudorandom number generator (at the basis of `UniformRandom()`) to improve thread safety. Previously, all threads shared a single PRNG, which was not thread safe. For newer fast processors with many threads, this could lead to sufficiently many "collisions" to introduce subtle biases in some cases (particularly for purely Brownian motion that is not dominated by chemotaxis, proliferation, and other behaviors). This is now corrected by creating a PRNG for each thread, each with its own seed. We used `std::seed_seq` to determinstically set a good spread of seeds to prevent correlation between the PRNGs, with the convention that the 0th thread's seed is either the user-specified seed or a random seed. This preserves original single-thread behavior from prior versions. + ++ Random motility now uses `UniformOnUnitCircle()` (in 2D) and `UniformOnUnitSphere()` (in 3D) to choose the random component of the migration direction, rather than hand-coding selection of the random vector. + ++ In response to PR 91 (https://github.com/MathCancer/PhysiCell/pull/91): Previoulsy, if the make jpeg rule fails, the `__*.txt` temporary files are left in place, so a subsequent "make jpeg" fails until these files are manually removed. Replacing `>>` (append) with `>` (overwrite) fixes the problem. Thanks [saikiRA1011](https://github.com/saikiRA1011)! + +### Notices for intended changes that may affect backwards compatibility: ++ We intend to deprecate the unused phenotype variables `relative_maximum_attachment_distance`, `relative_detachment_distance`, and `maximum_attachment_rate` from `phenotype.mechanics.` + ++ We intend to merge `Custom_Variable` and `Custom_Vector_Variable` in the very near future. + ++ We may change the role of `operator()` and `operator[]` in `Custom_Variable` to more closely mirror the functionality in `Parameters`. + ++ Some search functions (e.g., to find a substrate or a custom variable) will start to return -1 if no matches are found, rather than 0. + ++ We will change the timing of when `entry_function`s are executed within cycle models. Right now, they are evaluated immediately after the exit from the preceding phase (and prior to any cell division events), which means that only the parent cell executes it, rather than both daughter cells. Instead, we'll add an internal Boolean for "just exited a phase", and use this to execute the entry function at the next cycle call. This should make daughter cells independently execute the entry function. + ++ We might make `trigger_death` clear out all the cell's functions, or at least add an option to do this. + +### Planned future improvements: + ++ Further XML-based simulation setup. + ++ Read saved simulation states (as MultiCellDS digital snapshots) + ++ Add a new standard phenotype function that uses mechanobiology, where high pressure can arrest cycle progression. (See https://twitter.com/MathCancer/status/1022555441518338048.) + ++ Add module for standardized pharmacodynamics, as prototyped in the nanobio project. (See https://nanohub.org/resources/pc4nanobio.) + ++ Create an angiogenesis sample project + ++ Create a small library of angiogenesis and vascularization codes as an optional standard module in ./modules (but not as a core component) + ++ Improved plotting options in SVG + ++ Further update sample projects to make use of more efficient interaction testing available + ++ Major refresh of documentation. + +* * * + +# PhysiCell: an Open Source Physics-Based Cell Simulator for 3-D Multicellular Systems + **Version:** 1.10.2 **Release date:** 24 May 2022 @@ -16,15 +329,15 @@ Visit http://MathCancer.org/blog for the latest tutorials and help. ### Key makefile rules: -**make** : compiles the current project. If no +**`make`** : compiles the current project. If no project has been defined, it first populates the cancer heterogeneity 2D sample project and compiles it -**make \[project-name\]**: populates the indicated sample project. +**`make project-name`**: populates the indicated sample project. Use "make" to compile it. - * **\[project-name\]** choices: + * **`project-name`** choices: * template * biorobots-sample * cancer-biorobots-sample @@ -39,9 +352,9 @@ Visit http://MathCancer.org/blog for the latest tutorials and help. * cancer-metabolism-sample * interaction-sample -**make list-projects** : list all available sample projects +**`make list-projects`** : list all available sample projects -**make clean** : removes all .o files and the executable, so that the next "make" recompiles the entire project +**`make clean`** : removes all .o files and the executable, so that the next "make" recompiles the entire project **make data-cleanup** : clears out all simulation data diff --git a/core/PhysiCell_phenotype.cpp b/core/PhysiCell_phenotype.cpp index 7626eb29a..e6e5d49a5 100644 --- a/core/PhysiCell_phenotype.cpp +++ b/core/PhysiCell_phenotype.cpp @@ -685,12 +685,20 @@ Mechanics::Mechanics() // this is a multiple of the cell (equivalent) radius relative_maximum_adhesion_distance = 1.25; // maximum_adhesion_distance = 0.0; - - - relative_maximum_attachment_distance = relative_maximum_adhesion_distance; - relative_detachment_distance = relative_maximum_adhesion_distance; + + /* for spring attachments */ maximum_number_of_attachments = 12; attachment_elastic_constant = 0.01; + + attachment_rate = 10; + detachment_rate = 0; + + /* to be deprecated */ + relative_maximum_attachment_distance = relative_maximum_adhesion_distance; + relative_detachment_distance = relative_maximum_adhesion_distance; + + maximum_attachment_rate = 1.0; + maximum_attachment_rate = 1.0; return; diff --git a/core/PhysiCell_phenotype.h b/core/PhysiCell_phenotype.h index 8269700c6..eb02accac 100644 --- a/core/PhysiCell_phenotype.h +++ b/core/PhysiCell_phenotype.h @@ -375,12 +375,19 @@ class Mechanics // this is a multiple of the cell (equivalent) radius double relative_maximum_adhesion_distance; // double maximum_adhesion_distance; // needed? - - double relative_maximum_attachment_distance; - double relative_detachment_distance; - + + /* for spring attachments */ + int maximum_number_of_attachments; double attachment_elastic_constant; + + double attachment_rate; + double detachment_rate; + + /* to be deprecated */ + + double relative_maximum_attachment_distance; + double relative_detachment_distance; double maximum_attachment_rate; Mechanics(); // done From a50920ef61b5339a234d3c5090d7a413c9b60b7f Mon Sep 17 00:00:00 2001 From: Randy Heiland Date: Fri, 27 May 2022 19:00:08 -0400 Subject: [PATCH 02/38] parse more mechanics params --- core/PhysiCell_cell.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/core/PhysiCell_cell.cpp b/core/PhysiCell_cell.cpp index bd21c6c44..768bb3623 100644 --- a/core/PhysiCell_cell.cpp +++ b/core/PhysiCell_cell.cpp @@ -1706,6 +1706,18 @@ void display_cell_definitions( std::ostream& os ) // mechanics + + Mechanics* pMech = &(pCD->phenotype.mechanics); + + os << "\tmechanics:" << std::endl + << "\t\tcell_cell_adhesion_strength: " << pMech->cell_cell_adhesion_strength << std::endl + << "\t\tcell_cell_repulsion_strength: " << pMech->cell_cell_repulsion_strength << std::endl + << "\t\trel max adhesion dist: " << pMech->relative_maximum_adhesion_distance << std::endl + << "\t\tcell_BM_adhesion_strength: " << pMech->cell_BM_adhesion_strength << std::endl + << "\t\tcell_BM_repulsion_strength: " << pMech->cell_BM_repulsion_strength << std::endl + << "\t\tattachment_elastic_constant: " << pMech->attachment_elastic_constant << std::endl + << "\t\tattachment_rate: " << pMech->attachment_rate << std::endl + << "\t\tdetachment_rate: " << pMech->detachment_rate << std::endl; // size @@ -2421,10 +2433,18 @@ Cell_Definition* initialize_cell_definition_from_pugixml( pugi::xml_node cd_node if( node_mech ) { pM->cell_cell_adhesion_strength = xml_get_my_double_value( node_mech ); } + node_mech = node.child( "cell_BM_adhesion_strength" ); + if( node_mech ) + { pM->cell_BM_adhesion_strength = xml_get_my_double_value( node_mech ); } + node_mech = node.child( "cell_cell_repulsion_strength" ); if( node_mech ) { pM->cell_cell_repulsion_strength = xml_get_my_double_value( node_mech ); } + node_mech = node.child( "cell_BM_repulsion_strength" ); + if( node_mech ) + { pM->cell_BM_repulsion_strength = xml_get_my_double_value( node_mech ); } + node_mech = node.child( "relative_maximum_adhesion_distance" ); if( node_mech ) { pM->relative_maximum_adhesion_distance = xml_get_my_double_value( node_mech ); } @@ -2474,6 +2494,20 @@ Cell_Definition* initialize_cell_definition_from_pugixml( pugi::xml_node cd_node } } } + + node_mech = node.child( "attachment_elastic_constant" ); + if( node_mech ) + { pM->attachment_elastic_constant = xml_get_my_double_value( node_mech ); } + std::cout << " --------- attachment_elastic_constant = " << pM->attachment_elastic_constant << std::endl; + + node_mech = node.child( "attachment_rate" ); + if( node_mech ) + { pM->attachment_rate = xml_get_my_double_value( node_mech ); } + + node_mech = node.child( "detachment_rate" ); + if( node_mech ) + { pM->detachment_rate = xml_get_my_double_value( node_mech ); } + } // motility From 0a469b2f789107012595ee5cd20dbf8a580ad192 Mon Sep 17 00:00:00 2001 From: Randy Heiland Date: Thu, 2 Jun 2022 11:25:50 -0400 Subject: [PATCH 03/38] add new mechanics params --- sample_projects/template/config/PhysiCell_settings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sample_projects/template/config/PhysiCell_settings.xml b/sample_projects/template/config/PhysiCell_settings.xml index 01e526a5a..f00a8301a 100644 --- a/sample_projects/template/config/PhysiCell_settings.xml +++ b/sample_projects/template/config/PhysiCell_settings.xml @@ -260,6 +260,11 @@ 1.8 15.12 + 4.0 + 10.0 + 0.01 + 10.0 + 0.0 From 2a4574ab5b3c573780f0cb678f8da3385fbac5ec Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Fri, 3 Jun 2022 04:11:06 -0400 Subject: [PATCH 04/38] mcds 2.0 output --- ALL_CITATIONS.txt | 4 + Makefile | 216 +--- config/PhysiCell_settings.xml | 1871 +++++++++++++++++++++++------ config/cells.csv | 11 + custom_modules/custom.cpp | 793 ++++++++++++ custom_modules/custom.h | 101 ++ main-backup.cpp | 0 main.cpp | 257 ++++ modules/PhysiCell_MultiCellDS.cpp | 1151 ++++++++++++++++++ modules/PhysiCell_MultiCellDS.h | 15 + pyMCDS2.py | 520 ++++++++ 11 files changed, 4360 insertions(+), 579 deletions(-) create mode 100644 ALL_CITATIONS.txt create mode 100644 config/cells.csv create mode 100644 custom_modules/custom.cpp create mode 100644 custom_modules/custom.h create mode 100644 main-backup.cpp create mode 100644 main.cpp create mode 100644 pyMCDS2.py diff --git a/ALL_CITATIONS.txt b/ALL_CITATIONS.txt new file mode 100644 index 000000000..338d8385d --- /dev/null +++ b/ALL_CITATIONS.txt @@ -0,0 +1,4 @@ +Using PhysiCell version 1.10.2 + Please cite DOI: 10.1371/journal.pcbi.1005991 + Project website: http://PhysiCell.MathCancer.org + diff --git a/Makefile b/Makefile index 595ea5cd2..602d17216 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ VERSION := $(shell grep . VERSION.txt | cut -f1 -d:) -PROGRAM_NAME := project +PROGRAM_NAME := interaction_demo CC := g++ # CC := g++-mp-7 # typical macports compiler name @@ -14,8 +14,17 @@ 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 @@ -49,194 +58,24 @@ 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 +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) -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 +# compile the project -all: - make heterogeneity-sample - make +all: main.cpp $(ALL_OBJECTS) + $(COMPILE_COMMAND) -o $(PROGRAM_NAME) $(ALL_OBJECTS) main.cpp + make name 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" - @echo "" - @echo "Sample intracellular projects: ode-energy-sample physiboss-cell-lines-sample cancer-metabolism-sample" - @echo "" - -template: - cp ./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 ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml - cp ./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-biorobots.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-cancer_biorobots.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-heterogeneity.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/ - -# ---- 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/ - -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/ - - -# 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 @@ -262,7 +101,7 @@ PhysiCell_custom.o: ./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 @@ -311,25 +150,28 @@ PhysiCell_MultiCellDS.o: ./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 + $(COMPILE_COMMAND) -c ./modules/PhysiCell_settings.cpp PhysiCell_basic_signaling.o: ./core/PhysiCell_basic_signaling.cpp - $(COMPILE_COMMAND) -c ./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 PhysiCell_cell.o + rm -f *.cpp cp ./sample_projects/Makefile-default Makefile rm -f ./custom_modules/* touch ./custom_modules/empty.txt @@ -338,7 +180,7 @@ reset: rm ALL_CITATIONS.txt cp ./config/PhysiCell_settings-backup.xml ./config/PhysiCell_settings.xml touch ./config/empty.csv - rm ./config/*.csv + rm -f ./config/*.csv clean: rm -f *.o @@ -348,9 +190,9 @@ 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/* @@ -421,4 +263,4 @@ upgrade: $(SOURCE) unzip $(SOURCE) PhysiCell/documentation/User_Guide.pdf mv -f PhysiCell/documentation/User_Guide.pdf documentation rm -f -r PhysiCell - rm -f $(SOURCE) + rm -f $(SOURCE) \ No newline at end of file diff --git a/config/PhysiCell_settings.xml b/config/PhysiCell_settings.xml index 5164a3782..68404dc82 100644 --- a/config/PhysiCell_settings.xml +++ b/config/PhysiCell_settings.xml @@ -1,83 +1,9 @@ - - - - - - -500 - 500 - -500 - 500 + -400 + 400 + -400 + 400 -10 10 20 @@ -87,7 +13,7 @@ - 7200 + 10080 min micron @@ -97,19 +23,19 @@ - 4 + 6 - output + output - 60 + 180 true - 15 + 30 true @@ -120,330 +46,1491 @@ false + true + false - - - 100.0 - 0 - - 1 - 0 - - - - - - - 1000.0 - .1 - - 0 - 0 - - - - - - - 1000.0 - .1 - - 0 - 0 - - - + + + 100000.0 + 0.1 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + - - + + + 100 + 0.1 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 1000 + 0.1 + + 0.0 + 0.0 + + + + + + + + + + + + 1000 + 0.01 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 1000 + 0.1 + + 0.0 + 0.0 + + + + + + + + + + true true - - + + ./config/initial.mat - - + + ./config/dirichlet.mat - - - - - - - - - 0.0 - - - - - - - - - 0 - - - - 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 - 10.0 - 1.25 - - - 1.8 - 15.12 - - - - - 0.25 - 5 - 0.5 - - - true - true - - false - food - -1 - - - - - - - 100 - 1 - 0 - 0 - - - - 0 - 1 - 0 - 0 - - - - 0 - 1 - 0 - 0 - - - - - - - 1.0 - 1.0 - 1.0 - - -1 - -1 - -10 - - - - - - - - - - - - 0.003 - - - - - 0 - 1 - - - - 10 - - - - 0.5 - 5 - 0.5 - - true - true - - false - food - 1 - - - - - - 1.0 - 1.0 - 1.0 - - -100 - 10 - 1 - - - - - - - - 0 - 0 - - - - 10 - - - - 0.5 - 2.5 - 0.7 - - - true - true - - false - prey signal - 1 - - - - - - 1.0 - 1.0 - 1.0 - - -2 - 100 - 1 - - - - + + + + + 0.00028 + + + + + + 0.00028 + + 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 + + + + + + 500 + 0.75 + 499 + 0.05 + 0.0045 + 0.0055 + 0 + 0 + 2.0 + + + + 0.04 + 20.0 + 1.25 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + + 1.8 + 15.12 + + + + + 1 + 5 + 0.2 + + true + true + + false + resource + 1 + + + + true + false + + 1 + 0 + 0.1 + 0 + 0 + + + + + + + + + 0 + 1 + 30 + 0 + + + 0.0 + 0.0 + 0.0 + 100 + + + 0 + 0.0 + 0.0 + 1 + + + 0.0 + 0.0 + 0.0 + 0.0 + + + 0.0 + 0.0 + 0.0 + 0.0 + + + + 0 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + 1 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + 0.15 + 0.075 + 0.15 + 0.25 + 0.5 + 0.0 + 0.0 + 0.0 + 0.0 + 36 + 100 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + + + + + + + + 0 + + + + + + 0 + + 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.4 + 10.0 + 1.25 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 1.8 + 15.12 + + + + + 1 + 1 + .5 + + false + true + + false + debris + 1 + + + + false + false + + 0 + 0 + 0 + 0 + 0 + + + + + + + + + 1000 + 1 + 0 + 0 + + + 0.0 + 0.0 + 0 + 0.0 + + + 0.0 + 0.0 + 0 + 0.0 + + + 0.0 + 0.0 + 0.0 + 0.0 + + + 0.0 + 0.0 + 0.0 + 0.0 + + + + 0 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + 1 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0.15 + 0.075 + 0.15 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + + + + + + + + 0.002 + + + + + + 5.3e-08 + + 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.4 + 10.0 + 1.25 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 1.8 + 15.12 + + + + + 1 + 1 + .5 + + false + true + + false + debris + 1 + + + + false + false + + 0 + 0 + 0 + 0 + 0 + + + + + + + + + 0 + 1 + 1 + 0 + + + 0.0 + 0.0 + 0 + 0.0 + + + 0.0 + 0.0 + 0.0 + 0.0 + + + 0.0 + 0.0 + 0.0 + 0.0 + + + 0.0 + 0.0 + 0.0 + 0.0 + + + + 0 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + 1 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + 0 + 0 + 0 + 0.0001 + 0 + 0 + 0 + + + + + + 0.15 + 0.075 + 0.15 + 0.0 + 0.0 + 0.4 + 100 + 0.1 + 0.1 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + + + + + + + + 5.3e-4 + + + + + + 5.3e-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.4 + 10.0 + 1.25 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 1.8 + 15.12 + + + + + 1 + 1 + .5 + + false + true + + false + debris + 1 + + + + false + false + + 0 + 0 + 0 + 0 + 0 + + + + + + + + + 0 + 1 + 10 + 0 + + + 0.0 + 0.0 + 0 + 0.0 + + + 0.0 + 0.0 + 0.0 + 0.0 + + + 0.0 + 0.0 + 0.0 + 0.0 + + + 0.0 + 0.0 + 0.0 + 0.0 + + + + 0 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + 1 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0.15 + 0.075 + 0.15 + 0.0 + 0.0 + 0.2 + 100 + 0.0 + 0.0 + 0.0 + 0.0 + 0.5 + 0.0 + 0.0 + 0.0 + 0.0 + + + + + + + + 0 + + + + + + 0 + + 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 + + + + + + 3000 + 0.75 + 600 + 0.05 + 0.045 + 0.0055 + 0 + 0 + 2.0 + + + + 0.04 + 10.0 + 1.25 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 1.8 + 15.12 + + + + + 1 + 5 + 0.1 + + true + true + + false + debris + 1 + + + + true + false + + 0 + 0 + 1 + 0 + 0.1 + + + + + + + + + 0 + 1 + 5 + 0 + + + 0.0 + 0.0 + 0.0 + 0 + + + 0.0 + 0.0 + 0.0 + 0 + + + 0.0 + 1.0 + 0 + 0.0 + + + 0.0 + 0.0 + 5 + 0.0 + + + + 0.05 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + 1 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0.15 + 0.075 + 0.15 + 0.05 + 0.01 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.005 + 0.1 + 1 + 0 + + + + + + + + 0 + + + + + + 0 + + 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 + + + + + + 3000 + 0.75 + 600 + 0.05 + 0.0045 + 0.0055 + 0 + 0 + 2.0 + + + + 0.04 + 10.0 + 1.25 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 1.8 + 15.12 + + + + + 1 + 5 + 0.1 + + true + true + + true + pro-inflammatory + 1 + + + + false + false + + 0 + 0 + 0 + 0 + 0 + + + + + + + + + 0 + 1 + 5 + 0 + + + 0.0 + 0.0 + 0.0 + 0 + + + 0.0 + 0.0 + 0.0 + 0 + + + 0.0 + 0.0 + 1 + 0.0 + + + 0.0 + 0.0 + 0 + 0.0 + + + + 0 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 10 + 0 + 0 + 0 + 0 + 0 + 0 + + 1 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0.15 + 0.075 + 0.15 + 0.0 + 0.5 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + + + + + + + + 0 + + + + + + 0 + + 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 + + + + + + 1000 + 0.75 + 200 + 0.05 + 0.045 + 0.0055 + 0 + 0 + 2.0 + + + + 0.04 + 10.0 + 1.25 + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 1.8 + 15.12 + + + + + 1 + 5 + 0.1 + + true + true + + true + pro-inflammatory + 1 + + + + false + false + + 0 + 0 + 0 + 0 + 0 + + + + + + + + + 0 + 1 + 5 + 0 + + + 0.0 + 0.0 + 0.0 + 0 + + + 0.0 + 0.0 + 0.0 + 0 + + + 0.0 + 0.0 + 1 + 0.0 + + + 0.0 + 0.0 + 0 + 0.0 + + + + 0 + + 0.05 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + 1 + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0.15 + 0.075 + 0.15 + 0.0 + 0.5 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + 0.0 + + + + + + + + + cells.csv + + - 0 - - - - - 15 - + 0 + 50 + 400 + 40 + 20 + 50 + 50 + 50 + 0.0075 + diff --git a/config/cells.csv b/config/cells.csv new file mode 100644 index 000000000..da8c78e7a --- /dev/null +++ b/config/cells.csv @@ -0,0 +1,11 @@ +0,0,0,0 +12,3,0,0 +24,5,0,0 +36,6,0,0 +48,5,0,0 +60,3,0,0 +72,0,0,0 +84,-3,0,0 +96,-5,0,0 +108,-6,0,0 +120,-5,0,0 \ No newline at end of file diff --git a/custom_modules/custom.cpp b/custom_modules/custom.cpp new file mode 100644 index 000000000..a141e9226 --- /dev/null +++ b/custom_modules/custom.cpp @@ -0,0 +1,793 @@ +/* +############################################################################### +# 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 "./custom.h" + +void create_cell_types( void ) +{ + // set the random seed + 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(); + + /* + 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; + + // set up bacteria + + Cell_Definition* pCD = find_cell_definition( "bacteria"); + pCD->functions.update_phenotype = bacteria_phenotype; + // pCD->functions.update_migration_bias = advanced_chemotaxis_function; + // pCD->phenotype.motility.chemotactic_sensitivity( "resource" ) = 1; + // pCD->phenotype.motility.chemotactic_sensitivity( "quorum" ) = 0.1; + + // set up blood vessels + + pCD = find_cell_definition( "blood vessel"); + pCD->is_movable = false; + + // set up stem cells + + pCD = find_cell_definition( "stem"); + pCD->functions.update_phenotype = stem_cell_phenotype; + // pCD->phenotype.cell_transformations.transformation_rate("differentiated") = 0.0001; + + // set up differentiated cells + + pCD = find_cell_definition( "differentiated"); + pCD->functions.update_phenotype = differentiated_cell_phenotype; + + // set up macrophages + + pCD = find_cell_definition( "macrophage"); + // pCD->phenotype.cell_interactions.dead_phagocytosis_rate = 0.05; + pCD->functions.update_phenotype = macrophage_phenotype; + // pCD->functions.update_migration_bias = advanced_chemotaxis_function; + // pCD->phenotype.motility.chemotactic_sensitivity( "debris" ) = 0.1; + // pCD->phenotype.motility.chemotactic_sensitivity( "quorum" ) = 1; + + + // set up CD8+ T cells + pCD = find_cell_definition( "CD8+ T cell"); + pCD->functions.update_phenotype = CD8Tcell_phenotype; + // pCD->phenotype.cell_interactions.attack_rate("bacteria") = 0.05; + + // set up neutrophil + pCD = find_cell_definition( "neutrophil"); + pCD->functions.update_phenotype = neutrophil_phenotype; + // pCD->phenotype.cell_interactions.live_phagocytosis_rate("bacteria") = 0.05; + + /* + This builds the map of cell definitions and summarizes the setup. + */ + + build_cell_definitions_maps(); + 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]; + int num_cells = parameters.ints("number_of_cells"); + if( num_cells > 0 ) + { 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 ); + } + } + + // parameter-based placement + // bacteria + Cell_Definition* pCD = find_cell_definition("bacteria"); + std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; + for( int n = 0 ; n < parameters.ints("number_of_bacteria") ; 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 ); + } + + // blood vessels + pCD = find_cell_definition("blood vessel"); + std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; + for( int n = 0 ; n < parameters.ints("number_of_blood_vessels") ; 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 ); + } + + // stem cells + pCD = find_cell_definition("stem"); + std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; + for( int n = 0 ; n < parameters.ints("number_of_stem_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 ); + } + + // differentiated cells + pCD = find_cell_definition("differentiated"); + std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; + for( int n = 0 ; n < parameters.ints("number_of_differentiated_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 ); + } + + // macrophages + pCD = find_cell_definition("macrophage"); + std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; + for( int n = 0 ; n < parameters.ints("number_of_macrophages") ; 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 ); + } + + // neutrophils + pCD = find_cell_definition("neutrophil"); + std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; + for( int n = 0 ; n < parameters.ints("number_of_neutrophils") ; 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 ); + } + + // CD8+ T cells + pCD = find_cell_definition("CD8+ T cell"); + std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; + for( int n = 0 ; n < parameters.ints("number_of_CD8T_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 ); + } + + // load cells from your CSV file (if enabled) + load_cells_from_pugixml(); + + 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; } + +void bacteria_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) +{ + // find my cell definition + static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); + + // sample resource, quorum, and toxin + + static int nR = microenvironment.find_density_index( "resource" ); + static int nDebris = microenvironment.find_density_index( "debris" ); + static int nQuorum = microenvironment.find_density_index( "quorum" ); + static int nToxin = microenvironment.find_density_index( "toxin" ); + + // if dead: stop exporting quorum factor. + // also, replace phenotype function + if( phenotype.death.dead == true ) + { + phenotype.secretion.net_export_rates[nQuorum] = 0; + phenotype.secretion.net_export_rates[nToxin] = 0; + + phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; + + pCell->functions.update_phenotype = NULL; + return; + } + + std::vector samples = pCell->nearest_density_vector(); + double R = samples[nR]; + double Q = samples[nQuorum]; + double Tox = samples[nToxin]; + + // resource increases cycle entry + double base_val = pCD->phenotype.cycle.data.exit_rate(0); + double max_val = base_val * 10.0; + static double min_cycle_resource = pCD->custom_data["cycling_entry_threshold_resource"]; // 0.15 + phenotype.cycle.data.exit_rate(0) = max_val * linear_response_function( R, min_cycle_resource, 1 ); + + // resource decreses necrosis + + max_val = 0.0028; + static int nNecrosis = phenotype.death.find_death_model_index( PhysiCell_constants::necrosis_death_model ); + static double saturation_necrosis_resource = pCD->custom_data["necrosis_saturation_resource"]; //0.075 + static double threshold_necrosis_resource = pCD->custom_data["necrosis_threshold_resource"]; // 0.15 + phenotype.death.rates[nNecrosis] = max_val * + decreasing_linear_response_function( R, saturation_necrosis_resource, threshold_necrosis_resource ); + + // resource decreases motile speed + + double signal = R; + base_val = pCD->phenotype.motility.migration_speed; + double max_response = 0.0; + static double motility_resource_halfmax = + pCD->custom_data["migration_speed_halfmax"]; // 0.25 // parameters.doubles("bacteria_motility_resource_halfmax"); + double hill = Hill_response_function( signal, motility_resource_halfmax , 1.5); + phenotype.motility.migration_speed = base_val + (max_response-base_val)*hill; + + // quorum and resource increases motility bias + signal = Q+R; + base_val = pCD->phenotype.motility.migration_speed; + max_response = 1.0; + static double bias_halfmax = pCD->custom_data["migration_bias_halfmax"]; + // 0.5 // parameters.doubles("bacteria_migration_bias_halfmax"); + hill = Hill_response_function( signal, bias_halfmax , 1.5); + phenotype.motility.migration_bias = base_val + (max_response-base_val)*hill; + + // damage increases death + static int nApoptosis = phenotype.death.find_death_model_index( PhysiCell_constants::apoptosis_death_model ); + + signal = pCell->state.damage; + base_val = pCD->phenotype.death.rates[nApoptosis]; + + static double damage_halfmax = pCD->custom_data["damage_halfmax"]; + static double relative_max_damage_death = pCD->custom_data["relative_max_damage_death"]; + max_response = base_val * relative_max_damage_death; + + // 36 // parameters.doubles("bacteria_damage_halfmax"); + hill = Hill_response_function( signal , damage_halfmax , 1.5 ); + phenotype.death.rates[nApoptosis] = base_val + (max_response-base_val)*hill; + + return; +} + +/* https://www.karger.com/Article/Fulltext/494069 */ + +void macrophage_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) +{ + // find my cell definition + static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); + + // sample environment + + static int nPIF = microenvironment.find_density_index( "pro-inflammatory" ); + static int nDebris = microenvironment.find_density_index( "debris"); + static int nQ = microenvironment.find_density_index("quorum"); + + // if dead, release debris + if( phenotype.death.dead == true ) + { + phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; + pCell->functions.update_phenotype = NULL; + return; + } + + std::vector samples = pCell->nearest_density_vector(); + double PIF = samples[nPIF]; + double debris = samples[nDebris]; + double Q = samples[nQ]; + + // sample contacts + + static int bacteria_type = find_cell_definition( "bacteria")->type; + + int num_bacteria = 0; + int num_dead = 0; + for( int n=0; n < pCell->state.neighbors.size(); n++ ) + { + Cell* pC = pCell->state.neighbors[n]; + if( pC->phenotype.death.dead == true ) + { num_dead++; } + else + { + if( pC->type == bacteria_type ) + { num_bacteria++; } + } + } + + // contact with dead cells or bacteria, or debris + // increases secretion of pro-inflammatory + + static double secretion_dead_sensitivity = 1; + static double secretion_bacteria_sensitivity = 1; + static double secretion_debris_sensitivity = 2; + static double secretion_quorum_sensitivity = 5; + + double base_val = pCD->phenotype.secretion.secretion_rates[nPIF]; + double max_response = 10; // phenotype.volume.total; + double signal = + secretion_dead_sensitivity*num_dead + + secretion_bacteria_sensitivity*num_bacteria + + secretion_debris_sensitivity*debris + + secretion_quorum_sensitivity*Q; + double half_max = pCD->custom_data["secretion_halfmax"]; // 0.5; // 0.5; + double hill = Hill_response_function( signal , half_max , 1.5 ); + + + phenotype.secretion.secretion_rates[nPIF] = base_val + (max_response-base_val)*hill; + +/* + #pragma omp critical + { + std::cout << "secretion index: " << nPIF << " base: " << base_val << " max: " << max_response << " actual: " << phenotype.secretion.secretion_rates[nPIF] << std::endl; + std::cout << "\tsignal: " << signal << " vs halfmax: " << half_max << std::endl; + std::cout << "\t\tdead: " << num_dead << " bac: " << num_bacteria << " debris: " << debris << " Q: " << Q << std::endl; + std::cout << "\t\t\tsaturation: " << phenotype.secretion.saturation_densities[nPIF]<< std::endl; + } +*/ + + // chemotaxis bias increases with debris or quorum factor + + static double bias_debris_sensitivity = 0.1; + static double bias_quorum_sensitivity = 1; + + base_val = pCD->phenotype.motility.migration_bias; + max_response = 0.75; + signal = bias_debris_sensitivity*debris + + bias_quorum_sensitivity*Q ; // + 10 * PIF; + half_max = pCD->custom_data["migration_bias_halfmax"]; // 0.01 // 0.005 //0.1 // 0.05 + hill = Hill_response_function( signal , half_max , 1.5 ); + phenotype.motility.migration_bias = base_val + (max_response-base_val)*hill; + +/* + #pragma omp critical + { + std::cout << "signal: " << signal << " halfmax: " << half_max + << " hill: " << hill << std::endl; + + std::cout << "\tbase: " << base_val + << " max: " << max_response + << " actual: " << phenotype.motility.migration_bias << std::endl; + } +*/ + + // migration speed slows down in the presence of debris or quorum factor + + base_val = pCD->phenotype.motility.migration_speed; + max_response = 0.1 * base_val; + signal = bias_debris_sensitivity*debris + + bias_quorum_sensitivity*Q ; // + 10 * PIF; + half_max = pCD->custom_data["migration_speed_halfmax"]; // 0.1 // 0.05 + hill = Hill_response_function( signal , half_max , 1.5 ); + phenotype.motility.migration_speed = base_val + (max_response-base_val)*hill; + + return; +} + +void CD8Tcell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) +{ + // find my cell definition + static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); + + // sample environment + + static int nR = microenvironment.find_density_index( "resource"); + static int nTox = microenvironment.find_density_index( "toxin"); + static int nDebris = microenvironment.find_density_index( "debris" ); + static int nPIF = microenvironment.find_density_index( "pro-inflammatory"); + + std::vector samples = pCell->nearest_density_vector(); + double PIF = samples[nPIF]; + + // if dead, release debris + if( phenotype.death.dead == true ) + { + phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; + pCell->functions.update_phenotype = NULL; + return; + } + + // migration bias increases with pro-inflammatory + + double signal = PIF; + double base_val = pCD->phenotype.motility.migration_bias; + double max_val = 0.75; + double half_max = pCD->custom_data["migration_bias_halfmax"]; // 0.05 // 0.25 + double hill = Hill_response_function( PIF , half_max , 1.5 ); + + phenotype.motility.migration_bias = base_val + (max_val-base_val)*hill; + +/* + #pragma omp critical + { + std::cout << "signal: " << signal << " halfmax: " << half_max + << " hill: " << hill << std::endl; + + std::cout << "\tbase: " << base_val + << " max: " << max_val + << " actual: " << phenotype.motility.migration_bias << std::endl; + } +*/ + + return; +} + +void neutrophil_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) +{ + // find my cell definition + static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); + + // sample environment + + static int nR = microenvironment.find_density_index( "resource"); + static int nTox = microenvironment.find_density_index( "toxin"); + static int nDebris = microenvironment.find_density_index( "debris" ); + static int nPIF = microenvironment.find_density_index( "pro-inflammatory"); + + std::vector samples = pCell->nearest_density_vector(); + double PIF = samples[nPIF]; + + // if dead, release debris + if( phenotype.death.dead == true ) + { + phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; + pCell->functions.update_phenotype = NULL; + return; + } + + // migration bias increases with pro-inflammatory + + double signal = PIF; + double base_val = pCD->phenotype.motility.migration_bias; + double max_val = 0.75; + double half_max = pCD->custom_data["migration_bias_halfmax"]; // 0.25 + double hill = Hill_response_function( PIF , half_max , 1.5 ); + + phenotype.motility.migration_bias = base_val + (max_val-base_val)*hill; + + return; +} + +void stem_cell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) +{ + // find my cell definition + static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); + + // sample environment + + static int nR = microenvironment.find_density_index( "resource"); + static int nTox = microenvironment.find_density_index( "toxin"); + static int nDebris = microenvironment.find_density_index( "debris" ); + + // if dead, release debris + if( phenotype.death.dead == true ) + { + phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; + pCell->functions.update_phenotype = NULL; + return; + } + + std::vector samples = pCell->nearest_density_vector(); + double R = samples[nR]; + double toxin = samples[nTox]; + + // sample contacts + + static int stem_type = find_cell_definition( "stem")->type; + static int diff_type = find_cell_definition( "differentiated")->type; + static int bacteria_type = find_cell_definition( "bacteria")->type; + + int num_stem = 0; + int num_differentiated = 0; + int num_bacteria = 0; + int num_dead = 0; + for( int n=0; n < pCell->state.neighbors.size(); n++ ) + { + Cell* pC = pCell->state.neighbors[n]; + if( pC->phenotype.death.dead == true ) + { num_dead++; } + else + { + if( pC->type == stem_type ) + { num_stem++; } + if( pC->type == num_differentiated ) + { num_differentiated++; } + if( pC->type == bacteria_type ) + { num_bacteria++; } + } + } + + // contact with a stem cell increases differentiation + static double max_stem_diff = parameters.doubles("max_stem_differentiation"); // 0.0075 + static double stem_diff_halfmax = pCD->custom_data["differentiation_contact_halfmax"]; // 0.1 + + double base_val = 0; // phenotype.cell_transformations.transformation_rates[diff_type]; + double max_val = max_stem_diff; // 0.0075; + double signal = num_stem; + double half_max = stem_diff_halfmax; // 0.1; + double hill = Hill_response_function( signal, half_max , 1.5 ); + phenotype.cell_transformations.transformation_rates[diff_type] = base_val + (max_val-base_val)*hill; + + // contact with a differentiated cell reduces proliferation + // high rate of proliferation unless in contact with a differentiated cell + + static double stem_cycling_halfmax = pCD->custom_data["cycling_contact_halfmax"]; // 0.1; + + base_val = pCD->phenotype.cycle.data.exit_rate(0); // 0.002; + max_val = 0.0; + signal = num_differentiated; + half_max = stem_cycling_halfmax; // 0.1; + hill = Hill_response_function( signal, half_max , 1.5 ); + phenotype.cycle.data.exit_rate(0) = base_val + (max_val-base_val)*hill; + + // resource reduces necrotic death + + max_val = 0.0028; + static int nNecrosis = phenotype.death.find_death_model_index( PhysiCell_constants::necrosis_death_model ); + static double stem_saturation_necrosis = pCD->custom_data["necrosis_saturation_resource"]; + static double stem_threshold_necrosis = pCD->custom_data["necrosis_threshold_resource"]; + + phenotype.death.rates[nNecrosis] = max_val * + decreasing_linear_response_function( R, stem_saturation_necrosis, stem_threshold_necrosis ); + + // toxin increases apoptotic death + + static int nApoptosis = phenotype.death.find_death_model_index( PhysiCell_constants::apoptosis_death_model ); + + static double toxicity_halfmax = pCD->custom_data["toxicity_halfmax"]; // 0.4 + static double relative_max_toxicity = pCD->custom_data["relative_max_toxicity"]; + + signal = toxin; + base_val = pCD->phenotype.death.rates[nApoptosis]; + max_val = base_val * relative_max_toxicity; // 100*base_val; + + hill = Hill_response_function( signal , toxicity_halfmax , 1.5 ); + phenotype.death.rates[nApoptosis] = base_val + (max_val-base_val)*hill; + + return; +} + +void differentiated_cell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) +{ + // find my cell definition + static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); + + // sample environment + + static int nR = microenvironment.find_density_index( "resource"); + static int nTox = microenvironment.find_density_index( "toxin"); + static int nDebris = microenvironment.find_density_index( "debris" ); + + // if dead, release debris + if( phenotype.death.dead == true ) + { + phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; + pCell->functions.update_phenotype = NULL; + return; + } + + std::vector samples = pCell->nearest_density_vector(); + double R = samples[nR]; + double toxin = samples[nTox]; + + + double signal = 0.0; + double hill = 0.0; + + // pressure reduces proliferation + signal = pCell->state.simple_pressure; + static double pressure_halfmax = pCD->custom_data["cycling_pressure_halfmax"]; // 0.5 + hill = Hill_response_function( signal, pressure_halfmax , 1.5 ); + double base_val = pCD->phenotype.cycle.data.exit_rate(0); + + phenotype.cycle.data.exit_rate(0) = (1-hill)*base_val; + + // resource reduces necrotic death + + double max_val = 0.0028; + static int nNecrosis = phenotype.death.find_death_model_index( PhysiCell_constants::necrosis_death_model ); + + // get same from bacteria + static double necrosis_saturation = pCD->custom_data["necrosis_saturation_resource"]; // 0.075 + static double necrosis_threshold = pCD->custom_data["necrosis_threshold_resource"]; // 0.15 + + phenotype.death.rates[nNecrosis] = max_val * + decreasing_linear_response_function( R, necrosis_saturation, necrosis_threshold ); + + // toxin increases apoptotic death + + static int nApoptosis = phenotype.death.find_death_model_index( PhysiCell_constants::apoptosis_death_model ); + + static double toxicity_halfmax = pCD->custom_data["toxicity_halfmax"]; // 0.2 + static double relative_max_tox_death = pCD->custom_data["relative_max_toxicity"]; // 100 + + signal = toxin; + base_val = pCD->phenotype.death.rates[nApoptosis]; + double max_response = base_val * relative_max_tox_death; + hill = Hill_response_function( signal , toxicity_halfmax , 1.5 ); + // std::cout << "tox: " << signal << " " << hill << std::endl; + phenotype.death.rates[nApoptosis] = base_val + (max_response-base_val)*hill; + + return; +} diff --git a/custom_modules/custom.h b/custom_modules/custom.h new file mode 100644 index 000000000..7b6616bc3 --- /dev/null +++ b/custom_modules/custom.h @@ -0,0 +1,101 @@ +/* +############################################################################### +# 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 "../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 ); + +void bacteria_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); // final + +void macrophage_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); // final +void CD8Tcell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); +void neutrophil_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); + +void stem_cell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); // final +void differentiated_cell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); // final + diff --git a/main-backup.cpp b/main-backup.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/main.cpp b/main.cpp new file mode 100644 index 000000000..5b61d6861 --- /dev/null +++ b/main.cpp @@ -0,0 +1,257 @@ +/* +############################################################################### +# 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_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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; + + 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"<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 ); + + // timer + + std::cout << std::endl << "Total simulation runtime: " << std::endl; + BioFVM::display_stopwatch_value( std::cout , BioFVM::runtime_stopwatch_value() ); + + return 0; +} diff --git a/modules/PhysiCell_MultiCellDS.cpp b/modules/PhysiCell_MultiCellDS.cpp index 1004fcbe1..95628c34c 100644 --- a/modules/PhysiCell_MultiCellDS.cpp +++ b/modules/PhysiCell_MultiCellDS.cpp @@ -780,6 +780,7 @@ void save_PhysiCell_to_MultiCellDS_xml_pugi( std::string filename_base , Microen // now, add the PhysiCell data add_PhysiCell_cells_to_open_xml_pugi( BioFVM::biofvm_doc , filename_base , M ); + // add_PhysiCell_cells_to_open_xml_pugi_v2( BioFVM::biofvm_doc , filename_base , M ); // Lastly, save to the indicated filename @@ -790,6 +791,1156 @@ void save_PhysiCell_to_MultiCellDS_xml_pugi( std::string filename_base , Microen return; } + +void save_PhysiCell_to_MultiCellDS_v2( std::string filename_base , Microenvironment& M , double current_simulation_time) +{ + // set some metadata + + BioFVM::MultiCellDS_version_string = "2"; + BioFVM::BioFVM_metadata.program.program_name = "PhysiCell"; + BioFVM::BioFVM_metadata.program.program_version = PhysiCell_Version; + BioFVM::BioFVM_metadata.program.program_URL = "http://physicell.org"; + + BioFVM::BioFVM_metadata.program.creator.type = "creator"; + BioFVM::BioFVM_metadata.program.creator.surname = "Macklin"; + BioFVM::BioFVM_metadata.program.creator.given_names = "Paul"; + BioFVM::BioFVM_metadata.program.creator.email = "macklinp@iu.edu"; + BioFVM::BioFVM_metadata.program.creator.URL = "http://MathCancer.org"; + BioFVM::BioFVM_metadata.program.creator.organization = "Indiana University & PhysiCell Project"; + BioFVM::BioFVM_metadata.program.creator.department = "Intelligent Systems Engineering"; + BioFVM::BioFVM_metadata.program.creator.ORCID = "0000-0002-9925-0151"; + + BioFVM::BioFVM_metadata.program.citation.DOI = "10.1371/journal.pcbi.1005991"; + BioFVM::BioFVM_metadata.program.citation.PMID = "29474446"; + BioFVM::BioFVM_metadata.program.citation.PMCID = "PMC5841829"; + BioFVM::BioFVM_metadata.program.citation.text = "A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin. PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellular Systems, PLoS Comput. Biol. 14(2): e1005991, 2018. DOI: 10.1371/journal.pcbi.1005991"; + BioFVM::BioFVM_metadata.program.citation.notes = ""; + BioFVM::BioFVM_metadata.program.citation.URL = "https://dx.doi.org/PMC5841829"; + + // start with a standard BioFVM save + // overall XML structure + add_MultiCellDS_main_structure_to_open_xml_pugi( BioFVM::biofvm_doc ); + // save metadata + BioFVM_metadata.add_to_open_xml_pugi( current_simulation_time , BioFVM::biofvm_doc ); + // save diffusing substrates + add_BioFVM_substrates_to_open_xml_pugi( BioFVM::biofvm_doc , filename_base, M ); + + // add_BioFVM_agents_to_open_xml_pugi( xml_dom , filename_base, M); + + // now, add the PhysiCell data + + // add_PhysiCell_cells_to_open_xml_pugi( BioFVM::biofvm_doc , filename_base , M ); + add_PhysiCell_cells_to_open_xml_pugi_v2( BioFVM::biofvm_doc , filename_base , M ); + + // Lastly, save to the indicated filename + + char filename[1024]; + sprintf( filename , "%s.xml" , filename_base.c_str() ); + BioFVM::biofvm_doc.save_file( filename ); + + return; +} + +void add_PhysiCell_cells_to_open_xml_pugi_v2( pugi::xml_document& xml_dom, std::string filename_base, Microenvironment& M ) +{ + // get number of substrates + static int m = microenvironment.number_of_densities(); // number_of_substrates + // get number of cell types + static int n = cell_definition_indices_by_name.size(); // number_of_cell_types + // get number of death models + static int nd = (*all_cells)[0]->phenotype.death.rates.size(); // + // get number of custom data + static int nc = 0; // + static int nc_scalar = 0; + static int nc_vector = 0; + + static int cell_data_size = 0; + + + static bool legends_done= false; + static std::vector data_names; + static std::vector data_units; + static std::vector data_start_indices; + static std::vector data_sizes; + + // set up the labels + if( legends_done == false ) + { + data_names.clear(); + data_sizes.clear(); + data_start_indices.clear(); + data_units.clear(); + + std::string name; + std::string units; + int size; + int index = 0; + + +// compatibilty : first 17 entries + // ID + name = "ID"; + size = 1; + units="none"; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "position"; + size = 3; + units="microns"; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "total_volume"; + units = "cubic microns"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "cell_type"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "cycle_model"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "current_phase"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "elapsed_time_in_phase"; + units = "min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "nuclear_volume"; + units = "cubic microns"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "cytoplasmic_volume"; + units = "cubic microns"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "fluid_fraction"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "calcified_fraction"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "orientation"; + units = "none"; + size = 3; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // + name = "polarity"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + +/* state variables to save */ +// state + // velocity // 3 + name = "velocity"; + units = "micron/min"; + size = 3; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // pressure // 1 + name = "pressure"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // number of nuclei // 1 + name = "number_of_nuclei"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // damage // 1 + name = "damage"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // total attack time // 1 + name = "total_attack_time"; + units = "min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // contact_with_basement_membrane // 1 + name = "contact_with_basement_membrane"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + + +/* now go through phenotype and state */ +// cycle + // cycle model // already above + // current phase // already above + // current exit rate // 1 + name = "current_cycle_phase_exit_rate"; + units = "1/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // elapsed time in phase // 1 + name = "elapsed_time_in_phase"; + units = "min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + +// death + // live or dead state // 1 + name = "dead"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // current death model // 1 + name = "current_death_model"; // + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // death rates // nd + name = "death_rates"; + units = "1/min"; + size = nd; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; +// + +// volume () + // cytoplasmic_biomass_change_rate // 1 + name = "cytoplasmic_biomass_change_rate"; + units = "1/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // nuclear_biomass_change_rate; // 1 + name = "nuclear_biomass_change_rate"; + units = "1/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // fluid_change_rate; // 1 + name = "fluid_change_rate"; + units = "1/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // calcification_rate; // 1 + name = "calcification_rate"; + units = "1/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // target_solid_cytoplasmic; // 1 + name = "target_solid_cytoplasmic"; + units = "cubic microns"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // target_solid_nuclear; // 1 + name = "target_solid_nuclear"; + units = "cubic microns"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // target_fluid_fraction; // 1 + name = "target_fluid_fraction"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + + // geometry + // radius //1 + name = "radius"; + units = "microns"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // nuclear_radius // 1 + name = "nuclear_radius"; + units = "microns"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // surface_area //1 + name = "surface_area"; + units = "square microns"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // polarity // arleady done + + // mechanics + // cell_cell_adhesion_strength; // 1 + name = "cell_cell_adhesion_strength"; + units = "micron/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // cell_BM_adhesion_strength; // 1 + name = "cell_BM_adhesion_strength"; + units = "micron/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // cell_cell_repulsion_strength; // 1 + name = "cell_cell_repulsion_strength"; + units = "micron/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // cell_BM_repulsion_strength; // 1 + name = "cell_BM_repulsion_strength"; + units = "micron/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // std::vector cell_adhesion_affinities; // n + name = "cell_adhesion_affinities"; + units = "none"; + size = n; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // relative_maximum_adhesion_distance; // 1 + name = "relative_maximum_adhesion_distance"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // maximum_number_of_attachments; // 1 + name = "maximum_number_of_attachments"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // attachment_elastic_constant; // 1 + name = "attachment_elastic_constant"; + units = "1/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // attachment_rate; // 1 + name = "attachment_rate"; + units = "1/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // detachment_rate; // 1 + name = "detachment_rate"; + units = "1/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // Motility + // is_motile // 1 + name = "is_motile"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // persistence_time; // 1 + name = "persistence_time"; + units = "min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // migration_speed; // 1 + name = "migration_speed"; + units = "micron/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // std::vector migration_bias_direction; // 3 // motility_bias_direction originally + name = "migration_bias_direction"; + units = "none"; + size = 3; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // migration_bias; //1 + name = "migration_bias"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // std::vector motility_vector; // 3 + name = "motility_vector"; + units = "micron/min"; + size = 3; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // chemotaxis_index; // 1 + name = "chemotaxis_index"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // chemotaxis_direction; // 1 + name = "chemotaxis_direction"; + units = "none"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // advanced chemotaxis + // std::vector chemotactic_sensitivities; // m + name = "chemotactic_sensitivities"; + units = "none"; + size = m; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + +// secretion + // std::vector secretion_rates; // m + name = "secretion_rates"; + units = "1/min"; + size = m; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // std::vector uptake_rates; // m + name = "uptake_rates"; + units = "1/min"; + size = m; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // std::vector saturation_densities; // m + name = "saturation_densities"; + units = "stuff/cubic micron"; + size = m; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // std::vector net_export_rates; // m + name = "net_export_rates"; + units = "stuff/min"; + size = m; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + +// molecular + // internalized_total_substrates // m + name = "internalized_total_substrates"; + units = "stuff"; + size = m; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // fraction_released_at_death // m + name = "fraction_released_at_death"; + units = "none"; + size = m; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // fraction_transferred_when_ingested //m + name = "fraction_transferred_when_ingested"; + units = "none"; + size = m; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; +// interactions + // dead_phagocytosis_rate; // 1 + name = "dead_phagocytosis_rate"; + units = "1/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // std::vector live_phagocytosis_rates; // n + name = "live_phagocytosis_rates"; + units = "1/min"; + size = n; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // std::vector attack_rates; // n + name = "attack_rates"; + units = "1/min"; + size = n; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // double damage_rate; 1 + name = "damage_rate"; + units = "1/min"; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + // std::vector fusion_rates; // n + name = "fusion_rates"; + units = "1/min"; + size = n; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; +// transformations + // std::vector transformation_rates; // n + name = "transformation_rates"; + units = "1/min"; + size = n; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + +// custom + for( int j=0 ; j < (*all_cells)[0]->custom_data.variables.size(); j++ ) + { + name = (*all_cells)[0]->custom_data.variables[j].name; + units = (*all_cells)[0]->custom_data.variables[j].units; + size = 1; + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + } + + // custom vector variables + for( int j=0 ; j < (*all_cells)[0]->custom_data.vector_variables.size(); j++ ) + { + name = (*all_cells)[0]->custom_data.vector_variables[j].name; + units = (*all_cells)[0]->custom_data.vector_variables[j].units; + size = (*all_cells)[0]->custom_data.vector_variables[j].value.size(); + data_names.push_back( name ); + data_units.push_back(units); + data_sizes.push_back( size ); + data_start_indices.push_back( index ); + cell_data_size += size; + index += size; + } + + legends_done = true; + } + + // get ready for XML navigation + // pugi::xml_document& xml_dom = BioFVM::biofvm_doc; + + pugi::xml_node root = xml_dom.child("MultiCellDS") ; + pugi::xml_node node = root.child( "cellular_information" ); // root = cellular_information + root = node; + + // Let's reduce memory allocations and sprintf calls. + // This reduces execution time. + static char* temp; + static bool initialized = false; + + static char rate_chars [1024]; + static char volume_chars [1024]; + static char diffusion_chars [1024]; + if( !initialized ) + { + temp = new char [1024]; + initialized = true; + + sprintf( rate_chars, "1/%s" , M.time_units.c_str() ); + sprintf( volume_chars, "%s^3" , M.spatial_units.c_str() ); + sprintf( diffusion_chars , "%s^2/%s", M.spatial_units.c_str() , M.time_units.c_str() ); + } + + node = node.child( "cell_populations" ); + if( !node ) + { + node = root.append_child( "cell_populations" ); + } + root = node; // root = cellular_information.cell_populations + + node = root.child( "cell_population" ); + if( !node ) + { + node = root.append_child( "cell_population" ); + pugi::xml_attribute attrib = node.append_attribute( "type" ); + attrib.set_value( "individual" ); + } + root = node; // root = cellular_information.cell_populations.cell_population + + node = root.child( "custom" ); + if( !node ) + { + node = root.append_child( "custom" ); + } + root = node; // root = cellular_information.cell_populations.cell_population.custom + + node = root.child( "simplified_data" ); + if( !node ) + { + node = root.append_child( "simplified_data" ); + pugi::xml_attribute attrib = node.append_attribute( "type" ); + attrib.set_value( "matlab" ); + + attrib = node.append_attribute( "source" ); + attrib.set_value( "PhysiCell" ); + + attrib = node.append_attribute( "data_version" ); + attrib.set_value( "2" ); + } + root = node; // root = cellular_information.cell_populations.cell_population.custom.simplified_data + + // write legend + + node = root.child( "labels" ); + if( !node ) + { + node = root.append_child( "labels" ); + root = node; // root = cellular_information.cell_populations.cell_population.custom.simplified_data.labels + + for( int i=0; i < data_names.size(); i++ ) + { + node = root.append_child( "label" ); + pugi::xml_attribute attrib = node.append_attribute( "index" ); + attrib.set_value( data_start_indices[i] ); + + attrib = node.append_attribute( "size" ); + attrib.set_value( data_sizes[i] ); + + attrib = node.append_attribute( "units" ); + attrib.set_value( data_units[i].c_str() ); + + node.append_child( pugi::node_pcdata ).set_value( data_names[i].c_str() ); + } + root = root.parent(); // root = cellular_information.cell_populations.cell_population.custom.simplified_data + } + + // write data + node = root.child( "filename" ); + if( !node ) + { + node = root.append_child( "filename" ); + } + + // write the filename + + // next, filename + char filename [1024]; + sprintf( filename , "%s_cells.mat" , filename_base.c_str() ); + + /* store filename without the relative pathing (if any) */ + char filename_without_pathing [1024]; + char* filename_start = strrchr( filename , '/' ); + if( filename_start == NULL ) + { filename_start = filename; } + else + { filename_start++; } + strcpy( filename_without_pathing , filename_start ); + + if( !node.first_child() ) + { + node.append_child( pugi::node_pcdata ).set_value( filename_without_pathing ); // filename ); + } + else + { + node.first_child().set_value( filename_without_pathing ); // filename ); + } + + // now write the actual data + + int size_of_each_datum = cell_data_size; + int number_of_data_entries = (*all_cells).size(); + + FILE* fp = write_matlab_header( size_of_each_datum, number_of_data_entries, filename, "cells" ); + if( fp == NULL ) + { + std::cout << std::endl << "Error: Failed to open " << filename << " for MAT writing." << std::endl << std::endl; + + std::cout << std::endl << "Error: We're not writing data like we expect. " << std::endl + << "Check to make sure your save directory exists. " << std::endl << std::endl + << "I'm going to exit with a crash code of -1 now until " << std::endl + << "you fix your directory. Sorry!" << std::endl << std::endl; + exit(-1); + } + + + Cell* pCell; + + double dTemp; + // storing data as cols (each column is a cell) + for( int i=0; i < number_of_data_entries ; i++ ) + { + pCell = (*all_cells)[i]; + + int writes = 0; + + // compatibilty : first 17 entries + // ID + // double ID_temp = (double) (*all_cells)[i]->ID; + // fwrite( (char*) &( ID_temp ) , sizeof(double) , 1 , fp ); + + // name = "ID"; + dTemp = (double) pCell->ID; + fwrite( (char*) &(dTemp) , sizeof(double) , 1 , fp ); + // name = "position"; + fwrite( (char*) &( pCell->position ) , sizeof(double) , 3 , fp ); + // name = "total_volume"; + fwrite( (char*) &( pCell->phenotype.volume.total ) , sizeof(double) , 1 , fp ); + // name = "cell_type"; + dTemp = (double) pCell->type; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); + // name = "cycle_model"; + dTemp = (double) pCell->phenotype.cycle.model().code; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); // cycle model + // name = "current_phase"; + dTemp = (double) pCell->phenotype.cycle.current_phase().code; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); // cycle model + // name = "elapsed_time_in_phase"; + fwrite( (char*) &( pCell->phenotype.cycle.data.elapsed_time_in_phase ) , sizeof(double) , 1 , fp ); + // name = "nuclear_volume"; + fwrite( (char*) &( pCell->phenotype.volume.nuclear ) , sizeof(double) , 1 , fp ); + // name = "cytoplasmic_volume"; + fwrite( (char*) &( pCell->phenotype.volume.cytoplasmic ) , sizeof(double) , 1 , fp ); + // name = "fluid_fraction"; + fwrite( (char*) &( pCell->phenotype.volume.fluid_fraction ) , sizeof(double) , 1 , fp ); + // name = "calcified_fraction"; + fwrite( (char*) &( pCell->phenotype.volume.calcified_fraction ) , sizeof(double) , 1 , fp ); + // name = "orientation"; + fwrite( (char*) &( pCell->state.orientation ) , sizeof(double) , 3 , fp ); + // name = "polarity"; + fwrite( (char*) &( pCell->phenotype.geometry.polarity ) , sizeof(double) , 1 , fp ); + + /* state variables to save */ +// state + // name = "velocity"; + fwrite( (char*) &( pCell->velocity ) , sizeof(double) , 3 , fp ); + // name = "pressure"; + fwrite( (char*) &( pCell->state.simple_pressure ) , sizeof(double) , 1 , fp ); + // name = "number_of_nuclei"; + dTemp = (double) pCell->state.number_of_nuclei; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); + // name = "damage"; + fwrite( (char*) &( pCell->state.damage ) , sizeof(double) , 1 , fp ); + // name = "total_attack_time"; + fwrite( (char*) &( pCell->state.total_attack_time ) , sizeof(double) , 1 , fp ); + // name = "contact_with_basement_membrane"; + dTemp = (double) pCell->state.contact_with_basement_membrane; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); + +/* now go through phenotype and state */ +// cycle + // current exit rate // 1 + // name = "current_cycle_phase_exit_rate"; + int phase_index = pCell->phenotype.cycle.data.current_phase_index; + fwrite( (char*) &( pCell->phenotype.cycle.data.exit_rate(phase_index) ) , sizeof(double) , 1 , fp ); + // name = "elapsed_time_in_phase"; + fwrite( (char*) &( pCell->phenotype.cycle.data.elapsed_time_in_phase ) , sizeof(double) , 1 , fp ); + +// death + // live or dead state // 1 + // name = "dead"; + dTemp = (double) pCell->phenotype.death.dead; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); + // name = "current_death_model"; // + dTemp = (double) pCell->phenotype.death.current_death_model_index; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); + // name = "death_rates"; + fwrite( (char*) &( pCell->phenotype.death.rates ) , sizeof(double) , nd , fp ); + + // volume () + // name = "cytoplasmic_biomass_change_rate"; + fwrite( (char*) &( pCell->phenotype.volume.cytoplasmic_biomass_change_rate ) , sizeof(double) , 1 , fp ); + // name = "nuclear_biomass_change_rate"; + fwrite( (char*) &( pCell->phenotype.volume.nuclear_biomass_change_rate ) , sizeof(double) , 1 , fp ); + // name = "fluid_change_rate"; + fwrite( (char*) &( pCell->phenotype.volume.fluid_change_rate ) , sizeof(double) , 1 , fp ); + // name = "calcification_rate"; + fwrite( (char*) &( pCell->phenotype.volume.calcification_rate ) , sizeof(double) , 1 , fp ); + // name = "target_solid_cytoplasmic"; + fwrite( (char*) &( pCell->phenotype.volume.target_solid_cytoplasmic ) , sizeof(double) , 1 , fp ); + // name = "target_solid_nuclear"; + fwrite( (char*) &( pCell->phenotype.volume.target_solid_nuclear ) , sizeof(double) , 1 , fp ); + // name = "target_fluid_fraction"; + fwrite( (char*) &( pCell->phenotype.volume.target_fluid_fraction ) , sizeof(double) , 1 , fp ); + + // geometry + // radius //1 + // name = "radius"; + fwrite( (char*) &( pCell->phenotype.geometry.radius ) , sizeof(double) , 1 , fp ); + // name = "nuclear_radius"; + fwrite( (char*) &( pCell->phenotype.geometry.nuclear_radius ) , sizeof(double) , 1 , fp ); + // name = "surface_area"; + fwrite( (char*) &( pCell->phenotype.geometry.surface_area ) , sizeof(double) , 1 , fp ); + + // mechanics + // cell_cell_adhesion_strength; // 1 + // name = "cell_cell_adhesion_strength"; + fwrite( (char*) &( pCell->phenotype.mechanics.cell_cell_adhesion_strength ) , sizeof(double) , 1 , fp ); + // name = "cell_BM_adhesion_strength"; + fwrite( (char*) &( pCell->phenotype.mechanics.cell_BM_adhesion_strength ) , sizeof(double) , 1 , fp ); + // name = "cell_cell_repulsion_strength"; + fwrite( (char*) &( pCell->phenotype.mechanics.cell_cell_repulsion_strength ) , sizeof(double) , 1 , fp ); + // name = "cell_BM_repulsion_strength"; + fwrite( (char*) &( pCell->phenotype.mechanics.cell_BM_repulsion_strength ) , sizeof(double) , 1 , fp ); + // name = "cell_adhesion_affinities"; + fwrite( (char*) &( pCell->phenotype.mechanics.cell_adhesion_affinities ) , sizeof(double) , n , fp ); + // name = "relative_maximum_adhesion_distance"; + fwrite( (char*) &( pCell->phenotype.mechanics.relative_maximum_adhesion_distance ) , sizeof(double) , 1 , fp ); + // name = "maximum_number_of_attachments"; + dTemp = (double) pCell->phenotype.mechanics.maximum_number_of_attachments; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); + // name = "attachment_elastic_constant"; + fwrite( (char*) &( pCell->phenotype.mechanics.attachment_elastic_constant ) , sizeof(double) , 1 , fp ); + // name = "attachment_rate"; + fwrite( (char*) &( pCell->phenotype.mechanics.attachment_rate ) , sizeof(double) , 1 , fp ); + // name = "detachment_rate"; + fwrite( (char*) &( pCell->phenotype.mechanics.detachment_rate ) , sizeof(double) , 1 , fp ); + + // Motility + // name = "is_motile"; + dTemp = (double) pCell->phenotype.motility.is_motile; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); + // name = "persistence_time"; + fwrite( (char*) &( pCell->phenotype.motility.persistence_time ) , sizeof(double) , 1 , fp ); + // name = "migration_speed"; + fwrite( (char*) &( pCell->phenotype.motility.migration_speed ) , sizeof(double) , 1 , fp ); + // name = "migration_bias_direction"; + fwrite( (char*) &( pCell->phenotype.motility.migration_bias_direction ) , sizeof(double) , 3 , fp ); + // name = "migration_bias"; + fwrite( (char*) &( pCell->phenotype.motility.migration_bias ) , sizeof(double) , 1 , fp ); + // name = "motility_vector"; + fwrite( (char*) &( pCell->phenotype.motility.motility_vector ) , sizeof(double) , 3 , fp ); + // name = "chemotaxis_index"; + dTemp = (double) pCell->phenotype.motility.chemotaxis_index; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); + // name = "chemotaxis_direction"; + dTemp = (double) pCell->phenotype.motility.chemotaxis_direction; + fwrite( (char*) &( dTemp ) , sizeof(double) , 1 , fp ); + // name = "chemotactic_sensitivities"; + fwrite( (char*) &( pCell->phenotype.motility.chemotactic_sensitivities ) , sizeof(double) , m , fp ); + +// secretion + // name = "secretion_rates"; + fwrite( (char*) &( pCell->phenotype.secretion.secretion_rates ) , sizeof(double) , m , fp ); + // name = "uptake_rates"; + fwrite( (char*) &( pCell->phenotype.secretion.uptake_rates ) , sizeof(double) , m , fp ); + // name = "saturation_densities"; + fwrite( (char*) &( pCell->phenotype.secretion.saturation_densities ) , sizeof(double) , m , fp ); + // name = "net_export_rates"; + fwrite( (char*) &( pCell->phenotype.secretion.net_export_rates ) , sizeof(double) , m , fp ); + +// molecular + // name = "internalized_total_substrates"; + fwrite( (char*) &( pCell->phenotype.molecular.internalized_total_substrates ) , sizeof(double) , m , fp ); + // name = "fraction_released_at_death"; + fwrite( (char*) &( pCell->phenotype.molecular.fraction_released_at_death ) , sizeof(double) , m , fp ); + // name = "fraction_transferred_when_ingested"; + fwrite( (char*) &( pCell->phenotype.molecular.fraction_transferred_when_ingested ) , sizeof(double) , m , fp ); + +// interactions + // name = "dead_phagocytosis_rate"; + fwrite( (char*) &( pCell->phenotype.cell_interactions.dead_phagocytosis_rate ) , sizeof(double) , 1 , fp ); + // name = "live_phagocytosis_rates"; + fwrite( (char*) &( pCell->phenotype.cell_interactions.live_phagocytosis_rates ) , sizeof(double) , n , fp ); + // name = "attack_rates"; + fwrite( (char*) &( pCell->phenotype.cell_interactions.attack_rates ) , sizeof(double) , n , fp ); + // name = "damage_rate"; + fwrite( (char*) &( pCell->phenotype.cell_interactions.damage_rate ) , sizeof(double) , 1 , fp ); + // name = "fusion_rates"; + fwrite( (char*) &( pCell->phenotype.cell_interactions.fusion_rates ) , sizeof(double) , n , fp ); + +// transformations + // name = "transformation_rates"; + fwrite( (char*) &( pCell->phenotype.cell_transformations.transformation_rates ) , sizeof(double) , n , fp ); + +// custom + // custom scalar variables + for( int j=0 ; j < (*all_cells)[0]->custom_data.variables.size(); j++ ) + { fwrite( (char*) &( pCell->custom_data.variables[j].value ) , sizeof(double) , 1 , fp ); } + + // custom vector variables + for( int j=0 ; j < (*all_cells)[0]->custom_data.vector_variables.size(); j++ ) + { + int size_temp = pCell->custom_data.vector_variables[j].value.size(); + fwrite( (char*) &( pCell->custom_data.vector_variables[j].value ) , sizeof(double) , size_temp , fp ); + } + } + + fclose( fp ); + + return; +} + }; diff --git a/modules/PhysiCell_MultiCellDS.h b/modules/PhysiCell_MultiCellDS.h index d93a916e8..fe3a3f7d3 100644 --- a/modules/PhysiCell_MultiCellDS.h +++ b/modules/PhysiCell_MultiCellDS.h @@ -87,7 +87,22 @@ void add_PhysiCell_to_open_xml_pugi( pugi::xml_document& xml_dom , std::string f void save_PhysiCell_to_MultiCellDS_xml_pugi( std::string filename_base , Microenvironment& M , double current_simulation_time); + + +/* V2 functions */ + +/* +void add_PhysiCell_cell_to_open_xml_pugi_v2( pugi::xml_document& xml_dom, Cell& C ); // not implemented -- future edition +void add_PhysiCell_cells_to_open_xml_pugi_v2( pugi::xml_document& xml_dom, std::string filename_base, Microenvironment& M ); +void add_PhysiCell_to_open_xml_pugi_v2( pugi::xml_document& xml_dom , std::string filename_base, double current_simulation_time , Microenvironment& M ); +void save_PhysiCell_to_MultiCellDS_xml_pugi_v2( std::string filename_base , Microenvironment& M , double current_simulation_time); +*/ + +void add_PhysiCell_cells_to_open_xml_pugi_v2( pugi::xml_document& xml_dom, std::string filename_base, Microenvironment& M ); +void save_PhysiCell_to_MultiCellDS_v2( std::string filename_base , Microenvironment& M , double current_simulation_time); + + }; #endif \ No newline at end of file diff --git a/pyMCDS2.py b/pyMCDS2.py new file mode 100644 index 000000000..7b386d5a4 --- /dev/null +++ b/pyMCDS2.py @@ -0,0 +1,520 @@ +import xml.etree.ElementTree as ET +import numpy as np +import pandas as pd +import scipy.io as sio +import sys +import warnings +from pathlib import Path + +class pyMCDS2: + """ + This class contains a dictionary of dictionaries that contains all of the + output from a single time step of a PhysiCell Model. This class assumes that + all output files are stored in the same directory. Data is loaded by reading + the .xml file for a particular timestep. + + Parameters + ---------- + xml_name: str + String containing the name of the xml file without the path + output_path: str, optional + String containing the path (relative or absolute) to the directory + where PhysiCell output files are stored (default= ".") + + Attributes + ---------- + data : dict + Hierarchical container for all of the data retrieved by parsing the xml + file and the files referenced therein. + """ + def __init__(self, xml_file, output_path='.'): + self.data = self._read_xml(xml_file, output_path) + + ## METADATA RELATED FUNCTIONS + + def get_time(self): + return self.data['metadata']['current_time'] + + ## MESH RELATED FUNCTIONS + + def get_mesh(self, flat=False): + """ + Return a meshgrid of the computational domain. Can return either full + 3D or a 2D plane for contour plots. + + Parameters + ---------- + flat : bool + If flat is set to true, we return only the x and y meshgrid. + Otherwise we return x, y, and z + + Returns + ------- + splitting : list length=2 if flat=True, else length=3 + Contains arrays of voxel center coordinates as meshgrid with shape + [nx_voxel, ny_voxel, nz_voxel] or [nx_voxel, ny_voxel] if flat=True. + """ + if flat == True: + xx = self.data['mesh']['x_coordinates'][:, :, 0] + yy = self.data['mesh']['y_coordinates'][:, :, 0] + + return [xx, yy] + + # if we dont want a plane just return appropriate values + else: + xx = self.data['mesh']['x_coordinates'] + yy = self.data['mesh']['y_coordinates'] + zz = self.data['mesh']['z_coordinates'] + + return [xx, yy, zz] + + def get_2D_mesh(self): + """ + This function returns the x, y meshgrid as two numpy arrays. It is + identical to get_mesh with the option flat=True + + Returns + ------- + splitting : list length=2 + Contains arrays of voxel center coordinates in x and y dimensions + as meshgrid with shape [nx_voxel, ny_voxel] + """ + xx = self.data['mesh']['x_coordinates'][:, :, 0] + yy = self.data['mesh']['y_coordinates'][:, :, 0] + + return [xx, yy] + + def get_linear_voxels(self): + """ + Helper function to quickly grab voxel centers array stored linearly as + opposed to meshgrid-style. + """ + return self.data['mesh']['voxels']['centers'] + + def get_mesh_spacing(self): + """ + Returns the space in between voxel centers for the mesh in terms of the + mesh's spatial units. Assumes that voxel centers fall on integer values. + + Returns + ------- + dx : float + Distance between voxel centers in the same units as the other + spatial measurements + """ + centers = self.get_linear_voxels() + X = np.unique(centers[0, :]) + Y = np.unique(centers[1, :]) + Z = np.unique(centers[2, :]) + + dx = (X.max() - X.min()) / X.shape[0] + dy = (Y.max() - Y.min()) / Y.shape[0] + dz = (Z.max() - Z.min()) / Z.shape[0] + + if np.abs(dx - dy) > 1e-10 or np.abs(dy - dz) > 1e-10 \ + or np.abs(dx - dz) > 1e-10: + print('Warning: grid spacing may be axis dependent.') + + return round(dx) + + def get_containing_voxel_ijk(self, x, y, z): + """ + Internal function to get the meshgrid indices for the center of a voxel + that contains the given position. + + Note that pyMCDS stores meshgrids as 'cartesian' + (indexing='xy' in np.meshgrid) which means that we will have + to use these indices as [j, i, k] on the actual meshgrid objects + + Parameters + ---------- + x : float + x-coordinate for the position + y : float + y-coordinate for the position + z : float + z-coordinate for the position + + Returns + ------- + ijk : list length=3 + contains the i, j, and k indices for the containing voxel's center + """ + xx, yy, zz = self.get_mesh() + ds = self.get_mesh_spacing() + + if x > xx.max(): + warnings.warn('Position out of bounds: x out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting x = x_max!'.format(x, y, z)) + x = xx.max() + elif x < xx.min(): + warnings.warn('Position out of bounds: x out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting x = x_min!'.format(x, y, z)) + x = xx.min() + elif y > yy.max(): + warnings.warn('Position out of bounds: y out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting y = y_max!'.format(x, y, z)) + y = yy.max() + elif y < yy.min(): + warnings.warn('Position out of bounds: y out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting y = y_min!'.format(x, y, z)) + y = yy.min() + elif z > zz.max(): + warnings.warn('Position out of bounds: z out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting z = z_max!'.format(x, y, z)) + z = zz.max() + elif z < zz.min(): + warnings.warn('Position out of bounds: z out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting z = z_min!'.format(x, y, z)) + z = zz.min() + + i = np.round((x - xx.min()) / ds) + j = np.round((y - yy.min()) / ds) + k = np.round((z - zz.min()) / ds) + + ii, jj, kk = int(i), int(j), int(k) + + return [ii, jj, kk] + + ## MICROENVIRONMENT RELATED FUNCTIONS + + def get_substrate_names(self): + """ + Returns list of chemical species in microenvironment + + Returns + ------- + species_list : array (str), shape=[n_species,] + Contains names of chemical species in microenvironment + """ + species_list = [] + for name in self.data['continuum_variables']: + species_list.append(name) + + return species_list + + def get_concentrations(self, species_name, z_slice=None): + """ + Returns the concentration array for the specified chemical species + in the microenvironment. Can return either the whole 3D picture, or + a 2D plane of concentrations. + + Parameters + ---------- + species_name : str + Name of the chemical species for which to get concentrations + + z_slice : float + z-axis position to use as plane for 2D output. This value must match + a plane of voxel centers in the z-axis. + Returns + ------- + conc_arr : array (np.float) shape=[nx_voxels, ny_voxels, nz_voxels] + Contains the concentration of the specified chemical in each voxel. + The array spatially maps to a meshgrid of the voxel centers. + """ + if z_slice is not None: + # check to see that z_slice is a valid plane + zz = self.data['mesh']['z_coordinates'] + assert z_slice in zz, 'Specified z_slice {} not in z_coordinates'.format(z_slice) + + # do the processing if its ok + mask = zz == z_slice + full_conc = self.data['continuum_variables'][species_name]['data'] + conc_arr = full_conc[mask].reshape((zz.shape[0], zz.shape[1])) + else: + conc_arr = self.data['continuum_variables'][species_name]['data'] + + return conc_arr + + def get_concentrations_at(self, x, y, z): + """ + Return concentrations of each chemical species inside a particular voxel + that contains the point described in the arguments. + + Parameters + ---------- + x : float + x-position for the point of interest + y : float + y_position for the point of interest + z : float + z_position for the point of interest + + Returns + ------- + concs : array, shape=[n_substrates,] + array of concentrations in the order given by get_substrate_names() + """ + i, j, k = self.get_containing_voxel_ijk(x, y, z) + sub_name_list = self.get_substrate_names() + concs = np.zeros(len(sub_name_list)) + + for ix in range(len(sub_name_list)): + concs[ix] = self.get_concentrations(sub_name_list[ix])[j, i, k] + + return concs + + + ## CELL RELATED FUNCTIONS + + def get_cell_df(self): + """ + Builds DataFrame from data['discrete_cells'] + + Returns + ------- + cells_df : pd.Dataframe, shape=[n_cells, n_variables] + Dataframe containing the cell data for all cells at this time step + """ + cells_df = pd.DataFrame(self.data['discrete_cells']) + return cells_df + + def get_cell_variables(self): + """ + Returns the names of all of the cell variables tracked in ['discrete cells'] + dictionary + + Returns + ------- + var_list : list, shape=[n_variables] + Contains the names of the cell variables + """ + var_list = [] + for name in self.data['discrete_cells']: + var_list.append(name) + return var_list + + def get_cell_df_at(self, x, y, z): + """ + Returns a dataframe for cells in the same voxel as the position given by + x, y, and z. + + Parameters + ---------- + x : float + x-position for the point of interest + y : float + y_position for the point of interest + z : float + z_position for the point of interest + + Returns + ------- + vox_df : pd.DataFrame, shape=[n_cell_in_voxel, n_variables] + cell dataframe containing only cells in the same voxel as the point + specified by x, y, and z. + """ + ds = self.get_mesh_spacing() + xx, yy, zz = self.get_mesh() + i, j, k = self.get_containing_voxel_ijk(x, y, z) + x_vox = xx[j, i, k] + y_vox = yy[j, i, k] + z_vox = zz[j, i, k] + + cell_df = self.get_cell_df() + inside_voxel = ( (cell_df['position_x'] < x_vox + ds/2.) & + (cell_df['position_x'] > x_vox - ds/2.) & + (cell_df['position_y'] < y_vox + ds/2.) & + (cell_df['position_y'] > y_vox - ds/2.) & + (cell_df['position_z'] < z_vox + ds/2.) & + (cell_df['position_z'] > z_vox - ds/2.) ) + vox_df = cell_df[inside_voxel] + return vox_df + + def _read_xml(self, xml_file, output_path='.'): + """ + Does the actual work of initializing MultiCellDS by parsing the xml + """ + + output_path = Path(output_path) + xml_file = output_path / xml_file + tree = ET.parse(xml_file) + + print('Reading {}'.format(xml_file)) + + root = tree.getroot() + MCDS = {} + + # Get current simulated time + metadata_node = root.find('metadata') + time_node = metadata_node.find('current_time') + MCDS['metadata'] = {} + MCDS['metadata']['current_time'] = float(time_node.text) + MCDS['metadata']['time_units'] = time_node.get('units') + + # Get current runtime + time_node = metadata_node.find('current_runtime') + MCDS['metadata']['current_runtime'] = float(time_node.text) + MCDS['metadata']['runtime_units'] = time_node.get('units') + + # find the microenvironment node + me_node = root.find('microenvironment') + me_node = me_node.find('domain') + + # find the mesh node + mesh_node = me_node.find('mesh') + MCDS['metadata']['spatial_units'] = mesh_node.get('units') + MCDS['mesh'] = {} + + # while we're at it, find the mesh + coord_str = mesh_node.find('x_coordinates').text + delimiter = mesh_node.find('x_coordinates').get('delimiter') + x_coords = np.array(coord_str.split(delimiter), dtype=np.float) + + coord_str = mesh_node.find('y_coordinates').text + delimiter = mesh_node.find('y_coordinates').get('delimiter') + y_coords = np.array(coord_str.split(delimiter), dtype=np.float) + + coord_str = mesh_node.find('z_coordinates').text + delimiter = mesh_node.find('z_coordinates').get('delimiter') + z_coords = np.array(coord_str.split(delimiter), dtype=np.float) + + # reshape into a mesh grid + xx, yy, zz = np.meshgrid(x_coords, y_coords, z_coords) + + MCDS['mesh']['x_coordinates'] = xx + MCDS['mesh']['y_coordinates'] = yy + MCDS['mesh']['z_coordinates'] = zz + + # Voxel data must be loaded from .mat file + voxel_file = mesh_node.find('voxels').find('filename').text + voxel_path = output_path / voxel_file + try: + initial_mesh = sio.loadmat(voxel_path)['mesh'] + except: + raise FileNotFoundError( + "No such file or directory:\n'{}' referenced in '{}'".format(voxel_path, xml_file)) + sys.exit(1) + + print('Reading {}'.format(voxel_path)) + + # center of voxel specified by first three rows [ x, y, z ] + # volume specified by fourth row + MCDS['mesh']['voxels'] = {} + MCDS['mesh']['voxels']['centers'] = initial_mesh[:3, :] + MCDS['mesh']['voxels']['volumes'] = initial_mesh[3, :] + + # Continuum_variables, unlike in the matlab version the individual chemical + # species will be primarily accessed through their names e.g. + # MCDS['continuum_variables']['oxygen']['units'] + # MCDS['continuum_variables']['glucose']['data'] + MCDS['continuum_variables'] = {} + variables_node = me_node.find('variables') + file_node = me_node.find('data').find('filename') + + # micro environment data is shape [4+n, len(voxels)] where n is the number + # of species being tracked. the first 3 rows represent (x, y, z) of voxel + # centers. The fourth row contains the voxel volume. The 5th row and up will + # contain values for that species in that voxel. + me_file = file_node.text + me_path = output_path / me_file + # Changes here + try: + me_data = sio.loadmat(me_path)['multiscale_microenvironment'] + except: + raise FileNotFoundError( + "No such file or directory:\n'{}' referenced in '{}'".format(me_path, xml_file)) + sys.exit(1) + + print('Reading {}'.format(me_path)) + + var_children = variables_node.findall('variable') + + # we're going to need the linear x, y, and z coordinates later + # but we dont need to get them in the loop + X, Y, Z = np.unique(xx), np.unique(yy), np.unique(zz) + + for si, species in enumerate(var_children): + species_name = species.get('name') + MCDS['continuum_variables'][species_name] = {} + MCDS['continuum_variables'][species_name]['units'] = species.get( + 'units') + + print('Parsing {:s} data'.format(species_name)) + + # initialize array for concentration data + MCDS['continuum_variables'][species_name]['data'] = np.zeros(xx.shape) + + # travel down one level on tree + species = species.find('physical_parameter_set') + + # diffusion data for each species + MCDS['continuum_variables'][species_name]['diffusion_coefficient'] = {} + MCDS['continuum_variables'][species_name]['diffusion_coefficient']['value'] \ + = float(species.find('diffusion_coefficient').text) + MCDS['continuum_variables'][species_name]['diffusion_coefficient']['units'] \ + = species.find('diffusion_coefficient').get('units') + + # decay data for each species + MCDS['continuum_variables'][species_name]['decay_rate'] = {} + MCDS['continuum_variables'][species_name]['decay_rate']['value'] \ + = float(species.find('decay_rate').text) + MCDS['continuum_variables'][species_name]['decay_rate']['units'] \ + = species.find('decay_rate').get('units') + + # store data from microenvironment file as numpy array + # iterate over each voxel + for vox_idx in range(MCDS['mesh']['voxels']['centers'].shape[1]): + # find the center + center = MCDS['mesh']['voxels']['centers'][:, vox_idx] + + i = np.where(np.abs(center[0] - X) < 1e-10)[0][0] + j = np.where(np.abs(center[1] - Y) < 1e-10)[0][0] + k = np.where(np.abs(center[2] - Z) < 1e-10)[0][0] + + MCDS['continuum_variables'][species_name]['data'][j, i, k] \ + = me_data[4+si, vox_idx] + + # in order to get to the good stuff we have to pass through a few different + # hierarchal levels + cell_node = root.find('cellular_information') + cell_node = cell_node.find('cell_populations') + cell_node = cell_node.find('cell_population') + cell_node = cell_node.find('custom') + # we want the PhysiCell data, there is more of it + for child in cell_node.findall('simplified_data'): + if child.get('source') == 'PhysiCell': + cell_node = child + break + + print( 'working on discrete cell data...\n') + + MCDS['discrete_cells'] = {} + data_labels = [] + # iterate over 'label's which are children of 'labels' these will be used to + # label data arrays + n = 0; + for label in cell_node.find('labels').findall('label'): + # I don't like spaces in my dictionary keys + fixed_label = label.text.replace(' ', '_') + nlabels = int(label.get('size')) + if nlabels > 1: + # tags to differentiate repeated labels (usually space related) + print("n=",n) + if( nlabels == 3 ): + dir_label = ['_x', '_y', '_z'] + else: + dir_label = []; + for nn in range(100): + dir_label.append( '_%u' % nn ) + print("dir_label= ", dir_label ) + print("label= ",label) + print("label.get('size')= ",nlabels) + for i in range(nlabels): + print( fixed_label + dir_label[i] ) + data_labels.append(fixed_label + dir_label[i]) + else: + data_labels.append(fixed_label) + print(fixed_label) + n += 1 + # load the file + cell_file = cell_node.find('filename').text + cell_path = output_path / cell_file + try: + cell_data = sio.loadmat(cell_path)['cells'] + except: + raise FileNotFoundError( + "No such file or directory:\n'{}' referenced in '{}'".format(cell_path, xml_file)) + sys.exit(1) + + print('Reading {}'.format(cell_path)) + + for col in range(len(data_labels)): + MCDS['discrete_cells'][data_labels[col]] = cell_data[col, :] + + return MCDS From 370e079b8bfe1e3c2af339d300ad61002d30eb04 Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Fri, 3 Jun 2022 04:59:44 -0400 Subject: [PATCH 05/38] udpate sampel projects to use new output --- ALL_CITATIONS.txt | 4 - Makefile | 216 +- config/PhysiCell_settings.xml | 1871 ++++------------- config/cells.csv | 11 - custom_modules/custom.cpp | 793 ------- custom_modules/custom.h | 101 - main-backup.cpp | 0 main.cpp | 257 --- output/empty.txt | 0 sample_projects/biorobots/main-biorobots.cpp | 6 +- .../main-cancer_biorobots.cpp | 6 +- .../cancer_immune/main-cancer_immune_3D.cpp | 6 +- sample_projects/celltypes3/main.cpp | 6 +- .../heterogeneity/main-heterogeneity.cpp | 6 +- sample_projects/interactions/main.cpp | 6 +- sample_projects/pred_prey_farmer/main.cpp | 6 +- sample_projects/template/main.cpp | 6 +- sample_projects/virus_macrophage/main.cpp | 6 +- sample_projects/worm/main.cpp | 6 +- 19 files changed, 609 insertions(+), 2704 deletions(-) delete mode 100644 ALL_CITATIONS.txt delete mode 100644 config/cells.csv delete mode 100644 custom_modules/custom.cpp delete mode 100644 custom_modules/custom.h delete mode 100644 main-backup.cpp delete mode 100644 main.cpp delete mode 100644 output/empty.txt diff --git a/ALL_CITATIONS.txt b/ALL_CITATIONS.txt deleted file mode 100644 index 338d8385d..000000000 --- a/ALL_CITATIONS.txt +++ /dev/null @@ -1,4 +0,0 @@ -Using PhysiCell version 1.10.2 - Please cite DOI: 10.1371/journal.pcbi.1005991 - Project website: http://PhysiCell.MathCancer.org - diff --git a/Makefile b/Makefile index 602d17216..595ea5cd2 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ VERSION := $(shell grep . VERSION.txt | cut -f1 -d:) -PROGRAM_NAME := interaction_demo +PROGRAM_NAME := project CC := g++ # CC := g++-mp-7 # typical macports compiler name @@ -14,17 +14,8 @@ 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 @@ -58,24 +49,194 @@ 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 +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) -# compile the project +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: main.cpp $(ALL_OBJECTS) - $(COMPILE_COMMAND) -o $(PROGRAM_NAME) $(ALL_OBJECTS) main.cpp - make name +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" + @echo "" + @echo "Sample intracellular projects: ode-energy-sample physiboss-cell-lines-sample cancer-metabolism-sample" + @echo "" + +template: + cp ./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 ./config/PhysiCell_settings.xml ./config/PhysiCell_settings-backup.xml + cp ./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-biorobots.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-cancer_biorobots.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-heterogeneity.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/ + +# ---- 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/ + +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/ + + +# 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 @@ -101,7 +262,7 @@ PhysiCell_custom.o: ./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 @@ -150,28 +311,25 @@ PhysiCell_MultiCellDS.o: ./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 + $(COMPILE_COMMAND) -c ./modules/PhysiCell_settings.cpp PhysiCell_basic_signaling.o: ./core/PhysiCell_basic_signaling.cpp - $(COMPILE_COMMAND) -c ./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 +# user-defined PhysiCell modules # cleanup reset: - rm -f *.cpp + rm -f *.cpp PhysiCell_cell.o cp ./sample_projects/Makefile-default Makefile rm -f ./custom_modules/* touch ./custom_modules/empty.txt @@ -180,7 +338,7 @@ reset: rm ALL_CITATIONS.txt cp ./config/PhysiCell_settings-backup.xml ./config/PhysiCell_settings.xml touch ./config/empty.csv - rm -f ./config/*.csv + rm ./config/*.csv clean: rm -f *.o @@ -190,9 +348,9 @@ 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/* @@ -263,4 +421,4 @@ upgrade: $(SOURCE) unzip $(SOURCE) PhysiCell/documentation/User_Guide.pdf mv -f PhysiCell/documentation/User_Guide.pdf documentation rm -f -r PhysiCell - rm -f $(SOURCE) \ No newline at end of file + rm -f $(SOURCE) diff --git a/config/PhysiCell_settings.xml b/config/PhysiCell_settings.xml index 68404dc82..5164a3782 100644 --- a/config/PhysiCell_settings.xml +++ b/config/PhysiCell_settings.xml @@ -1,9 +1,83 @@ + + + + + - -400 - 400 - -400 - 400 + -500 + 500 + -500 + 500 -10 10 20 @@ -13,7 +87,7 @@ - 10080 + 7200 min micron @@ -23,19 +97,19 @@ - 6 + 4 - output + output - 180 + 60 true - 30 + 15 true @@ -46,1491 +120,330 @@ false - true - false - - - 100000.0 - 0.1 - - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - - - - - - 100 - 0.1 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - 1000 - 0.1 - - 0.0 - 0.0 - - - - - - - - - - - - 1000 - 0.01 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - 1000 - 0.1 - - 0.0 - 0.0 - - - - - - - - + + + 100.0 + 0 + + 1 + 0 + + + + + + + 1000.0 + .1 + + 0 + 0 + + + + + + + 1000.0 + .1 + + 0 + 0 + + + - + + true true - - + + ./config/initial.mat - - + + ./config/dirichlet.mat - - - - - 0.00028 - - - - - - 0.00028 - - 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 - - - - - - 500 - 0.75 - 499 - 0.05 - 0.0045 - 0.0055 - 0 - 0 - 2.0 - - - - 0.04 - 20.0 - 1.25 - - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - - - - 1.8 - 15.12 - - - - - 1 - 5 - 0.2 - - true - true - - false - resource - 1 - - - - true - false - - 1 - 0 - 0.1 - 0 - 0 - - - - - - - - - 0 - 1 - 30 - 0 - - - 0.0 - 0.0 - 0.0 - 100 - - - 0 - 0.0 - 0.0 - 1 - - - 0.0 - 0.0 - 0.0 - 0.0 - - - 0.0 - 0.0 - 0.0 - 0.0 - - - - 0 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - 1 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - 0.15 - 0.075 - 0.15 - 0.25 - 0.5 - 0.0 - 0.0 - 0.0 - 0.0 - 36 - 100 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - - - - - - - - 0 - - - - - - 0 - - 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.4 - 10.0 - 1.25 - - 1 - 1 - 1 - 1 - 1 - 1 - 1 - - - 1.8 - 15.12 - - - - - 1 - 1 - .5 - - false - true - - false - debris - 1 - - - - false - false - - 0 - 0 - 0 - 0 - 0 - - - - - - - - - 1000 - 1 - 0 - 0 - - - 0.0 - 0.0 - 0 - 0.0 - - - 0.0 - 0.0 - 0 - 0.0 - - - 0.0 - 0.0 - 0.0 - 0.0 - - - 0.0 - 0.0 - 0.0 - 0.0 - - - - 0 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - 1 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - 0.15 - 0.075 - 0.15 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - - - - - - - - 0.002 - - - - - - 5.3e-08 - - 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.4 - 10.0 - 1.25 - - 1 - 1 - 1 - 1 - 1 - 1 - 1 - - - 1.8 - 15.12 - - - - - 1 - 1 - .5 - - false - true - - false - debris - 1 - - - - false - false - - 0 - 0 - 0 - 0 - 0 - - - - - - - - - 0 - 1 - 1 - 0 - - - 0.0 - 0.0 - 0 - 0.0 - - - 0.0 - 0.0 - 0.0 - 0.0 - - - 0.0 - 0.0 - 0.0 - 0.0 - - - 0.0 - 0.0 - 0.0 - 0.0 - - - - 0 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - 1 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - 0 - 0 - 0 - 0.0001 - 0 - 0 - 0 - - - - - - 0.15 - 0.075 - 0.15 - 0.0 - 0.0 - 0.4 - 100 - 0.1 - 0.1 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - - - - - - - - 5.3e-4 - - - - - - 5.3e-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.4 - 10.0 - 1.25 - - 1 - 1 - 1 - 1 - 1 - 1 - 1 - - - 1.8 - 15.12 - - - - - 1 - 1 - .5 - - false - true - - false - debris - 1 - - - - false - false - - 0 - 0 - 0 - 0 - 0 - - - - - - - - - 0 - 1 - 10 - 0 - - - 0.0 - 0.0 - 0 - 0.0 - - - 0.0 - 0.0 - 0.0 - 0.0 - - - 0.0 - 0.0 - 0.0 - 0.0 - - - 0.0 - 0.0 - 0.0 - 0.0 - - - - 0 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - 1 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - 0.15 - 0.075 - 0.15 - 0.0 - 0.0 - 0.2 - 100 - 0.0 - 0.0 - 0.0 - 0.0 - 0.5 - 0.0 - 0.0 - 0.0 - 0.0 - - - - - - - - 0 - - - - - - 0 - - 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 - - - - - - 3000 - 0.75 - 600 - 0.05 - 0.045 - 0.0055 - 0 - 0 - 2.0 - - - - 0.04 - 10.0 - 1.25 - - 1 - 1 - 1 - 1 - 1 - 1 - 1 - - - 1.8 - 15.12 - - - - - 1 - 5 - 0.1 - - true - true - - false - debris - 1 - - - - true - false - - 0 - 0 - 1 - 0 - 0.1 - - - - - - - - - 0 - 1 - 5 - 0 - - - 0.0 - 0.0 - 0.0 - 0 - - - 0.0 - 0.0 - 0.0 - 0 - - - 0.0 - 1.0 - 0 - 0.0 - - - 0.0 - 0.0 - 5 - 0.0 - - - - 0.05 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - 1 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - 0.15 - 0.075 - 0.15 - 0.05 - 0.01 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.005 - 0.1 - 1 - 0 - - - - - - - - 0 - - - - - - 0 - - 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 - - - - - - 3000 - 0.75 - 600 - 0.05 - 0.0045 - 0.0055 - 0 - 0 - 2.0 - - - - 0.04 - 10.0 - 1.25 - - 1 - 1 - 1 - 1 - 1 - 1 - 1 - - - 1.8 - 15.12 - - - - - 1 - 5 - 0.1 - - true - true - - true - pro-inflammatory - 1 - - - - false - false - - 0 - 0 - 0 - 0 - 0 - - - - - - - - - 0 - 1 - 5 - 0 - - - 0.0 - 0.0 - 0.0 - 0 - - - 0.0 - 0.0 - 0.0 - 0 - - - 0.0 - 0.0 - 1 - 0.0 - - - 0.0 - 0.0 - 0 - 0.0 - - - - 0 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - 10 - 0 - 0 - 0 - 0 - 0 - 0 - - 1 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - 0.15 - 0.075 - 0.15 - 0.0 - 0.5 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - - - - - - - - 0 - - - - - - 0 - - 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 - - - - - - 1000 - 0.75 - 200 - 0.05 - 0.045 - 0.0055 - 0 - 0 - 2.0 - - - - 0.04 - 10.0 - 1.25 - - 1 - 1 - 1 - 1 - 1 - 1 - 1 - - - 1.8 - 15.12 - - - - - 1 - 5 - 0.1 - - true - true - - true - pro-inflammatory - 1 - - - - false - false - - 0 - 0 - 0 - 0 - 0 - - - - - - - - - 0 - 1 - 5 - 0 - - - 0.0 - 0.0 - 0.0 - 0 - - - 0.0 - 0.0 - 0.0 - 0 - - - 0.0 - 0.0 - 1 - 0.0 - - - 0.0 - 0.0 - 0 - 0.0 - - - - 0 - - 0.05 - 0 - 0 - 0 - 0 - 0 - 0 - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - 1 - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - 0.15 - 0.075 - 0.15 - 0.0 - 0.5 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - 0.0 - - - - - - - - - cells.csv - - + + + + + + + + + 0.0 + + + + + + + + + 0 + + + + 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 + 10.0 + 1.25 + + + 1.8 + 15.12 + + + + + 0.25 + 5 + 0.5 + + + true + true + + false + food + -1 + + + + + + + 100 + 1 + 0 + 0 + + + + 0 + 1 + 0 + 0 + + + + 0 + 1 + 0 + 0 + + + + + + + 1.0 + 1.0 + 1.0 + + -1 + -1 + -10 + + + + + + + + + + + + 0.003 + + + + + 0 + 1 + + + + 10 + + + + 0.5 + 5 + 0.5 + + true + true + + false + food + 1 + + + + + + 1.0 + 1.0 + 1.0 + + -100 + 10 + 1 + + + + + + + + 0 + 0 + + + + 10 + + + + 0.5 + 2.5 + 0.7 + + + true + true + + false + prey signal + 1 + + + + + + 1.0 + 1.0 + 1.0 + + -2 + 100 + 1 + + + + - 0 - 50 - 400 - 40 - 20 - 50 - 50 - 50 - 0.0075 - + 0 + + + + + 15 + diff --git a/config/cells.csv b/config/cells.csv deleted file mode 100644 index da8c78e7a..000000000 --- a/config/cells.csv +++ /dev/null @@ -1,11 +0,0 @@ -0,0,0,0 -12,3,0,0 -24,5,0,0 -36,6,0,0 -48,5,0,0 -60,3,0,0 -72,0,0,0 -84,-3,0,0 -96,-5,0,0 -108,-6,0,0 -120,-5,0,0 \ No newline at end of file diff --git a/custom_modules/custom.cpp b/custom_modules/custom.cpp deleted file mode 100644 index a141e9226..000000000 --- a/custom_modules/custom.cpp +++ /dev/null @@ -1,793 +0,0 @@ -/* -############################################################################### -# 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 "./custom.h" - -void create_cell_types( void ) -{ - // set the random seed - 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(); - - /* - 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; - - // set up bacteria - - Cell_Definition* pCD = find_cell_definition( "bacteria"); - pCD->functions.update_phenotype = bacteria_phenotype; - // pCD->functions.update_migration_bias = advanced_chemotaxis_function; - // pCD->phenotype.motility.chemotactic_sensitivity( "resource" ) = 1; - // pCD->phenotype.motility.chemotactic_sensitivity( "quorum" ) = 0.1; - - // set up blood vessels - - pCD = find_cell_definition( "blood vessel"); - pCD->is_movable = false; - - // set up stem cells - - pCD = find_cell_definition( "stem"); - pCD->functions.update_phenotype = stem_cell_phenotype; - // pCD->phenotype.cell_transformations.transformation_rate("differentiated") = 0.0001; - - // set up differentiated cells - - pCD = find_cell_definition( "differentiated"); - pCD->functions.update_phenotype = differentiated_cell_phenotype; - - // set up macrophages - - pCD = find_cell_definition( "macrophage"); - // pCD->phenotype.cell_interactions.dead_phagocytosis_rate = 0.05; - pCD->functions.update_phenotype = macrophage_phenotype; - // pCD->functions.update_migration_bias = advanced_chemotaxis_function; - // pCD->phenotype.motility.chemotactic_sensitivity( "debris" ) = 0.1; - // pCD->phenotype.motility.chemotactic_sensitivity( "quorum" ) = 1; - - - // set up CD8+ T cells - pCD = find_cell_definition( "CD8+ T cell"); - pCD->functions.update_phenotype = CD8Tcell_phenotype; - // pCD->phenotype.cell_interactions.attack_rate("bacteria") = 0.05; - - // set up neutrophil - pCD = find_cell_definition( "neutrophil"); - pCD->functions.update_phenotype = neutrophil_phenotype; - // pCD->phenotype.cell_interactions.live_phagocytosis_rate("bacteria") = 0.05; - - /* - This builds the map of cell definitions and summarizes the setup. - */ - - build_cell_definitions_maps(); - 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]; - int num_cells = parameters.ints("number_of_cells"); - if( num_cells > 0 ) - { 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 ); - } - } - - // parameter-based placement - // bacteria - Cell_Definition* pCD = find_cell_definition("bacteria"); - std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; - for( int n = 0 ; n < parameters.ints("number_of_bacteria") ; 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 ); - } - - // blood vessels - pCD = find_cell_definition("blood vessel"); - std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; - for( int n = 0 ; n < parameters.ints("number_of_blood_vessels") ; 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 ); - } - - // stem cells - pCD = find_cell_definition("stem"); - std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; - for( int n = 0 ; n < parameters.ints("number_of_stem_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 ); - } - - // differentiated cells - pCD = find_cell_definition("differentiated"); - std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; - for( int n = 0 ; n < parameters.ints("number_of_differentiated_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 ); - } - - // macrophages - pCD = find_cell_definition("macrophage"); - std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; - for( int n = 0 ; n < parameters.ints("number_of_macrophages") ; 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 ); - } - - // neutrophils - pCD = find_cell_definition("neutrophil"); - std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; - for( int n = 0 ; n < parameters.ints("number_of_neutrophils") ; 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 ); - } - - // CD8+ T cells - pCD = find_cell_definition("CD8+ T cell"); - std::cout << "Placing cells of type " << pCD->name << " ... " << std::endl; - for( int n = 0 ; n < parameters.ints("number_of_CD8T_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 ); - } - - // load cells from your CSV file (if enabled) - load_cells_from_pugixml(); - - 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; } - -void bacteria_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) -{ - // find my cell definition - static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); - - // sample resource, quorum, and toxin - - static int nR = microenvironment.find_density_index( "resource" ); - static int nDebris = microenvironment.find_density_index( "debris" ); - static int nQuorum = microenvironment.find_density_index( "quorum" ); - static int nToxin = microenvironment.find_density_index( "toxin" ); - - // if dead: stop exporting quorum factor. - // also, replace phenotype function - if( phenotype.death.dead == true ) - { - phenotype.secretion.net_export_rates[nQuorum] = 0; - phenotype.secretion.net_export_rates[nToxin] = 0; - - phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; - - pCell->functions.update_phenotype = NULL; - return; - } - - std::vector samples = pCell->nearest_density_vector(); - double R = samples[nR]; - double Q = samples[nQuorum]; - double Tox = samples[nToxin]; - - // resource increases cycle entry - double base_val = pCD->phenotype.cycle.data.exit_rate(0); - double max_val = base_val * 10.0; - static double min_cycle_resource = pCD->custom_data["cycling_entry_threshold_resource"]; // 0.15 - phenotype.cycle.data.exit_rate(0) = max_val * linear_response_function( R, min_cycle_resource, 1 ); - - // resource decreses necrosis - - max_val = 0.0028; - static int nNecrosis = phenotype.death.find_death_model_index( PhysiCell_constants::necrosis_death_model ); - static double saturation_necrosis_resource = pCD->custom_data["necrosis_saturation_resource"]; //0.075 - static double threshold_necrosis_resource = pCD->custom_data["necrosis_threshold_resource"]; // 0.15 - phenotype.death.rates[nNecrosis] = max_val * - decreasing_linear_response_function( R, saturation_necrosis_resource, threshold_necrosis_resource ); - - // resource decreases motile speed - - double signal = R; - base_val = pCD->phenotype.motility.migration_speed; - double max_response = 0.0; - static double motility_resource_halfmax = - pCD->custom_data["migration_speed_halfmax"]; // 0.25 // parameters.doubles("bacteria_motility_resource_halfmax"); - double hill = Hill_response_function( signal, motility_resource_halfmax , 1.5); - phenotype.motility.migration_speed = base_val + (max_response-base_val)*hill; - - // quorum and resource increases motility bias - signal = Q+R; - base_val = pCD->phenotype.motility.migration_speed; - max_response = 1.0; - static double bias_halfmax = pCD->custom_data["migration_bias_halfmax"]; - // 0.5 // parameters.doubles("bacteria_migration_bias_halfmax"); - hill = Hill_response_function( signal, bias_halfmax , 1.5); - phenotype.motility.migration_bias = base_val + (max_response-base_val)*hill; - - // damage increases death - static int nApoptosis = phenotype.death.find_death_model_index( PhysiCell_constants::apoptosis_death_model ); - - signal = pCell->state.damage; - base_val = pCD->phenotype.death.rates[nApoptosis]; - - static double damage_halfmax = pCD->custom_data["damage_halfmax"]; - static double relative_max_damage_death = pCD->custom_data["relative_max_damage_death"]; - max_response = base_val * relative_max_damage_death; - - // 36 // parameters.doubles("bacteria_damage_halfmax"); - hill = Hill_response_function( signal , damage_halfmax , 1.5 ); - phenotype.death.rates[nApoptosis] = base_val + (max_response-base_val)*hill; - - return; -} - -/* https://www.karger.com/Article/Fulltext/494069 */ - -void macrophage_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) -{ - // find my cell definition - static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); - - // sample environment - - static int nPIF = microenvironment.find_density_index( "pro-inflammatory" ); - static int nDebris = microenvironment.find_density_index( "debris"); - static int nQ = microenvironment.find_density_index("quorum"); - - // if dead, release debris - if( phenotype.death.dead == true ) - { - phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; - pCell->functions.update_phenotype = NULL; - return; - } - - std::vector samples = pCell->nearest_density_vector(); - double PIF = samples[nPIF]; - double debris = samples[nDebris]; - double Q = samples[nQ]; - - // sample contacts - - static int bacteria_type = find_cell_definition( "bacteria")->type; - - int num_bacteria = 0; - int num_dead = 0; - for( int n=0; n < pCell->state.neighbors.size(); n++ ) - { - Cell* pC = pCell->state.neighbors[n]; - if( pC->phenotype.death.dead == true ) - { num_dead++; } - else - { - if( pC->type == bacteria_type ) - { num_bacteria++; } - } - } - - // contact with dead cells or bacteria, or debris - // increases secretion of pro-inflammatory - - static double secretion_dead_sensitivity = 1; - static double secretion_bacteria_sensitivity = 1; - static double secretion_debris_sensitivity = 2; - static double secretion_quorum_sensitivity = 5; - - double base_val = pCD->phenotype.secretion.secretion_rates[nPIF]; - double max_response = 10; // phenotype.volume.total; - double signal = - secretion_dead_sensitivity*num_dead + - secretion_bacteria_sensitivity*num_bacteria + - secretion_debris_sensitivity*debris + - secretion_quorum_sensitivity*Q; - double half_max = pCD->custom_data["secretion_halfmax"]; // 0.5; // 0.5; - double hill = Hill_response_function( signal , half_max , 1.5 ); - - - phenotype.secretion.secretion_rates[nPIF] = base_val + (max_response-base_val)*hill; - -/* - #pragma omp critical - { - std::cout << "secretion index: " << nPIF << " base: " << base_val << " max: " << max_response << " actual: " << phenotype.secretion.secretion_rates[nPIF] << std::endl; - std::cout << "\tsignal: " << signal << " vs halfmax: " << half_max << std::endl; - std::cout << "\t\tdead: " << num_dead << " bac: " << num_bacteria << " debris: " << debris << " Q: " << Q << std::endl; - std::cout << "\t\t\tsaturation: " << phenotype.secretion.saturation_densities[nPIF]<< std::endl; - } -*/ - - // chemotaxis bias increases with debris or quorum factor - - static double bias_debris_sensitivity = 0.1; - static double bias_quorum_sensitivity = 1; - - base_val = pCD->phenotype.motility.migration_bias; - max_response = 0.75; - signal = bias_debris_sensitivity*debris + - bias_quorum_sensitivity*Q ; // + 10 * PIF; - half_max = pCD->custom_data["migration_bias_halfmax"]; // 0.01 // 0.005 //0.1 // 0.05 - hill = Hill_response_function( signal , half_max , 1.5 ); - phenotype.motility.migration_bias = base_val + (max_response-base_val)*hill; - -/* - #pragma omp critical - { - std::cout << "signal: " << signal << " halfmax: " << half_max - << " hill: " << hill << std::endl; - - std::cout << "\tbase: " << base_val - << " max: " << max_response - << " actual: " << phenotype.motility.migration_bias << std::endl; - } -*/ - - // migration speed slows down in the presence of debris or quorum factor - - base_val = pCD->phenotype.motility.migration_speed; - max_response = 0.1 * base_val; - signal = bias_debris_sensitivity*debris + - bias_quorum_sensitivity*Q ; // + 10 * PIF; - half_max = pCD->custom_data["migration_speed_halfmax"]; // 0.1 // 0.05 - hill = Hill_response_function( signal , half_max , 1.5 ); - phenotype.motility.migration_speed = base_val + (max_response-base_val)*hill; - - return; -} - -void CD8Tcell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) -{ - // find my cell definition - static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); - - // sample environment - - static int nR = microenvironment.find_density_index( "resource"); - static int nTox = microenvironment.find_density_index( "toxin"); - static int nDebris = microenvironment.find_density_index( "debris" ); - static int nPIF = microenvironment.find_density_index( "pro-inflammatory"); - - std::vector samples = pCell->nearest_density_vector(); - double PIF = samples[nPIF]; - - // if dead, release debris - if( phenotype.death.dead == true ) - { - phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; - pCell->functions.update_phenotype = NULL; - return; - } - - // migration bias increases with pro-inflammatory - - double signal = PIF; - double base_val = pCD->phenotype.motility.migration_bias; - double max_val = 0.75; - double half_max = pCD->custom_data["migration_bias_halfmax"]; // 0.05 // 0.25 - double hill = Hill_response_function( PIF , half_max , 1.5 ); - - phenotype.motility.migration_bias = base_val + (max_val-base_val)*hill; - -/* - #pragma omp critical - { - std::cout << "signal: " << signal << " halfmax: " << half_max - << " hill: " << hill << std::endl; - - std::cout << "\tbase: " << base_val - << " max: " << max_val - << " actual: " << phenotype.motility.migration_bias << std::endl; - } -*/ - - return; -} - -void neutrophil_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) -{ - // find my cell definition - static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); - - // sample environment - - static int nR = microenvironment.find_density_index( "resource"); - static int nTox = microenvironment.find_density_index( "toxin"); - static int nDebris = microenvironment.find_density_index( "debris" ); - static int nPIF = microenvironment.find_density_index( "pro-inflammatory"); - - std::vector samples = pCell->nearest_density_vector(); - double PIF = samples[nPIF]; - - // if dead, release debris - if( phenotype.death.dead == true ) - { - phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; - pCell->functions.update_phenotype = NULL; - return; - } - - // migration bias increases with pro-inflammatory - - double signal = PIF; - double base_val = pCD->phenotype.motility.migration_bias; - double max_val = 0.75; - double half_max = pCD->custom_data["migration_bias_halfmax"]; // 0.25 - double hill = Hill_response_function( PIF , half_max , 1.5 ); - - phenotype.motility.migration_bias = base_val + (max_val-base_val)*hill; - - return; -} - -void stem_cell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) -{ - // find my cell definition - static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); - - // sample environment - - static int nR = microenvironment.find_density_index( "resource"); - static int nTox = microenvironment.find_density_index( "toxin"); - static int nDebris = microenvironment.find_density_index( "debris" ); - - // if dead, release debris - if( phenotype.death.dead == true ) - { - phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; - pCell->functions.update_phenotype = NULL; - return; - } - - std::vector samples = pCell->nearest_density_vector(); - double R = samples[nR]; - double toxin = samples[nTox]; - - // sample contacts - - static int stem_type = find_cell_definition( "stem")->type; - static int diff_type = find_cell_definition( "differentiated")->type; - static int bacteria_type = find_cell_definition( "bacteria")->type; - - int num_stem = 0; - int num_differentiated = 0; - int num_bacteria = 0; - int num_dead = 0; - for( int n=0; n < pCell->state.neighbors.size(); n++ ) - { - Cell* pC = pCell->state.neighbors[n]; - if( pC->phenotype.death.dead == true ) - { num_dead++; } - else - { - if( pC->type == stem_type ) - { num_stem++; } - if( pC->type == num_differentiated ) - { num_differentiated++; } - if( pC->type == bacteria_type ) - { num_bacteria++; } - } - } - - // contact with a stem cell increases differentiation - static double max_stem_diff = parameters.doubles("max_stem_differentiation"); // 0.0075 - static double stem_diff_halfmax = pCD->custom_data["differentiation_contact_halfmax"]; // 0.1 - - double base_val = 0; // phenotype.cell_transformations.transformation_rates[diff_type]; - double max_val = max_stem_diff; // 0.0075; - double signal = num_stem; - double half_max = stem_diff_halfmax; // 0.1; - double hill = Hill_response_function( signal, half_max , 1.5 ); - phenotype.cell_transformations.transformation_rates[diff_type] = base_val + (max_val-base_val)*hill; - - // contact with a differentiated cell reduces proliferation - // high rate of proliferation unless in contact with a differentiated cell - - static double stem_cycling_halfmax = pCD->custom_data["cycling_contact_halfmax"]; // 0.1; - - base_val = pCD->phenotype.cycle.data.exit_rate(0); // 0.002; - max_val = 0.0; - signal = num_differentiated; - half_max = stem_cycling_halfmax; // 0.1; - hill = Hill_response_function( signal, half_max , 1.5 ); - phenotype.cycle.data.exit_rate(0) = base_val + (max_val-base_val)*hill; - - // resource reduces necrotic death - - max_val = 0.0028; - static int nNecrosis = phenotype.death.find_death_model_index( PhysiCell_constants::necrosis_death_model ); - static double stem_saturation_necrosis = pCD->custom_data["necrosis_saturation_resource"]; - static double stem_threshold_necrosis = pCD->custom_data["necrosis_threshold_resource"]; - - phenotype.death.rates[nNecrosis] = max_val * - decreasing_linear_response_function( R, stem_saturation_necrosis, stem_threshold_necrosis ); - - // toxin increases apoptotic death - - static int nApoptosis = phenotype.death.find_death_model_index( PhysiCell_constants::apoptosis_death_model ); - - static double toxicity_halfmax = pCD->custom_data["toxicity_halfmax"]; // 0.4 - static double relative_max_toxicity = pCD->custom_data["relative_max_toxicity"]; - - signal = toxin; - base_val = pCD->phenotype.death.rates[nApoptosis]; - max_val = base_val * relative_max_toxicity; // 100*base_val; - - hill = Hill_response_function( signal , toxicity_halfmax , 1.5 ); - phenotype.death.rates[nApoptosis] = base_val + (max_val-base_val)*hill; - - return; -} - -void differentiated_cell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ) -{ - // find my cell definition - static Cell_Definition* pCD = find_cell_definition( pCell->type_name ); - - // sample environment - - static int nR = microenvironment.find_density_index( "resource"); - static int nTox = microenvironment.find_density_index( "toxin"); - static int nDebris = microenvironment.find_density_index( "debris" ); - - // if dead, release debris - if( phenotype.death.dead == true ) - { - phenotype.secretion.net_export_rates[nDebris] = phenotype.volume.total; - pCell->functions.update_phenotype = NULL; - return; - } - - std::vector samples = pCell->nearest_density_vector(); - double R = samples[nR]; - double toxin = samples[nTox]; - - - double signal = 0.0; - double hill = 0.0; - - // pressure reduces proliferation - signal = pCell->state.simple_pressure; - static double pressure_halfmax = pCD->custom_data["cycling_pressure_halfmax"]; // 0.5 - hill = Hill_response_function( signal, pressure_halfmax , 1.5 ); - double base_val = pCD->phenotype.cycle.data.exit_rate(0); - - phenotype.cycle.data.exit_rate(0) = (1-hill)*base_val; - - // resource reduces necrotic death - - double max_val = 0.0028; - static int nNecrosis = phenotype.death.find_death_model_index( PhysiCell_constants::necrosis_death_model ); - - // get same from bacteria - static double necrosis_saturation = pCD->custom_data["necrosis_saturation_resource"]; // 0.075 - static double necrosis_threshold = pCD->custom_data["necrosis_threshold_resource"]; // 0.15 - - phenotype.death.rates[nNecrosis] = max_val * - decreasing_linear_response_function( R, necrosis_saturation, necrosis_threshold ); - - // toxin increases apoptotic death - - static int nApoptosis = phenotype.death.find_death_model_index( PhysiCell_constants::apoptosis_death_model ); - - static double toxicity_halfmax = pCD->custom_data["toxicity_halfmax"]; // 0.2 - static double relative_max_tox_death = pCD->custom_data["relative_max_toxicity"]; // 100 - - signal = toxin; - base_val = pCD->phenotype.death.rates[nApoptosis]; - double max_response = base_val * relative_max_tox_death; - hill = Hill_response_function( signal , toxicity_halfmax , 1.5 ); - // std::cout << "tox: " << signal << " " << hill << std::endl; - phenotype.death.rates[nApoptosis] = base_val + (max_response-base_val)*hill; - - return; -} diff --git a/custom_modules/custom.h b/custom_modules/custom.h deleted file mode 100644 index 7b6616bc3..000000000 --- a/custom_modules/custom.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -############################################################################### -# 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 "../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 ); - -void bacteria_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); // final - -void macrophage_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); // final -void CD8Tcell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); -void neutrophil_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); - -void stem_cell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); // final -void differentiated_cell_phenotype( Cell* pCell, Phenotype& phenotype, double dt ); // final - diff --git a/main-backup.cpp b/main-backup.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 5b61d6861..000000000 --- a/main.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* -############################################################################### -# 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_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); - 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; - - 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"<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 ); - - // timer - - std::cout << std::endl << "Total simulation runtime: " << std::endl; - BioFVM::display_stopwatch_value( std::cout , BioFVM::runtime_stopwatch_value() ); - - return 0; -} diff --git a/output/empty.txt b/output/empty.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/sample_projects/biorobots/main-biorobots.cpp b/sample_projects/biorobots/main-biorobots.cpp index d2b9f5e86..05b39a49f 100644 --- a/sample_projects/biorobots/main-biorobots.cpp +++ b/sample_projects/biorobots/main-biorobots.cpp @@ -142,7 +142,7 @@ int main( int argc, char* argv[] ) char filename[1024]; sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 @@ -194,7 +194,7 @@ int main( int argc, char* argv[] ) { sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); } PhysiCell_globals.full_output_index++; @@ -237,7 +237,7 @@ int main( int argc, char* argv[] ) // save a final simulation snapshot sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 ); diff --git a/sample_projects/cancer_biorobots/main-cancer_biorobots.cpp b/sample_projects/cancer_biorobots/main-cancer_biorobots.cpp index 0a3148e0a..b686d11d8 100644 --- a/sample_projects/cancer_biorobots/main-cancer_biorobots.cpp +++ b/sample_projects/cancer_biorobots/main-cancer_biorobots.cpp @@ -144,7 +144,7 @@ int main( int argc, char* argv[] ) char filename[1024]; sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 @@ -210,7 +210,7 @@ int main( int argc, char* argv[] ) { sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); } PhysiCell_globals.full_output_index++; @@ -253,7 +253,7 @@ int main( int argc, char* argv[] ) // save a final simulation snapshot sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 ); diff --git a/sample_projects/cancer_immune/main-cancer_immune_3D.cpp b/sample_projects/cancer_immune/main-cancer_immune_3D.cpp index 1ae323dc3..3959fb514 100644 --- a/sample_projects/cancer_immune/main-cancer_immune_3D.cpp +++ b/sample_projects/cancer_immune/main-cancer_immune_3D.cpp @@ -145,7 +145,7 @@ int main( int argc, char* argv[] ) char filename[1024]; sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 @@ -211,7 +211,7 @@ int main( int argc, char* argv[] ) { sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); } PhysiCell_globals.full_output_index++; @@ -256,7 +256,7 @@ int main( int argc, char* argv[] ) // save a final simulation snapshot sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 ); diff --git a/sample_projects/celltypes3/main.cpp b/sample_projects/celltypes3/main.cpp index 58bf90402..cc2b26152 100644 --- a/sample_projects/celltypes3/main.cpp +++ b/sample_projects/celltypes3/main.cpp @@ -130,7 +130,7 @@ int main( int argc, char* argv[] ) char filename[1024]; sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 @@ -234,7 +234,7 @@ int main( int argc, char* argv[] ) { sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); } PhysiCell_globals.full_output_index++; @@ -289,7 +289,7 @@ int main( int argc, char* argv[] ) // save a final simulation snapshot sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); sprintf( filename , "%s/final.svg" , PhysiCell_settings.folder.c_str() ); SVG_plot_dark( filename , microenvironment, 0.0 , PhysiCell_globals.current_time, cell_coloring_function ); diff --git a/sample_projects/heterogeneity/main-heterogeneity.cpp b/sample_projects/heterogeneity/main-heterogeneity.cpp index e2fd9bf91..dcae79e93 100644 --- a/sample_projects/heterogeneity/main-heterogeneity.cpp +++ b/sample_projects/heterogeneity/main-heterogeneity.cpp @@ -143,7 +143,7 @@ int main( int argc, char* argv[] ) char filename[1024]; sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 @@ -195,7 +195,7 @@ int main( int argc, char* argv[] ) { sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); } PhysiCell_globals.full_output_index++; @@ -238,7 +238,7 @@ int main( int argc, char* argv[] ) // save a final simulation snapshot sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 ); diff --git a/sample_projects/interactions/main.cpp b/sample_projects/interactions/main.cpp index 826ec9497..100fdcb7c 100644 --- a/sample_projects/interactions/main.cpp +++ b/sample_projects/interactions/main.cpp @@ -140,7 +140,7 @@ int main( int argc, char* argv[] ) char filename[1024]; sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 @@ -192,7 +192,7 @@ int main( int argc, char* argv[] ) { sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); } PhysiCell_globals.full_output_index++; @@ -239,7 +239,7 @@ int main( int argc, char* argv[] ) // save a final simulation snapshot sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 ); diff --git a/sample_projects/pred_prey_farmer/main.cpp b/sample_projects/pred_prey_farmer/main.cpp index 2ba481a1f..2d6ddec87 100644 --- a/sample_projects/pred_prey_farmer/main.cpp +++ b/sample_projects/pred_prey_farmer/main.cpp @@ -140,7 +140,7 @@ int main( int argc, char* argv[] ) char filename[1024]; sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 @@ -192,7 +192,7 @@ int main( int argc, char* argv[] ) { sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); } PhysiCell_globals.full_output_index++; @@ -239,7 +239,7 @@ int main( int argc, char* argv[] ) // save a final simulation snapshot sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 ); diff --git a/sample_projects/template/main.cpp b/sample_projects/template/main.cpp index 378e646e3..9d26e541d 100644 --- a/sample_projects/template/main.cpp +++ b/sample_projects/template/main.cpp @@ -140,7 +140,7 @@ int main( int argc, char* argv[] ) char filename[1024]; sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 @@ -192,7 +192,7 @@ int main( int argc, char* argv[] ) { sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); } PhysiCell_globals.full_output_index++; @@ -239,7 +239,7 @@ int main( int argc, char* argv[] ) // save a final simulation snapshot sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 ); diff --git a/sample_projects/virus_macrophage/main.cpp b/sample_projects/virus_macrophage/main.cpp index e130f1017..b9fdfca8e 100644 --- a/sample_projects/virus_macrophage/main.cpp +++ b/sample_projects/virus_macrophage/main.cpp @@ -140,7 +140,7 @@ int main( int argc, char* argv[] ) char filename[1024]; sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 @@ -192,7 +192,7 @@ int main( int argc, char* argv[] ) { sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); } PhysiCell_globals.full_output_index++; @@ -242,7 +242,7 @@ int main( int argc, char* argv[] ) // save a final simulation snapshot sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 ); diff --git a/sample_projects/worm/main.cpp b/sample_projects/worm/main.cpp index 2ba481a1f..2d6ddec87 100644 --- a/sample_projects/worm/main.cpp +++ b/sample_projects/worm/main.cpp @@ -140,7 +140,7 @@ int main( int argc, char* argv[] ) char filename[1024]; sprintf( filename , "%s/initial" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 @@ -192,7 +192,7 @@ int main( int argc, char* argv[] ) { sprintf( filename , "%s/output%08u" , PhysiCell_settings.folder.c_str(), PhysiCell_globals.full_output_index ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + save_PhysiCell_to_MultiCellDS_v2( filename , microenvironment , PhysiCell_globals.current_time ); } PhysiCell_globals.full_output_index++; @@ -239,7 +239,7 @@ int main( int argc, char* argv[] ) // save a final simulation snapshot sprintf( filename , "%s/final" , PhysiCell_settings.folder.c_str() ); - save_PhysiCell_to_MultiCellDS_xml_pugi( filename , microenvironment , PhysiCell_globals.current_time ); + 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 ); From 861447d03479dd5f7ec0fde7a6d5c35c27c1dd58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 13:48:10 +0200 Subject: [PATCH 06/38] Added display pure virtual method to the intracellular interface --- core/PhysiCell_cell.cpp | 6 ++++++ core/PhysiCell_phenotype.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/core/PhysiCell_cell.cpp b/core/PhysiCell_cell.cpp index 768bb3623..0acf46851 100644 --- a/core/PhysiCell_cell.cpp +++ b/core/PhysiCell_cell.cpp @@ -1721,6 +1721,12 @@ void display_cell_definitions( std::ostream& os ) // size + + // intracellular + if (pCD->phenotype.intracellular != NULL) + { + pCD->phenotype.intracellular->display(os); + } Custom_Cell_Data* pCCD = &(pCD->custom_data); os << "\tcustom data: " << std::endl; diff --git a/core/PhysiCell_phenotype.h b/core/PhysiCell_phenotype.h index eb02accac..c17fc7020 100644 --- a/core/PhysiCell_phenotype.h +++ b/core/PhysiCell_phenotype.h @@ -615,6 +615,8 @@ class Intracellular virtual std::string get_state() = 0; + virtual void display(std::ostream& os) = 0; + virtual Intracellular* clone() = 0; virtual ~Intracellular(){}; From a11e27c402c86ef925e0444bf6f0e7498b611e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 13:48:49 +0200 Subject: [PATCH 07/38] Implemented display in PhysiBoSS --- addons/PhysiBoSS/src/maboss_intracellular.cpp | 23 +++++++++++++++++++ addons/PhysiBoSS/src/maboss_intracellular.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/addons/PhysiBoSS/src/maboss_intracellular.cpp b/addons/PhysiBoSS/src/maboss_intracellular.cpp index 63d8f60bf..3c2798ec7 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.cpp +++ b/addons/PhysiBoSS/src/maboss_intracellular.cpp @@ -139,6 +139,29 @@ MaBoSSIntracellular* getMaBoSSModel(PhysiCell::Phenotype& phenotype) { return static_cast(phenotype.intracellular); } +void MaBoSSIntracellular::display(std::ostream& os) +{ + os << "\tintracellular model using maboss" << std::endl + << "\t\t model bnd : " << bnd_filename << std::endl + << "\t\t model cfg : " << cfg_filename << std::endl + << "\t\t dt = " << time_step << std::endl + << "\t\t " << initial_values.size() << " initial values override" << std::endl; + for (auto& initial_value : initial_values) + os << "\t\t\t" << initial_value.first << " = " << initial_value.second << std::endl; + + os << "\t\t " << parameters.size() << " parameters override" << std::endl; + for (auto& parameter : parameters) + os << "\t\t\t" << parameter.first << " = " << parameter.second << std::endl; + + os << "\t\t " << mutations.size() << " mutations override" << std::endl; + for (auto& mutation : mutations) + os << "\t\t\t" << mutation.first << " = " << mutation.second << std::endl; + + os << "\t\t scaling = " << scaling << std::endl + << "\t\t time_stochasticity = " << time_stochasticity << std::endl + << std::endl; +} + void MaBoSSIntracellular::save(std::string filename, std::vector& cells) { diff --git a/addons/PhysiBoSS/src/maboss_intracellular.h b/addons/PhysiBoSS/src/maboss_intracellular.h index 3c73817fe..a1bc76862 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.h +++ b/addons/PhysiBoSS/src/maboss_intracellular.h @@ -90,6 +90,8 @@ class MaBoSSIntracellular : public PhysiCell::Intracellular { void print_current_nodes(){ this->maboss.print_nodes(); } + + void display(std::ostream& os); static void save(std::string filename, std::vector& cells); From f6e9e18046e664bcd9f1526938ec22d4e202fd81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 14:20:13 +0200 Subject: [PATCH 08/38] Added dummy implementation of display for dfba and librr --- addons/dFBA/src/dfba_intracellular.h | 1 + addons/libRoadrunner/src/librr_intracellular.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/dFBA/src/dfba_intracellular.h b/addons/dFBA/src/dfba_intracellular.h index a7ab44798..f916a7f09 100644 --- a/addons/dFBA/src/dfba_intracellular.h +++ b/addons/dFBA/src/dfba_intracellular.h @@ -95,6 +95,7 @@ class dFBAIntracellular : public PhysiCell::Intracellular void print_current_nodes() {} // static void save_PhysiBoSS(std::string path, std::string index); + void display(std::ostream&os) {} static void save_dFBA(std::string path, std::string index); }; diff --git a/addons/libRoadrunner/src/librr_intracellular.h b/addons/libRoadrunner/src/librr_intracellular.h index b02ba7e4b..49a4e96cb 100644 --- a/addons/libRoadrunner/src/librr_intracellular.h +++ b/addons/libRoadrunner/src/librr_intracellular.h @@ -99,7 +99,7 @@ class RoadRunnerIntracellular : public PhysiCell::Intracellular void set_parameter_value(std::string name, double value); std::string get_state(); - + void display(std::ostream&os) {} // for now, define dummy methods for these in the abstract parent class bool has_variable(std::string name) { return false; } bool get_boolean_variable_value(std::string name) { return false; } From eb6cb5b337c3f21ae8c2a358ead4dea5b731b955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 14:46:45 +0200 Subject: [PATCH 09/38] Added new update function in intracellular interface --- core/PhysiCell_phenotype.h | 1 + 1 file changed, 1 insertion(+) diff --git a/core/PhysiCell_phenotype.h b/core/PhysiCell_phenotype.h index eb02accac..d7a7a9765 100644 --- a/core/PhysiCell_phenotype.h +++ b/core/PhysiCell_phenotype.h @@ -606,6 +606,7 @@ class Intracellular // This function update the model for the time_step defined in the xml definition virtual void update() = 0; + virtual void update(Cell* cell, Phenotype& phenotype, double dt) = 0; // Get value for model parameter virtual double get_parameter_value(std::string name) = 0; From 034892e544d58789283f940469cf34cdc6ca02ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 14:55:05 +0200 Subject: [PATCH 10/38] Added call to intracellular update in update_all_cells() --- core/PhysiCell_cell_container.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/PhysiCell_cell_container.cpp b/core/PhysiCell_cell_container.cpp index c6c3584b1..ee17a4610 100644 --- a/core/PhysiCell_cell_container.cpp +++ b/core/PhysiCell_cell_container.cpp @@ -139,6 +139,17 @@ void Cell_Container::update_all_cells(double t, double phenotype_dt_ , double me static double phenotype_dt_tolerance = 0.001 * phenotype_dt_; static double mechanics_dt_tolerance = 0.001 * mechanics_dt_; + // intracellular update. called for every diffusion_dt, but actually depends on the intracellular_dt of each cell (as it can be noisy) + + #pragma omp parallel for + for( int i=0; i < (*all_cells).size(); i++ ) + { + if( (*all_cells)[i]->phenotype.intracellular != NULL && (*all_cells)[i]->phenotype.intracellular->need_update()) + { + (*all_cells)[i]->phenotype.intracellular->update( (*all_cells)[i], (*all_cells)[i]->phenotype , diffusion_dt_ ); + } + } + if( fabs(time_since_last_cycle-phenotype_dt_ ) < phenotype_dt_tolerance || !initialzed) { // Reset the max_radius in each voxel. It will be filled in set_total_volume From 2f858fa1160ebcc2a487b85dafe6502b643bdc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 15:30:17 +0200 Subject: [PATCH 11/38] Added function pointers for pre and post intracellular custom update --- core/PhysiCell_cell_container.cpp | 6 ++++++ core/PhysiCell_phenotype.cpp | 3 +++ core/PhysiCell_phenotype.h | 3 +++ 3 files changed, 12 insertions(+) diff --git a/core/PhysiCell_cell_container.cpp b/core/PhysiCell_cell_container.cpp index ee17a4610..13fe12008 100644 --- a/core/PhysiCell_cell_container.cpp +++ b/core/PhysiCell_cell_container.cpp @@ -146,7 +146,13 @@ void Cell_Container::update_all_cells(double t, double phenotype_dt_ , double me { if( (*all_cells)[i]->phenotype.intracellular != NULL && (*all_cells)[i]->phenotype.intracellular->need_update()) { + if ((*all_cells)[i]->functions.pre_update_intracellular != NULL) + (*all_cells)[i]->functions.pre_update_intracellular( (*all_cells)[i], (*all_cells)[i]->phenotype , diffusion_dt_ ); + (*all_cells)[i]->phenotype.intracellular->update( (*all_cells)[i], (*all_cells)[i]->phenotype , diffusion_dt_ ); + + if ((*all_cells)[i]->functions.post_update_intracellular != NULL) + (*all_cells)[i]->functions.post_update_intracellular( (*all_cells)[i], (*all_cells)[i]->phenotype , diffusion_dt_ ); } } diff --git a/core/PhysiCell_phenotype.cpp b/core/PhysiCell_phenotype.cpp index e6e5d49a5..e5a4f8bdc 100644 --- a/core/PhysiCell_phenotype.cpp +++ b/core/PhysiCell_phenotype.cpp @@ -1149,6 +1149,9 @@ Cell_Functions::Cell_Functions() update_phenotype = NULL; custom_cell_rule = NULL; + pre_update_intracellular = NULL; + post_update_intracellular = NULL; + update_velocity = NULL; add_cell_basement_membrane_interactions = NULL; calculate_distance_to_membrane = NULL; diff --git a/core/PhysiCell_phenotype.h b/core/PhysiCell_phenotype.h index d7a7a9765..12ce2d936 100644 --- a/core/PhysiCell_phenotype.h +++ b/core/PhysiCell_phenotype.h @@ -482,6 +482,9 @@ class Cell_Functions void (*custom_cell_rule)( Cell* pCell, Phenotype& phenotype, double dt ); void (*update_phenotype)( Cell* pCell, Phenotype& phenotype, double dt ); // used in celll + void (*pre_update_intracellular) ( Cell* pCell, Phenotype& phenotype, double dt ); + void (*post_update_intracellular) ( Cell* pCell, Phenotype& phenotype, double dt ); + void (*update_velocity)( Cell* pCell, Phenotype& phenotype, double dt ); void (*add_cell_basement_membrane_interactions)(Cell* pCell, Phenotype& phenotype, double dt ); From bc4b655d242e05f1b64061a43e2754d39d0003aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 14:57:11 +0200 Subject: [PATCH 12/38] Implemented new update in physiboss --- addons/PhysiBoSS/src/maboss_intracellular.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/addons/PhysiBoSS/src/maboss_intracellular.h b/addons/PhysiBoSS/src/maboss_intracellular.h index 3c73817fe..0b2319bad 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.h +++ b/addons/PhysiBoSS/src/maboss_intracellular.h @@ -57,6 +57,11 @@ class MaBoSSIntracellular : public PhysiCell::Intracellular { this->maboss.run_simulation(); this->next_physiboss_run += this->maboss.get_time_to_update(); } + + void update(PhysiCell::Cell * cell, PhysiCell::Phenotype& phenotype, double dt) { + this->maboss.run_simulation(); + this->next_physiboss_run += this->maboss.get_time_to_update(); + } bool need_update() { return PhysiCell::PhysiCell_globals.current_time >= this->next_physiboss_run; From 65c4076b34b096a72bb776b8b93345880c21dd30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 15:01:34 +0200 Subject: [PATCH 13/38] Fixed physiboss-cell-lines example --- .../custom_modules/custom.cpp | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp b/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp index 096256faf..d24d7df3a 100644 --- a/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp +++ b/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp @@ -183,23 +183,13 @@ void setup_tissue( void ) void tumor_cell_phenotype_with_signaling( Cell* pCell, Phenotype& phenotype, double dt ) { + if (PhysiCell::PhysiCell_globals.current_time >= 100.0 + && pCell->phenotype.intracellular->get_parameter_value("$time_scale") == 0.0 + ){ + pCell->phenotype.intracellular->set_parameter_value("$time_scale", 0.1); + } - if (pCell->phenotype.intracellular->need_update()) - { - if ( - pCell->type == get_cell_definition("last_one").type - && PhysiCell::PhysiCell_globals.current_time >= 100.0 - && pCell->phenotype.intracellular->get_parameter_value("$time_scale") == 0.0 - ) - pCell->phenotype.intracellular->set_parameter_value("$time_scale", 0.1); - - set_input_nodes(pCell); - - pCell->phenotype.intracellular->update(); - - from_nodes_to_cell(pCell, phenotype, dt); - color_node(pCell); - } + color_node(pCell); } From 1f4827fc0bca339dc81c61ae68445d22228231ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 15:13:18 +0200 Subject: [PATCH 14/38] Added tentative of update implementation for librr --- addons/libRoadrunner/src/librr_intracellular.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/libRoadrunner/src/librr_intracellular.h b/addons/libRoadrunner/src/librr_intracellular.h index b02ba7e4b..a2c8d28f4 100644 --- a/addons/libRoadrunner/src/librr_intracellular.h +++ b/addons/libRoadrunner/src/librr_intracellular.h @@ -88,7 +88,10 @@ class RoadRunnerIntracellular : public PhysiCell::Intracellular // Need 'int' return type to avoid bizarre compile errors. void update(); - + void update(PhysiCell::Cell* cell, PhysiCell::Phenotype& phenotype, double dt) { + update(); + update_phenotype_parameters(phenotype); + } int update_phenotype_parameters(PhysiCell::Phenotype& phenotype); int validate_PhysiCell_tokens(PhysiCell::Phenotype& phenotype); From 3cc4c3a128dc5c5751b8ab72c8bc46c98091741d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 18:23:25 +0200 Subject: [PATCH 15/38] PhysiBoSS cell lines now using pre and post update intracellular custom fuctions --- .../physiboss_cell_lines/custom_modules/custom.cpp | 11 +++++++---- .../physiboss_cell_lines/custom_modules/custom.h | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp b/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp index d24d7df3a..ba7c345c5 100644 --- a/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp +++ b/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp @@ -89,7 +89,8 @@ void create_cell_types( void ) cell_defaults.functions.update_velocity = NULL; cell_defaults.functions.update_migration_bias = NULL; - cell_defaults.functions.update_phenotype = tumor_cell_phenotype_with_signaling; // update_cell_and_death_parameters_O2_based; + cell_defaults.functions.pre_update_intracellular = pre_update_intracellular; + cell_defaults.functions.post_update_intracellular = post_update_intracellular; cell_defaults.functions.custom_cell_rule = NULL; cell_defaults.functions.add_cell_basement_membrane_interactions = NULL; @@ -181,17 +182,19 @@ void setup_tissue( void ) } -void tumor_cell_phenotype_with_signaling( Cell* pCell, Phenotype& phenotype, double dt ) +void pre_update_intracellular( Cell* pCell, Phenotype& phenotype, double dt ) { if (PhysiCell::PhysiCell_globals.current_time >= 100.0 && pCell->phenotype.intracellular->get_parameter_value("$time_scale") == 0.0 ){ pCell->phenotype.intracellular->set_parameter_value("$time_scale", 0.1); } - - color_node(pCell); } +void post_update_intracellular( Cell* pCell, Phenotype& phenotype, double dt ) +{ + color_node(pCell); +} void set_input_nodes(Cell* pCell) {} 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 650b41064..77b7347f0 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 @@ -84,7 +84,8 @@ void setup_microenvironment( void ); std::vector my_coloring_function( Cell* ); // custom cell phenotype functions could go here -void tumor_cell_phenotype_with_signaling( Cell* pCell, Phenotype& phenotype, double dt ); +void pre_update_intracellular( Cell* pCell, Phenotype& phenotype, double dt ); +void post_update_intracellular( Cell* pCell, Phenotype& phenotype, double dt ); /** \brief Write Density values to output file */ void set_input_nodes(Cell* pCell); void from_nodes_to_cell(Cell* pCell, Phenotype& phenotype, double dt); From 5a956d824dcd4453e4e308c58ba9ceabbf31fcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Fri, 3 Jun 2022 18:25:59 +0200 Subject: [PATCH 16/38] Cleanup physiboss cell lines example --- .../boolean/physiboss_cell_lines/custom_modules/custom.cpp | 6 ------ .../boolean/physiboss_cell_lines/custom_modules/custom.h | 3 --- 2 files changed, 9 deletions(-) diff --git a/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp b/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp index ba7c345c5..c7cb3fc6b 100644 --- a/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp +++ b/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp @@ -181,7 +181,6 @@ void setup_tissue( void ) return; } - void pre_update_intracellular( Cell* pCell, Phenotype& phenotype, double dt ) { if (PhysiCell::PhysiCell_globals.current_time >= 100.0 @@ -196,11 +195,6 @@ void post_update_intracellular( Cell* pCell, Phenotype& phenotype, double dt ) color_node(pCell); } -void set_input_nodes(Cell* pCell) {} - -void from_nodes_to_cell(Cell* pCell, Phenotype& phenotype, double dt) {} - - std::vector my_coloring_function( Cell* pCell ) { std::vector< std::string > output( 4 , "rgb(0,0,0)" ); 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 77b7347f0..44cd833d9 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 @@ -86,9 +86,6 @@ std::vector my_coloring_function( Cell* ); // custom cell phenotype functions could go here void pre_update_intracellular( Cell* pCell, Phenotype& phenotype, double dt ); void post_update_intracellular( Cell* pCell, Phenotype& phenotype, double dt ); -/** \brief Write Density values to output file */ -void set_input_nodes(Cell* pCell); -void from_nodes_to_cell(Cell* pCell, Phenotype& phenotype, double dt); void color_node(Cell* pCell); #endif \ No newline at end of file From 5e137a9f73f9f3a6f5345876a50b72722954255f Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Fri, 3 Jun 2022 14:16:17 -0400 Subject: [PATCH 17/38] Create empty.txt --- output/empty.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 output/empty.txt diff --git a/output/empty.txt b/output/empty.txt new file mode 100644 index 000000000..e69de29bb From 32349f1d41eebcd1e31273b910537396c2232e50 Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Sat, 4 Jun 2022 01:37:12 -0400 Subject: [PATCH 18/38] updates - cell graphs --- core/PhysiCell_cell.cpp | 4 +- modules/PhysiCell_MultiCellDS.cpp | 171 ++++++++++++++++++++++++++++++ modules/PhysiCell_MultiCellDS.h | 4 +- 3 files changed, 176 insertions(+), 3 deletions(-) diff --git a/core/PhysiCell_cell.cpp b/core/PhysiCell_cell.cpp index 0acf46851..33c539358 100644 --- a/core/PhysiCell_cell.cpp +++ b/core/PhysiCell_cell.cpp @@ -2894,13 +2894,13 @@ Cell_Definition* initialize_cell_definition_from_pugixml( pugi::xml_node cd_node } // intracellular - node = cd_node.child( "phenotype" ); node = node.child( "intracellular" ); if( node ) { std::string model_type = node.attribute( "type" ).value(); + #ifdef ADDON_PHYSIBOSS if (model_type == "maboss") { // If it has already be copied @@ -2950,7 +2950,7 @@ Cell_Definition* initialize_cell_definition_from_pugixml( pugi::xml_node cd_node #endif } - + // set up custom data node = cd_node.child( "custom_data" ); pugi::xml_node node1 = node.first_child(); diff --git a/modules/PhysiCell_MultiCellDS.cpp b/modules/PhysiCell_MultiCellDS.cpp index 95628c34c..c3beacf7c 100644 --- a/modules/PhysiCell_MultiCellDS.cpp +++ b/modules/PhysiCell_MultiCellDS.cpp @@ -1938,9 +1938,180 @@ void add_PhysiCell_cells_to_open_xml_pugi_v2( pugi::xml_document& xml_dom, std:: fclose( fp ); + // neighbor graph + node = node.parent().parent(); // custom + + root = node; + node = node.child( "neighbor_graph" ); + if( !node ) + { + node = root.append_child( "neighbor_graph" ); + + pugi::xml_attribute attrib = node.append_attribute( "type" ); + attrib.set_value( "text" ); + + attrib = node.append_attribute( "source" ); + attrib.set_value( "PhysiCell" ); + + attrib = node.append_attribute( "data_version" ); + attrib.set_value( "2" ); + } + root = node; // root = cellular_information.cell_populations.cell_population.custom.neighbor_graph + node = root.child( "filename"); + if( !node ) + { + node = root.append_child( "filename" ); + + } + root = node; // root = cellular_information.cell_populations.cell_population.custom.neighbor_graph.filename + + + // next, filename + sprintf( filename , "%s_cell_neighbor_graph.txt" , filename_base.c_str() ); + + /* store filename without the relative pathing (if any) */ + filename_start = strrchr( filename , '/' ); + if( filename_start == NULL ) + { filename_start = filename; } + else + { filename_start++; } + strcpy( filename_without_pathing , filename_start ); + + if( !node.first_child() ) + { + node.append_child( pugi::node_pcdata ).set_value( filename_without_pathing ); // filename ); + } + else + { + node.first_child().set_value( filename_without_pathing ); // filename ); + } + + write_neighbor_graph( filename ); + + + // attached cell graph + node = root; + node = node.parent().parent(); // root = cellular_information.cell_populations.cell_population.custom + + root = node; + node = node.child( "attached_cells_graph" ); + if( !node ) + { + node = root.append_child( "attached_cells_graph" ); + + pugi::xml_attribute attrib = node.append_attribute( "type" ); + attrib.set_value( "text" ); + + attrib = node.append_attribute( "source" ); + attrib.set_value( "PhysiCell" ); + + attrib = node.append_attribute( "data_version" ); + attrib.set_value( "2" ); + } + root = node; // root = cellular_information.cell_populations.cell_population.custom.attached_cells_graph + node = root.child( "filename"); + if( !node ) + { node = root.append_child( "filename" ); } + root = node; // root = cellular_information.cell_populations.cell_population.custom.attached_cells_graph.filename + + + // next, filename + sprintf( filename , "%s_attached_cells_graph.txt" , filename_base.c_str() ); + + /* store filename without the relative pathing (if any) */ + filename_start = strrchr( filename , '/' ); + if( filename_start == NULL ) + { filename_start = filename; } + else + { filename_start++; } + strcpy( filename_without_pathing , filename_start ); + + if( !node.first_child() ) + { + node.append_child( pugi::node_pcdata ).set_value( filename_without_pathing ); // filename ); + } + else + { + node.first_child().set_value( filename_without_pathing ); // filename ); + } + + write_attached_cells_graph( filename ); + return; } +void write_neighbor_graph( std::string filename_base ) +{ + char filename [1024]; + sprintf( filename , "%s_cell_neighbor_graph.txt" , filename_base.c_str() ); + + /* store filename without the relative pathing (if any) */ + char filename_without_pathing [1024]; + char* filename_start = strrchr( filename , '/' ); + if( filename_start == NULL ) + { filename_start = filename; } + else + { filename_start++; } + strcpy( filename_without_pathing , filename_start ); + + std::ofstream of( filename , std::ios::out ); + std::stringstream buffer; + + for( int i=0 ; i < (*all_cells).size(); i++ ) + { + buffer << (*all_cells)[i]->ID << ": " ; + int size = (*all_cells)[i]->state.neighbors.size(); + for( int j=0 ; j < size; j++ ) + { + buffer << (*all_cells)[i]->state.neighbors[j]->ID; + if( j != size-1 ) + { buffer << ","; } + } + if( i != (*all_cells).size()-1 ) + { buffer << std::endl; } + of << buffer.rdbuf(); + } + of.close(); + + return; +} + + +void write_attached_cells_graph( std::string filename_base ) +{ + char filename [1024]; + sprintf( filename , "%s_cell_attached_graph.txt" , filename_base.c_str() ); + + /* store filename without the relative pathing (if any) */ + char filename_without_pathing [1024]; + char* filename_start = strrchr( filename , '/' ); + if( filename_start == NULL ) + { filename_start = filename; } + else + { filename_start++; } + strcpy( filename_without_pathing , filename_start ); + + std::ofstream of( filename , std::ios::out ); + std::stringstream buffer; + + for( int i=0 ; i < (*all_cells).size(); i++ ) + { + buffer << (*all_cells)[i]->ID << ": " ; + int size = (*all_cells)[i]->state.attached_cells.size(); + for( int j=0 ; j < size; j++ ) + { + buffer << (*all_cells)[i]->state.attached_cells[j]->ID; + if( j != size-1 ) + { buffer << ","; } + } + if( i != (*all_cells).size()-1 ) + { buffer << std::endl; } + of << buffer.rdbuf(); + } + of.close(); + + return; +} }; diff --git a/modules/PhysiCell_MultiCellDS.h b/modules/PhysiCell_MultiCellDS.h index fe3a3f7d3..68d611a1a 100644 --- a/modules/PhysiCell_MultiCellDS.h +++ b/modules/PhysiCell_MultiCellDS.h @@ -69,6 +69,7 @@ #define __PhysiCell_MultiCellDS_h__ #include +#include #include #include #include @@ -101,7 +102,8 @@ void save_PhysiCell_to_MultiCellDS_xml_pugi_v2( std::string filename_base , Micr void add_PhysiCell_cells_to_open_xml_pugi_v2( pugi::xml_document& xml_dom, std::string filename_base, Microenvironment& M ); void save_PhysiCell_to_MultiCellDS_v2( std::string filename_base , Microenvironment& M , double current_simulation_time); - +void write_neighbor_graph( std::string filename_base ); +void write_attached_cells_graph( std::string filename_base ); }; From 65ffa5651ddb95b6d934ad73f93b75548a83b149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Mon, 6 Jun 2022 15:29:51 +0200 Subject: [PATCH 19/38] Created data structure for PhysiBoSS mapping --- addons/PhysiBoSS/src/maboss_intracellular.h | 1 + addons/PhysiBoSS/src/maboss_network.h | 1 - addons/PhysiBoSS/src/utils.h | 47 +++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/addons/PhysiBoSS/src/maboss_intracellular.h b/addons/PhysiBoSS/src/maboss_intracellular.h index 868d16e4f..82388bdf5 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.h +++ b/addons/PhysiBoSS/src/maboss_intracellular.h @@ -8,6 +8,7 @@ #include "../../../core/PhysiCell_cell.h" #include "../../../modules/PhysiCell_pugixml.h" #include "maboss_network.h" +#include "utils.h" static std::string PhysiBoSS_Version = "2.1.0"; diff --git a/addons/PhysiBoSS/src/maboss_network.h b/addons/PhysiBoSS/src/maboss_network.h index 9dbf38dbb..580939e17 100644 --- a/addons/PhysiBoSS/src/maboss_network.h +++ b/addons/PhysiBoSS/src/maboss_network.h @@ -4,7 +4,6 @@ #include "StochasticSimulationEngine.h" #include "BooleanNetwork.h" #include "RunConfig.h" -#include "utils.h" #include "../../../core/PhysiCell_utilities.h" /** diff --git a/addons/PhysiBoSS/src/utils.h b/addons/PhysiBoSS/src/utils.h index 9e4307cc2..a0766c566 100644 --- a/addons/PhysiBoSS/src/utils.h +++ b/addons/PhysiBoSS/src/utils.h @@ -1,4 +1,51 @@ #ifndef _PhysiBoSS_utils_h_ #define _PhysiBoSS_utils_h_ +#include "maboss_network.h" +class MaBoSSInput +{ + static const int NODE = 0; + static const int PARAMETER = 1; +public: + std::string physicell_name; + int type; + std::string intracellular_name; + std::string intracellular_parameter; + std::string action; + double threshold; + double inact_threshold; + double scaling; + int smoothing; + double smoothed_value; + MaBoSSInput(std::string physicell_name, std::string intracellular_name, std::string action, double threshold, double inact_threshold, int smoothing) : physicell_name(physicell_name), intracellular_name(intracellular_name), action(action), threshold(threshold), inact_threshold(inact_threshold), smoothing(smoothing) { + type = NODE; + smoothed_value = 0; + } + + MaBoSSInput(std::string physicell_name, std::string intracellular_parameter, double scaling, int smoothing) : physicell_name(physicell_name), intracellular_parameter(intracellular_parameter), scaling(scaling), smoothing(smoothing) { + type = PARAMETER; + smoothed_value = 0; + } + + bool isNode() { return type == NODE; } + bool isParameter() { return type == PARAMETER; } + +}; + +class MaBoSSOutput +{ +public: + std::string physicell_name; + std::string intracellular_name; + std::string action; + double value; + double base_value; + int smoothing; + double smoothed_value; + + MaBoSSOutput(std::string physicell_name, std::string intracellular_name, std::string action, double value, double base_value, int smoothing) : physicell_name(physicell_name), intracellular_name(intracellular_name), action(action), value(value), base_value(base_value), smoothing(smoothing) { + smoothed_value = base_value; + } + +}; #endif \ No newline at end of file From c29a3550e9c95f313e61c7c00b466aa4269c60aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Mon, 6 Jun 2022 15:32:47 +0200 Subject: [PATCH 20/38] Updated of intracellular xml specification. Added depreciation warnings --- addons/PhysiBoSS/src/maboss_intracellular.cpp | 186 ++++++++++++++---- 1 file changed, 151 insertions(+), 35 deletions(-) diff --git a/addons/PhysiBoSS/src/maboss_intracellular.cpp b/addons/PhysiBoSS/src/maboss_intracellular.cpp index 3c2798ec7..270c78e52 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.cpp +++ b/addons/PhysiBoSS/src/maboss_intracellular.cpp @@ -59,53 +59,126 @@ void MaBoSSIntracellular::initialize_intracellular_from_pugixml(pugi::xml_node& pugi::xml_node node_init_value = node_init_values.child( "initial_value" ); while( node_init_value ) { - std::string node_name = node_init_value.attribute( "node" ).value(); + pugi::xml_attribute node_name = node_init_value.attribute( "node" ); + pugi::xml_attribute node_intracellular_name = node_init_value.attribute( "intracellular_name" ); double node_value = PhysiCell::xml_get_my_double_value( node_init_value ); - initial_values[node_name] = node_value; - + if (node_intracellular_name) { + initial_values[node_intracellular_name.value()] = node_value; + } else if (node_name) { + std::cout << "The attribute node in mutation is deprecated and will be removed in future versions. Please switch to intracellular_name !" << std::endl; + initial_values[node_name.value()] = node_value; + } node_init_value = node_init_value.next_sibling( "initial_value" ); } } - - pugi::xml_node node_mutations = node.child( "mutations" ); - if( node_mutations ) - { - pugi::xml_node node_mutation = node_mutations.child( "mutation" ); - while( node_mutation ) + + maboss.init_maboss(bnd_filename, cfg_filename); + maboss.set_initial_values(initial_values); + + pugi::xml_node node_settings = node.child( "settings" ); + if ( node_settings ) { + + pugi::xml_node node_mutations = node_settings.child( "mutations" ); + if( node_mutations ) { - std::string node_name = node_mutation.attribute( "node" ).value(); - double node_value = PhysiCell::xml_get_my_double_value( node_mutation ); - - mutations[node_name] = node_value; - - node_mutation = node_mutation.next_sibling( "mutation" ); + pugi::xml_node node_mutation = node_mutations.child( "mutation" ); + while( node_mutation ) + { + pugi::xml_attribute node_name = node_mutation.attribute( "node" ); + pugi::xml_attribute node_intracellular_name = node_mutation.attribute( "intracellular_name" ); + + double node_value = PhysiCell::xml_get_my_double_value( node_mutation ); + + if (node_intracellular_name) { + mutations[node_intracellular_name.value()] = node_value; + } else if (node_name) { + std::cout << "The attribute node in mutation is deprecated and will be removed in future versions. Please switch to intracellular_name !" << std::endl; + mutations[node_name.value()] = node_value; + } + + node_mutation = node_mutation.next_sibling( "mutation" ); + } } - } - - pugi::xml_node node_parameters = node.child( "parameters" ); - if( node_parameters ) - { - pugi::xml_node node_parameter = node_parameters.child( "parameter" ); - while( node_parameter ) + + maboss.mutate(mutations); + + pugi::xml_node node_parameters = node_settings.child( "parameters" ); + if( node_parameters ) { - std::string param_name = node_parameter.attribute( "name" ).value(); - double param_value = PhysiCell::xml_get_my_double_value( node_parameter ); - - parameters[param_name] = param_value; - - node_parameter = node_parameter.next_sibling( "parameter" ); + pugi::xml_node node_parameter = node_parameters.child( "parameter" ); + while( node_parameter ) + { + pugi::xml_attribute param_name = node_parameter.attribute( "name" ); + pugi::xml_attribute param_intracellular_name = node_parameter.attribute( "intracellular_name" ); + double param_value = PhysiCell::xml_get_my_double_value( node_parameter ); + + if (param_intracellular_name) { + parameters[param_intracellular_name.value()] = param_value; + } else if (param_name) { + std::cout << "The attribute name in parameter is deprecated and will be removed in future versions. Please switch to intracellular_name !" << std::endl; + parameters[param_name.value()] = param_value; + } + node_parameter = node_parameter.next_sibling( "parameter" ); + } } - } + + maboss.set_parameters(parameters); + + pugi::xml_node node_timestep = node_settings.child( "time_step" ); + pugi::xml_node node_intracellular_dt = node_settings.child( "intracellular_dt" ); + if( node_intracellular_dt ) + { + time_step = PhysiCell::xml_get_my_double_value( node_intracellular_dt ); + maboss.set_update_time_step(time_step); + + } else if ( node_timestep ) + { + std::cout << "The setting timestep in parameter is deprecated and will be removed in future versions. Please switch to intracellular_name !" << std::endl; + time_step = PhysiCell::xml_get_my_double_value( node_timestep ); + maboss.set_update_time_step(time_step); + } + + pugi::xml_node node_discretetime = node_settings.child( "discrete_time" ); + pugi::xml_node node_timetick = node_settings.child( "time_tick" ); + + if( node_discretetime && node_timetick ) + { + discrete_time = PhysiCell::xml_get_my_bool_value( node_discretetime ); + time_tick = PhysiCell::xml_get_my_double_value( node_timetick ); + maboss.set_discrete_time(discrete_time, time_tick); + } + + pugi::xml_node node_scaling = node_settings.child( "scaling" ); + if( node_scaling ) + { + scaling = PhysiCell::xml_get_my_double_value( node_scaling ); + maboss.set_scaling(scaling); + } + + pugi::xml_node node_time_stochasticity = node_settings.child( "time_stochasticity" ); + if( node_time_stochasticity ) + { + time_stochasticity = PhysiCell::xml_get_my_double_value( node_time_stochasticity ); + maboss.set_time_stochasticity(time_stochasticity); + } + - maboss.init_maboss(bnd_filename, cfg_filename); - maboss.mutate(mutations); - maboss.set_initial_values(initial_values); - maboss.set_parameters(parameters); + } + // Old structure, with deprecation warnings + pugi::xml_node node_timestep = node.child( "time_step" ); - if( node_timestep ) + pugi::xml_node node_intracellular_dt = node.child( "intracellular_dt" ); + if( node_intracellular_dt ) { + std::cout << "The intracellular_dt needs to be defined inside the settings tag. Please update your settings as this will become incompatible in future versions" << std::endl; + time_step = PhysiCell::xml_get_my_double_value( node_intracellular_dt ); + maboss.set_update_time_step(time_step); + + } else if ( node_timestep ) + { + std::cout << "The setting timestep in parameter is deprecated and will be removed in future versions. Please update your settings using intracellular_dt !" << std::endl; time_step = PhysiCell::xml_get_my_double_value( node_timestep ); maboss.set_update_time_step(time_step); } @@ -115,6 +188,8 @@ void MaBoSSIntracellular::initialize_intracellular_from_pugixml(pugi::xml_node& if( node_discretetime && node_timetick ) { + std::cout << "The discrete_time needs to be defined inside the settings tag. Please update your settings as this will become incompatible in future versions" << std::endl; + std::cout << "The time_tick needs to be defined inside the settings tag. Please update your settings as this will become incompatible in future versions" << std::endl; discrete_time = PhysiCell::xml_get_my_bool_value( node_discretetime ); time_tick = PhysiCell::xml_get_my_double_value( node_timetick ); maboss.set_discrete_time(discrete_time, time_tick); @@ -123,16 +198,57 @@ void MaBoSSIntracellular::initialize_intracellular_from_pugixml(pugi::xml_node& pugi::xml_node node_scaling = node.child( "scaling" ); if( node_scaling ) { + std::cout << "The scaling needs to be defined inside the settings tag. Please update your settings as this will become incompatible in future versions" << std::endl; scaling = PhysiCell::xml_get_my_double_value( node_scaling ); maboss.set_scaling(scaling); } - + pugi::xml_node node_time_stochasticity = node.child( "time_stochasticity" ); if( node_time_stochasticity ) { + std::cout << "The time stochasticity needs to be defined inside the settings tag. Please update your settings as this will become incompatible in future versions" << std::endl; time_stochasticity = PhysiCell::xml_get_my_double_value( node_time_stochasticity ); maboss.set_time_stochasticity(time_stochasticity); } + + + pugi::xml_node node_mutations = node.child( "mutations" ); + if( node_mutations ) + { + std::cout << "The mutant declaration is now defined the the settings tag. Please update your settings as this will be incompatible in future versions !" << std::endl; + pugi::xml_node node_mutation = node_mutations.child( "mutation" ); + while( node_mutation ) + { + pugi::xml_attribute node_name = node_mutation.attribute( "node" ); + + double node_value = PhysiCell::xml_get_my_double_value( node_mutation ); + + + mutations[node_name.value()] = node_value; + + node_mutation = node_mutation.next_sibling( "mutation" ); + } + } + + maboss.mutate(mutations); + + pugi::xml_node node_parameters = node.child( "parameters" ); + if( node_parameters ) + { + std::cout << "The parameters declaration is now defined the the settings tag. Please update your settings as this will be incompatible in future versions !" << std::endl; + pugi::xml_node node_parameter = node.child( "parameter" ); + while( node_parameter ) + { + pugi::xml_attribute param_name = node_parameter.attribute( "name" ); + double param_value = PhysiCell::xml_get_my_double_value( node_parameter ); + + parameters[param_name.value()] = param_value; + node_parameter = node_parameter.next_sibling( "parameter" ); + } + } + + maboss.set_parameters(parameters); + } MaBoSSIntracellular* getMaBoSSModel(PhysiCell::Phenotype& phenotype) { From 0b14e6a168be2518340316b01c991f11eec644d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Mon, 6 Jun 2022 15:33:39 +0200 Subject: [PATCH 21/38] Added mappings parser --- addons/PhysiBoSS/src/maboss_intracellular.cpp | 59 +++++++++++++++++++ addons/PhysiBoSS/src/maboss_intracellular.h | 4 +- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/addons/PhysiBoSS/src/maboss_intracellular.cpp b/addons/PhysiBoSS/src/maboss_intracellular.cpp index 270c78e52..04fcb4db8 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.cpp +++ b/addons/PhysiBoSS/src/maboss_intracellular.cpp @@ -27,6 +27,8 @@ MaBoSSIntracellular::MaBoSSIntracellular(MaBoSSIntracellular* copy) initial_values = copy->initial_values; mutations = copy->mutations; parameters = copy->parameters; + listOfInputs = copy->listOfInputs; + listOfOutputs = copy->listOfOutputs; if (copy->maboss.has_init()) { maboss.init_maboss(copy->bnd_filename, copy->cfg_filename); @@ -249,6 +251,63 @@ void MaBoSSIntracellular::initialize_intracellular_from_pugixml(pugi::xml_node& maboss.set_parameters(parameters); + // Mappings + + pugi::xml_node node_mappings = node.child( "mapping" ); + if( node_mappings ) + { + + pugi::xml_node node_input = node_mappings.child("input"); + while (node_input) + { + pugi::xml_node settings = node_input.child("settings"); + + std::string intracellular_name = node_input.attribute( "intracellular_name" ).value(); + if (intracellular_name[0] == '$') { + + MaBoSSInput input = MaBoSSInput( + node_input.attribute( "physicell_name" ).value(), + intracellular_name, + (settings && settings.child( "scaling" ) ? PhysiCell::xml_get_my_double_value( settings.child( "scaling" )) : 1.0), + (settings && settings.child( "smoothing" ) ? PhysiCell::xml_get_my_int_value( settings.child( "smoothing" )) : 0) + ); + + listOfInputs.push_back(input); + } else { + + MaBoSSInput input = MaBoSSInput( + node_input.attribute( "physicell_name" ).value(), + intracellular_name, + PhysiCell::xml_get_my_string_value(settings.child("action")), + PhysiCell::xml_get_my_double_value(settings.child("threshold")), + (settings && settings.child( "inact_threshold" ) ? PhysiCell::xml_get_my_double_value( settings.child( "inact_threshold" )) : PhysiCell::xml_get_my_double_value(settings.child("threshold"))), + (settings && settings.child( "smoothing" ) ? PhysiCell::xml_get_my_int_value( settings.child( "smoothing" )) : 0) + ); + + listOfInputs.push_back(input); + + } + + node_input = node_input.next_sibling( "input" ); + } + + pugi::xml_node node_output = node_mappings.child("output"); + while (node_output) + { + pugi::xml_node settings = node_output.child("settings"); + + listOfOutputs.push_back(MaBoSSOutput( + node_output.attribute( "physicell_name" ).value(), + node_output.attribute( "intracellular_name" ).value(), + PhysiCell::xml_get_my_string_value(settings.child("action")), + PhysiCell::xml_get_my_double_value(settings.child("value")), + (settings && settings.child( "base_value" ) ? PhysiCell::xml_get_my_double_value( settings.child( "base_value" )) : PhysiCell::xml_get_my_double_value(settings.child("value"))), + (settings && settings.child( "smoothing" ) ? PhysiCell::xml_get_my_int_value( settings.child( "smoothing" )) : 0) + )); + + node_output = node_output.next_sibling( "output" ); + } + } } MaBoSSIntracellular* getMaBoSSModel(PhysiCell::Phenotype& phenotype) { diff --git a/addons/PhysiBoSS/src/maboss_intracellular.h b/addons/PhysiBoSS/src/maboss_intracellular.h index 82388bdf5..14e6aa8e2 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.h +++ b/addons/PhysiBoSS/src/maboss_intracellular.h @@ -30,7 +30,9 @@ class MaBoSSIntracellular : public PhysiCell::Intracellular { std::map initial_values; std::map mutations; std::map parameters; - + + std::vector listOfInputs; + std::vector listOfOutputs; MaBoSSNetwork maboss; double next_physiboss_run = 0; From a6b39b58ee5d31729bb691c409cd4f8b3e6f437a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Mon, 6 Jun 2022 15:34:02 +0200 Subject: [PATCH 22/38] Added mappings display --- addons/PhysiBoSS/src/maboss_intracellular.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/addons/PhysiBoSS/src/maboss_intracellular.cpp b/addons/PhysiBoSS/src/maboss_intracellular.cpp index 04fcb4db8..5ebba4487 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.cpp +++ b/addons/PhysiBoSS/src/maboss_intracellular.cpp @@ -333,8 +333,21 @@ void MaBoSSIntracellular::display(std::ostream& os) os << "\t\t\t" << mutation.first << " = " << mutation.second << std::endl; os << "\t\t scaling = " << scaling << std::endl - << "\t\t time_stochasticity = " << time_stochasticity << std::endl - << std::endl; + << "\t\t time_stochasticity = " << time_stochasticity << std::endl; + + os << "\t\t " << listOfInputs.size() << " input mapping defined" << std::endl; + for (auto& input : listOfInputs) + os << "\t\t\t" << input.physicell_name << " = " << input.intracellular_name + << "(" << input.threshold << ", " << input.inact_threshold << ", " << input.smoothing << ")" + << std::endl; + + os << "\t\t " << listOfOutputs.size() << " output mapping defined" << std::endl; + for (auto& output : listOfOutputs) + os << "\t\t\t" << output.physicell_name << " = " << output.intracellular_name + << "(" << output.value << ", " << output.base_value << ", " << output.smoothing << ")" + << std::endl; + + std::cout << std::endl; } void MaBoSSIntracellular::save(std::string filename, std::vector& cells) From 829fabf3a082f32ea8c2abe44e6e90856d8bc0fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Mon, 6 Jun 2022 15:34:32 +0200 Subject: [PATCH 23/38] Added update implementation for physiboss mappings --- addons/PhysiBoSS/src/utils.h | 63 ++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/addons/PhysiBoSS/src/utils.h b/addons/PhysiBoSS/src/utils.h index a0766c566..69c3d6089 100644 --- a/addons/PhysiBoSS/src/utils.h +++ b/addons/PhysiBoSS/src/utils.h @@ -30,6 +30,46 @@ class MaBoSSInput bool isNode() { return type == NODE; } bool isParameter() { return type == PARAMETER; } + void update_value(double value) { + smoothed_value = (smoothed_value * smoothing + value)/(smoothing + 1); + } + + bool updateNode(bool state, double value) + { + double true_value; + if (smoothing == 0) { + true_value = value; + } else { + update_value(value); + true_value = smoothed_value; + } + + if (state) { + if (action == "inhibition") { + return true_value <= inact_threshold; // When the node is active, and this is an activation, the node stays true if the value is below the inact threshold + + } else { + return true_value >= inact_threshold; // When the node is active, the node stays true if the value is above the inact threshold + } + + } else { + if (action == "inhibition") { + return true_value < threshold; + + } else { + return true_value > threshold; + } + } + } + + double updateParameter(double value) { + if (smoothing == 0) { + return value; + } else { + update_value(value); + return smoothed_value; + } + } }; class MaBoSSOutput @@ -47,5 +87,28 @@ class MaBoSSOutput smoothed_value = base_value; } + void update_value(bool test) { + smoothed_value = (smoothed_value*smoothing + (test?1.0:0.0)) / (smoothing + 1.0); + } + + double update(bool test) + { + double true_value; + if (smoothing == 0) { + true_value = value; + } else { + update_value((action == "activation" && test) || (action == "inhibition" and !test)); + true_value = smoothed_value; + } + + if (action == "activation" && test) { + double hill = PhysiCell::Hill_response_function( true_value*2 , 1 , 10 ); + return (value-base_value)*hill+base_value; + } else if (action == "inhibition" && !test) { + double hill = PhysiCell::Hill_response_function( true_value*2 , 1 , 10 ); + return value-(value-base_value)*hill; + } + return base_value; + } }; #endif \ No newline at end of file From 131f8edebc87115f0d8871783ce46a7658cc5c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Mon, 6 Jun 2022 15:35:15 +0200 Subject: [PATCH 24/38] Connected physiboss mapping update to physiboss intracellular update --- addons/PhysiBoSS/src/maboss_intracellular.cpp | 43 +++++++++++++++++++ addons/PhysiBoSS/src/maboss_intracellular.h | 7 +++ 2 files changed, 50 insertions(+) diff --git a/addons/PhysiBoSS/src/maboss_intracellular.cpp b/addons/PhysiBoSS/src/maboss_intracellular.cpp index 5ebba4487..9dd89a561 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.cpp +++ b/addons/PhysiBoSS/src/maboss_intracellular.cpp @@ -27,6 +27,8 @@ MaBoSSIntracellular::MaBoSSIntracellular(MaBoSSIntracellular* copy) initial_values = copy->initial_values; mutations = copy->mutations; parameters = copy->parameters; + indicesOfInputs = copy->indicesOfInputs; + indicesOfOutputs = copy->indicesOfOutputs; listOfInputs = copy->listOfInputs; listOfOutputs = copy->listOfOutputs; @@ -40,11 +42,52 @@ MaBoSSIntracellular::MaBoSSIntracellular(MaBoSSIntracellular* copy) maboss.set_scaling(copy->scaling); maboss.set_time_stochasticity(copy->time_stochasticity); maboss.restart_node_values(); + indicesOfInputs.clear(); + for (MaBoSSInput& input: listOfInputs) { + indicesOfInputs.push_back(PhysiCell::find_signal_index(input.physicell_name)); + } + indicesOfOutputs.clear(); + for (MaBoSSOutput& output: listOfOutputs) { + indicesOfOutputs.push_back(PhysiCell::find_behavior_index(output.physicell_name)); + } //maboss.set_state(copy->maboss.get_maboss_state()); //std::cout << get_state(); } } +void MaBoSSIntracellular::update_inputs(PhysiCell::Cell* cell, PhysiCell::Phenotype& phenotype, double dt) +{ + std::vector signals = PhysiCell::get_selected_signals(cell, indicesOfInputs); + + for (unsigned int i=0; i < listOfInputs.size(); i++) + { + MaBoSSInput& input = listOfInputs[i]; + if (input.isNode()) { + maboss.set_node_value( + input.intracellular_name, + input.updateNode(maboss.get_node_value(input.intracellular_name), signals[i]) + ); + } else if (input.isParameter()) { + maboss.set_parameter_value( + input.intracellular_parameter, + input.updateParameter(signals[i]) + ); + } + } +} + +void MaBoSSIntracellular::update_outputs(PhysiCell::Cell* cell, PhysiCell::Phenotype& phenotype, double dt) +{ + std::vector signals = std::vector(listOfOutputs.size(), 0.0); + for (unsigned int i=0; i < listOfOutputs.size(); i++) + { + MaBoSSOutput& output = listOfOutputs[i]; + signals[i] = output.update(maboss.get_node_value(output.intracellular_name)); + } + PhysiCell::set_selected_behaviors(cell, indicesOfOutputs, signals); +} + + void MaBoSSIntracellular::initialize_intracellular_from_pugixml(pugi::xml_node& node) { pugi::xml_node node_bnd = node.child( "bnd_filename" ); diff --git a/addons/PhysiBoSS/src/maboss_intracellular.h b/addons/PhysiBoSS/src/maboss_intracellular.h index 14e6aa8e2..eab16b43a 100644 --- a/addons/PhysiBoSS/src/maboss_intracellular.h +++ b/addons/PhysiBoSS/src/maboss_intracellular.h @@ -32,7 +32,9 @@ class MaBoSSIntracellular : public PhysiCell::Intracellular { std::map parameters; std::vector listOfInputs; + std::vector indicesOfInputs; std::vector listOfOutputs; + std::vector indicesOfOutputs; MaBoSSNetwork maboss; double next_physiboss_run = 0; @@ -62,7 +64,9 @@ class MaBoSSIntracellular : public PhysiCell::Intracellular { } void update(PhysiCell::Cell * cell, PhysiCell::Phenotype& phenotype, double dt) { + this->update_inputs(cell, phenotype, dt); this->maboss.run_simulation(); + this->update_outputs(cell, phenotype, dt); this->next_physiboss_run += this->maboss.get_time_to_update(); } @@ -70,6 +74,9 @@ class MaBoSSIntracellular : public PhysiCell::Intracellular { return PhysiCell::PhysiCell_globals.current_time >= this->next_physiboss_run; } + void update_inputs(PhysiCell::Cell* cell, PhysiCell::Phenotype& phenotype, double dt); + void update_outputs(PhysiCell::Cell * cell, PhysiCell::Phenotype& phenotype, double dt); + bool has_variable(std::string name) { return this->maboss.has_node(name); } From 8714d1dc1ab3a30cec55b0f1602601ba70f88927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Mon, 6 Jun 2022 15:36:08 +0200 Subject: [PATCH 25/38] Now using automatic mapping in physiboss example --- .../config/PhysiCell_settings.xml | 57 ++++++++++++++----- .../physiboss_cell_lines/config/model.cfg | 1 + .../custom_modules/custom.cpp | 13 ++++- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/sample_projects_intracellular/boolean/physiboss_cell_lines/config/PhysiCell_settings.xml b/sample_projects_intracellular/boolean/physiboss_cell_lines/config/PhysiCell_settings.xml index ab9934057..76451efcb 100644 --- a/sample_projects_intracellular/boolean/physiboss_cell_lines/config/PhysiCell_settings.xml +++ b/sample_projects_intracellular/boolean/physiboss_cell_lines/config/PhysiCell_settings.xml @@ -125,7 +125,7 @@ .1 38.0 - 38.0 + 38.0 @@ -179,11 +179,30 @@ ./config/model_0.bnd ./config/model.cfg - 1 + + 1 + - 1 - 0 - + 1 + 0 + + + + + inhibition + 10 + 10 + + + + + activation + 5 + 0 + 5 + + + @@ -199,9 +218,11 @@ - - 0.0 - + + + 0.0 + + @@ -209,9 +230,11 @@ - - 0.2 - + + + 0.2 + + @@ -219,7 +242,9 @@ - 0.25 + + 0.25 + @@ -227,9 +252,11 @@ - - 0.0 - + + + 0.0 + + diff --git a/sample_projects_intracellular/boolean/physiboss_cell_lines/config/model.cfg b/sample_projects_intracellular/boolean/physiboss_cell_lines/config/model.cfg index 5f6963118..c71e51467 100644 --- a/sample_projects_intracellular/boolean/physiboss_cell_lines/config/model.cfg +++ b/sample_projects_intracellular/boolean/physiboss_cell_lines/config/model.cfg @@ -1,4 +1,5 @@ $time_scale = 0.05; +$oxygen_concentration = 0.0; discrete_time = 0; use_physrandgen = FALSE; diff --git a/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp b/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp index c7cb3fc6b..4b3435684 100644 --- a/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp +++ b/sample_projects_intracellular/boolean/physiboss_cell_lines/custom_modules/custom.cpp @@ -115,9 +115,20 @@ void create_cell_types( void ) */ build_cell_definitions_maps(); + + /* + This intializes cell signal and response dictionaries + */ + + setup_signal_behavior_dictionaries(); + + /* + This summarizes the setup. + */ display_cell_definitions( std::cout ); - + + return; } From 26168e8b84d4217b6c66bcfacfcd9823712c7da0 Mon Sep 17 00:00:00 2001 From: Randy Heiland Date: Mon, 6 Jun 2022 11:20:02 -0400 Subject: [PATCH 26/38] macos arm64 --- beta/setup_libroadrunner.py | 289 +++++++++++++++++++----------------- 1 file changed, 156 insertions(+), 133 deletions(-) diff --git a/beta/setup_libroadrunner.py b/beta/setup_libroadrunner.py index 4aa128a5e..936428778 100644 --- a/beta/setup_libroadrunner.py +++ b/beta/setup_libroadrunner.py @@ -1,133 +1,156 @@ -# This script attempts to download the libRoadrunner (binary) libraries and -# headers for your particular operating system. It installs them in -# the appropriate /addons directory which the Makefile can find. -# -# Author: Randy Heiland - -import platform -import urllib.request -import os -import sys -import tarfile -import zipfile - -if os.path.exists(os.path.join(os.path.dirname(os.path.dirname(__file__)), "addons", "libRoadrunner", "roadrunner")): - print('\nlibroadrunner already installed.\n') - -else: - print('\nThis model requires the libRoadrunner libraries which will now be downloaded.') - os_type = platform.system() - print('(for your ',os_type, ' operating system)') - - # Assume Windows - rr_file = "" - url = "" - - if os_type.lower() == 'darwin': - rr_file = "roadrunner-osx-10.9-cp36m.tar.gz" - url = "https://sourceforge.net/projects/libroadrunner/files/libroadrunner-1.4.18/" + rr_file + "/download" - elif os_type.lower().startswith("win"): - rr_file = "roadrunner-win64-vs14-cp35m.zip" - url = "https://sourceforge.net/projects/libroadrunner/files/libroadrunner-1.4.18/" + rr_file + "/download" - elif os_type.lower().startswith("linux"): - rr_file = "cpplibroadrunner-1.3.0-linux_x86_64.tar.gz" - url = "https://sourceforge.net/projects/libroadrunner/files/libroadrunner-1.3/" + rr_file + "/download" - else: - print("Your operating system seems to be unsupported. Please submit a ticket at https://sourceforge.net/p/physicell/tickets/ ") - sys.exit(1) - - fname = url.split('/')[-2] - - # home = os.path.expanduser("~") - print('libRoadRunner will now be installed into this location:') - # dir_name = os.path.join(home, 'libroadrunner') - dir_name = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'addons', 'libRoadrunner') - print(dir_name + '\n') - # print(' - Press ENTER to confirm the location') - # print(' - Press CTL-C to abort the installation') - # print(' - Or specify a different location below\n') - prompt_str = '[' + dir_name + '] >>> ' - try: - # response = input(prompt_str) - # if (response == ""): - if (True): - # print('got Enter') - if not os.path.exists(dir_name): - try: - os.makedirs(dir_name) - except: - print('Error trying to create directory: ',dir_name) - exit(1) - # else: - # print(type(response)) - # dir_name = os.path.expanduser(response) - # if not os.path.exists(dir_name): - # try: - # os.makedirs(dir_name) - # except: - # print('Error trying to create directory: ',dir_name) - # exit(1) - except: - print(' installation canceled\n') - exit(1) - - print('Beginning download of libroadrunner into ' + dir_name + ' ...') - print(url) - - my_file = os.path.join(dir_name, fname) - print('my_file = ',my_file) - - if os_type.lower().startswith("win"): - rrlib_dir = my_file[:-4] - else: # darwin or linux - rrlib_dir = my_file[:-7] - print('rrlib_dir = ',rrlib_dir) - - def download_cb(blocknum, blocksize, totalsize): - readsofar = blocknum * blocksize - if totalsize > 0: - percent = readsofar * 1e2 / totalsize - s = "\r%5.1f%% %*d / %d" % ( - percent, len(str(totalsize)), readsofar, totalsize) - sys.stderr.write(s) - if readsofar >= totalsize: # near the end - sys.stderr.write("\n") - else: # total size is unknown - sys.stderr.write("read %d\n" % (readsofar,)) - - urllib.request.urlretrieve(url, my_file, download_cb) - - new_dir_name = "roadrunner" - os.chdir(dir_name) - print('installing (uncompressing) the file...') - if os_type.lower().startswith("win"): - try: - with zipfile.ZipFile(rr_file) as zf: - zf.extractall('.') - os.rename("roadrunner-win64-vs14-cp35m", new_dir_name) - except: - print('error unzipping the file') - exit(1) - else: # Darwin or Linux - try: - tar = tarfile.open(rr_file) - tar.extractall() - tar.close() - if 'darwin' in os_type.lower(): - os.rename("roadrunner-osx-10.9-cp36m", new_dir_name) - else: - os.rename("libroadrunner", new_dir_name) - except: - print('error untarring the file') - exit(1) - - print('Done.\n') - - # # LIBRR_DIR := /Users/heiland/libroadrunner/roadrunner-osx-10.9-cp36m - # print("Replace the following variables in your PhysiCell Makefile with these:\n") - # #print("LIBRR_DIR := /Users/heiland/libroadrunner/roadrunner-osx-10.9-cp36m") - # print("LIBRR_DIR := " + rrlib_dir) - # if os_type == 'Windows': - # print("LIBRR_LIBS := " + rrlib_dir + "/bin\n") - # else: - # print("LIBRR_LIBS := " + rrlib_dir + "/lib\n") +# This script attempts to download the libRoadrunner (binary) libraries and +# headers for your particular operating system. It installs them in +# the appropriate /addons directory which the Makefile can find. +# +# Author: Randy Heiland + +import platform +import urllib.request +import os +import sys +import tarfile +import zipfile + +if os.path.exists(os.path.join(os.path.dirname(os.path.dirname(__file__)), "addons", "libRoadrunner", "roadrunner")): + print('\nlibroadrunner already installed.\n') + +else: + print('\nThis model requires the libRoadrunner libraries which will now be downloaded.') + os_type = platform.system() + print('(for your ',os_type, ' operating system)') + + # Assume Windows + rr_file = "" + url = "" + + if os_type.lower() == 'darwin': + if "ARM64" in platform.uname().version: + # pass + print('... for the arm64 processor.') + # url = "https://github.com/PhysiCell-Tools/intracellular_libs/raw/main/ode/libs/macos12_arm64/libroadrunner_c_api.dylib" + rr_file = "roadrunner_macos_arm64.tar.gz" + url = "https://github.com/PhysiCell-Tools/intracellular_libs/raw/main/ode/roadrunner_macos_arm64.tar.gz" + else: + rr_file = "roadrunner-osx-10.9-cp36m.tar.gz" + url = "https://sourceforge.net/projects/libroadrunner/files/libroadrunner-1.4.18/" + rr_file + "/download" + url = "https://raw.github.com/PhysiCell-Tools/intracellular_libs/blob/main/ode/libs/macos/roadrunner-osx-10.9-cp36m.tar.gz" + + rr_file = "roadrunner-osx-10.9-cp36m.tar.gz" + url = "https://github.com/PhysiCell-Tools/intracellular_libs/raw/main/ode/libs/macos/roadrunner-osx-10.9-cp36m.tar.gz" + elif os_type.lower().startswith("win"): + rr_file = "roadrunner-win64-vs14-cp35m.zip" + url = "https://sourceforge.net/projects/libroadrunner/files/libroadrunner-1.4.18/" + rr_file + "/download" + elif os_type.lower().startswith("linux"): + rr_file = "cpplibroadrunner-1.3.0-linux_x86_64.tar.gz" + url = "https://sourceforge.net/projects/libroadrunner/files/libroadrunner-1.3/" + rr_file + "/download" + else: + print("Your operating system seems to be unsupported. Please submit a ticket at https://sourceforge.net/p/physicell/tickets/ ") + sys.exit(1) + + # fname = url.split('/')[-2] + fname = url.split('/')[-1] + print("fname = ",fname) + + # home = os.path.expanduser("~") + print('libRoadRunner will now be installed into this location:') + # dir_name = os.path.join(home, 'libroadrunner') + dir_name = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'addons', 'libRoadrunner') + print(dir_name + '\n') + # print(' - Press ENTER to confirm the location') + # print(' - Press CTL-C to abort the installation') + # print(' - Or specify a different location below\n') + prompt_str = '[' + dir_name + '] >>> ' + try: + # response = input(prompt_str) + # if (response == ""): + if (True): + # print('got Enter') + if not os.path.exists(dir_name): + try: + os.makedirs(dir_name) + except: + print('Error trying to create directory: ',dir_name) + exit(1) + # else: + # print(type(response)) + # dir_name = os.path.expanduser(response) + # if not os.path.exists(dir_name): + # try: + # os.makedirs(dir_name) + # except: + # print('Error trying to create directory: ',dir_name) + # exit(1) + except: + print(' installation canceled\n') + exit(1) + + print('Beginning download of libroadrunner into ' + dir_name + ' ...') + print(url) + + my_file = os.path.join(dir_name, fname) + print('my_file = ',my_file) + + if os_type.lower().startswith("win"): + rrlib_dir = my_file[:-4] + else: # darwin or linux + rrlib_dir = my_file[:-7] + rrlib_dir = my_file[:-6] + print('rrlib_dir = ',rrlib_dir) + + def download_cb(blocknum, blocksize, totalsize): + readsofar = blocknum * blocksize + if totalsize > 0: + percent = readsofar * 1e2 / totalsize + s = "\r%5.1f%% %*d / %d" % ( + percent, len(str(totalsize)), readsofar, totalsize) + sys.stderr.write(s) + if readsofar >= totalsize: # near the end + sys.stderr.write("\n") + else: # total size is unknown + sys.stderr.write("read %d\n" % (readsofar,)) + + urllib.request.urlretrieve(url, my_file, download_cb) + + # sys.exit(-1) + + new_dir_name = "roadrunner" + os.chdir(dir_name) + print('installing (uncompressing) the file...') + if os_type.lower().startswith("win"): # on Windows + try: + with zipfile.ZipFile(rr_file) as zf: + zf.extractall('.') + os.rename("roadrunner-win64-vs14-cp35m", new_dir_name) + except: + print('error unzipping the file') + exit(1) + else: # Darwin or Linux + try: + print("-- attempt to extract from the tar file...", rr_file) + tar = tarfile.open(rr_file) + tar.extractall() + tar.close() + if 'darwin' in os_type.lower(): + if "ARM64" in platform.uname().version: # on the new Mac M1, arm64 processor + # if False: + # print("--- TODO: rename ARM64 lib dir") + # sys.exit(-1) + pass # it already uncompresses and creates the 'roadrunner' dir + else: + os.rename("roadrunner-osx-10.9-cp36m", new_dir_name) + else: + os.rename("libroadrunner", new_dir_name) + except: + print('error untarring the file') + exit(1) + + print('Done.\n') + + # # LIBRR_DIR := /Users/heiland/libroadrunner/roadrunner-osx-10.9-cp36m + # print("Replace the following variables in your PhysiCell Makefile with these:\n") + # #print("LIBRR_DIR := /Users/heiland/libroadrunner/roadrunner-osx-10.9-cp36m") + # print("LIBRR_DIR := " + rrlib_dir) + # if os_type == 'Windows': + # print("LIBRR_LIBS := " + rrlib_dir + "/bin\n") + # else: + # print("LIBRR_LIBS := " + rrlib_dir + "/lib\n") From 32a736169195160c8f31da09112fcdbcc2b29cba Mon Sep 17 00:00:00 2001 From: Randy Heiland Date: Mon, 6 Jun 2022 17:04:29 -0400 Subject: [PATCH 27/38] macos arm64 --- beta/setup_libroadrunner.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/beta/setup_libroadrunner.py b/beta/setup_libroadrunner.py index 936428778..c9efca16b 100644 --- a/beta/setup_libroadrunner.py +++ b/beta/setup_libroadrunner.py @@ -11,6 +11,23 @@ import tarfile import zipfile +def reminder_dynamic_link_path_macos(): + print("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n") + print("* NOTE: if you have not yet done this, you need to specify where the shared libs can be found, e.g., via bash shell:") + print('export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:./addons/libRoadrunner/roadrunner/lib') + + print("\n* To make this permanent, add this line to the bottom of the respective shell startup file, e.g., .bashrc, .bash_profile, or .zshenv in your home directory.") + print("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n") + +def reminder_dynamic_link_path_linux(): + print("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n") + print("* NOTE: if you have not yet done this, you need to specify where the shared libs can be found, e.g., via bash shell:") + print('export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./addons/libRoadrunner/roadrunner/lib') + + print("\n* To make this permanent, add this line to the bottom of the respective shell startup file, e.g., .bashrc, .bash_profile, or .zshenv in your home directory.") + print("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n") + +# print("--------- print reminder!!!!!!!!!!!!!!\n\n") if os.path.exists(os.path.join(os.path.dirname(os.path.dirname(__file__)), "addons", "libRoadrunner", "roadrunner")): print('\nlibroadrunner already installed.\n') @@ -24,9 +41,11 @@ url = "" if os_type.lower() == 'darwin': + reminder_dynamic_link_path_macos() if "ARM64" in platform.uname().version: # pass - print('... for the arm64 processor.') + # reminder_dynamic_link_path() + # print('... for the arm64 processor.') # url = "https://github.com/PhysiCell-Tools/intracellular_libs/raw/main/ode/libs/macos12_arm64/libroadrunner_c_api.dylib" rr_file = "roadrunner_macos_arm64.tar.gz" url = "https://github.com/PhysiCell-Tools/intracellular_libs/raw/main/ode/roadrunner_macos_arm64.tar.gz" @@ -41,12 +60,15 @@ rr_file = "roadrunner-win64-vs14-cp35m.zip" url = "https://sourceforge.net/projects/libroadrunner/files/libroadrunner-1.4.18/" + rr_file + "/download" elif os_type.lower().startswith("linux"): + reminder_dynamic_link_path_linux() rr_file = "cpplibroadrunner-1.3.0-linux_x86_64.tar.gz" url = "https://sourceforge.net/projects/libroadrunner/files/libroadrunner-1.3/" + rr_file + "/download" else: print("Your operating system seems to be unsupported. Please submit a ticket at https://sourceforge.net/p/physicell/tickets/ ") sys.exit(1) + # print("-------- past if block...") + # reminder_dynamic_link_path() # fname = url.split('/')[-2] fname = url.split('/')[-1] print("fname = ",fname) From 0c67e0e8c9e7dd0cfc6dc024eb1753be3e9773a8 Mon Sep 17 00:00:00 2001 From: Randy Heiland Date: Tue, 7 Jun 2022 17:57:00 -0400 Subject: [PATCH 28/38] provide macos arm64 --- beta/setup_libmaboss.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/beta/setup_libmaboss.py b/beta/setup_libmaboss.py index 9937e4e8c..faf08b68c 100644 --- a/beta/setup_libmaboss.py +++ b/beta/setup_libmaboss.py @@ -1,9 +1,8 @@ -# This script attempts to download the libRoadrunner (binary) libraries and -# headers for your particular operating system. It puts them in a directory -# of your choosing (default = your home dir) and sets an environment variable -# to that location which can then be used by a PhysiCell Makefile. +# This script attempts to download the MaBoSS (binary) library(s) and +# headers for your particular operating system. It installs them in a standard +# location (relative to a PhysiCell installation) which will be used by a PhysiCell Makefile. # -# Author: Randy Heiland +# Authors: Randy Heiland, Vincent Noel import platform import urllib.request @@ -24,16 +23,23 @@ url = "" if os_type.lower() == 'darwin': - mb_file = "libMaBoSS-osx64.tar.gz" + if "ARM64" in platform.uname().version: + mb_file = "libMaBoSS-macos-arm64.tar.gz" + url = "https://github.com/PhysiCell-Tools/intracellular_libs/raw/main/boolean/libMaBoSS-macos-arm64.tar.gz" + else: + mb_file = "libMaBoSS-osx64.tar.gz" + url = "https://github.com/sysbio-curie/MaBoSS-env-2.0/releases/download/v2.4.1/" + mb_file elif os_type.lower().startswith("win") or os_type.lower().startswith("msys_nt") or os_type.lower().startswith("mingw64_nt"): mb_file = "libMaBoSS-win64.tar.gz" + url = "https://github.com/sysbio-curie/MaBoSS-env-2.0/releases/download/v2.4.1/" + mb_file elif os_type.lower().startswith("linux"): mb_file = "libMaBoSS-linux64.tar.gz" + url = "https://github.com/sysbio-curie/MaBoSS-env-2.0/releases/download/v2.4.1/" + mb_file else: print("Your operating system seems to be unsupported. Please submit a ticket at https://sourceforge.net/p/physicell/tickets/ ") sys.exit(1) - url = "https://github.com/sysbio-curie/MaBoSS-env-2.0/releases/download/v2.4.1/" + mb_file + # url = "https://github.com/sysbio-curie/MaBoSS-env-2.0/releases/download/v2.4.1/" + mb_file fname = mb_file @@ -89,12 +95,3 @@ def download_cb(blocknum, blocksize, totalsize): exit(1) print('Done.\n') - - # # LIBRR_DIR := /Users/heiland/libroadrunner/roadrunner-osx-10.9-cp36m - # print("Replace the following variables in your PhysiCell Makefile with these:\n") - # #print("LIBRR_DIR := /Users/heiland/libroadrunner/roadrunner-osx-10.9-cp36m") - # print("LIBRR_DIR := " + rrlib_dir) - # if os_type == 'Windows': - # print("LIBRR_LIBS := " + rrlib_dir + "/bin\n") - # else: - # print("LIBRR_LIBS := " + rrlib_dir + "/lib\n") From b9c0594fcb1180d4df50b67ef8296f2bb17e4027 Mon Sep 17 00:00:00 2001 From: Randy Heiland Date: Tue, 7 Jun 2022 19:16:30 -0400 Subject: [PATCH 29/38] use sf for osx libRR --- beta/setup_libroadrunner.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/beta/setup_libroadrunner.py b/beta/setup_libroadrunner.py index c9efca16b..e91bb3cd2 100644 --- a/beta/setup_libroadrunner.py +++ b/beta/setup_libroadrunner.py @@ -52,10 +52,10 @@ def reminder_dynamic_link_path_linux(): else: rr_file = "roadrunner-osx-10.9-cp36m.tar.gz" url = "https://sourceforge.net/projects/libroadrunner/files/libroadrunner-1.4.18/" + rr_file + "/download" - url = "https://raw.github.com/PhysiCell-Tools/intracellular_libs/blob/main/ode/libs/macos/roadrunner-osx-10.9-cp36m.tar.gz" + # url = "https://raw.github.com/PhysiCell-Tools/intracellular_libs/blob/main/ode/libs/macos/roadrunner-osx-10.9-cp36m.tar.gz" - rr_file = "roadrunner-osx-10.9-cp36m.tar.gz" - url = "https://github.com/PhysiCell-Tools/intracellular_libs/raw/main/ode/libs/macos/roadrunner-osx-10.9-cp36m.tar.gz" + # rr_file = "roadrunner-osx-10.9-cp36m.tar.gz" + # url = "https://github.com/PhysiCell-Tools/intracellular_libs/raw/main/ode/libs/macos/roadrunner-osx-10.9-cp36m.tar.gz" elif os_type.lower().startswith("win"): rr_file = "roadrunner-win64-vs14-cp35m.zip" url = "https://sourceforge.net/projects/libroadrunner/files/libroadrunner-1.4.18/" + rr_file + "/download" From 59f545f62ec68cc4917d1961f2b34f7ffe20447d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Wed, 8 Jun 2022 17:08:07 +0200 Subject: [PATCH 30/38] Removing mfpmath=both from PhysiBoSS' example Makefile when compiling with macos arm64 --- .../boolean/physiboss_cell_lines/Makefile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sample_projects_intracellular/boolean/physiboss_cell_lines/Makefile b/sample_projects_intracellular/boolean/physiboss_cell_lines/Makefile index 735ddcaaa..100dcb9e9 100644 --- a/sample_projects_intracellular/boolean/physiboss_cell_lines/Makefile +++ b/sample_projects_intracellular/boolean/physiboss_cell_lines/Makefile @@ -56,6 +56,18 @@ ARCH := native # best auto-tuning # 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 \ From 274e7174c667507438f7433dc8287812ec68a18f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Wed, 8 Jun 2022 17:08:33 +0200 Subject: [PATCH 31/38] Using proper PHYSICELL_CPP when recompiling MaBoSS --- .../boolean/physiboss_cell_lines/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample_projects_intracellular/boolean/physiboss_cell_lines/Makefile b/sample_projects_intracellular/boolean/physiboss_cell_lines/Makefile index 100dcb9e9..790163a30 100644 --- a/sample_projects_intracellular/boolean/physiboss_cell_lines/Makefile +++ b/sample_projects_intracellular/boolean/physiboss_cell_lines/Makefile @@ -195,7 +195,7 @@ PhysiCell_settings.o: ./modules/PhysiCell_settings.cpp # user-defined PhysiCell modules Compile_MaBoSS: MaBoSS - cd ./addons/PhysiBoSS/MaBoSS-env-2.0/engine/src;make install_alib;make clean; cd ../../../../.. + cd ./addons/PhysiBoSS/MaBoSS-env-2.0/engine/src;make CXX=$(CC) install_alib;make clean; cd ../../../../.. MaBoSS: ifeq ($(OS), Windows_NT) From 546b5a6af2492a71c457ac8aa54eefc638705ce0 Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Sun, 26 Jun 2022 17:15:05 -0400 Subject: [PATCH 32/38] 1.10.3 updates custom data now accessible as signals and behaviors custom data can be designated as conserved quantities that are divided among daughter cells at division. --- CITATION.txt | 4 +- README.md | 62 ++++++++++++----- VERSION.txt | 2 +- changes.md | 33 +++++++-- core/PhysiCell.h | 2 +- core/PhysiCell_cell.cpp | 29 +++++++- core/PhysiCell_custom.cpp | 2 + core/PhysiCell_custom.h | 2 + core/PhysiCell_phenotype.cpp | 67 +++++++++++++++++++ core/PhysiCell_phenotype.h | 28 ++++++++ core/PhysiCell_signal_behavior.cpp | 104 ++++++++++++++++++++++++++++- 11 files changed, 304 insertions(+), 31 deletions(-) diff --git a/CITATION.txt b/CITATION.txt index fcc60673e..7d91331c6 100644 --- a/CITATION.txt +++ b/CITATION.txt @@ -1,7 +1,7 @@ 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 1.10.2) [1]. +We implemented and solved the model using PhysiCell (Version 1.10.3) [1]. [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, PhysiCell: an Open Source Physics-Based Cell Simulator for Multicellu- @@ -11,7 +11,7 @@ We implemented and solved the model using PhysiCell (Version 1.10.2) [1]. Because PhysiCell extensively uses BioFVM, we suggest you also cite BioFVM as below: -We implemented and solved the model using PhysiCell (Version 1.10.2) [1], +We implemented and solved the model using PhysiCell (Version 1.10.3) [1], with BioFVM [2] to solve the transport equations. [1] A Ghaffarizadeh, R Heiland, SH Friedman, SM Mumenthaler, and P Macklin, diff --git a/README.md b/README.md index dbf72a2b5..57f20838c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # PhysiCell: an Open Source Physics-Based Cell Simulator for 3-D Multicellular Systems -**Version:** 1.10.2 +**Version:** 1.10.3 -**Release date:** 24 May 2022 +**Release date:** 25 June 2022 ## Overview: PhysiCell is a flexible open source framework for building agent-based multicellular models in 3-D tissue environments. @@ -16,15 +16,15 @@ Visit http://MathCancer.org/blog for the latest tutorials and help. ### Key makefile rules: -**make** : compiles the current project. If no +**`make`** : compiles the current project. If no project has been defined, it first populates the cancer heterogeneity 2D sample project and compiles it -**make \[project-name\]**: populates the indicated sample project. +**`make project-name`**: populates the indicated sample project. Use "make" to compile it. - * **\[project-name\]** choices: + * **`project-name`** choices: * template * biorobots-sample * cancer-biorobots-sample @@ -39,21 +39,22 @@ Visit http://MathCancer.org/blog for the latest tutorials and help. * cancer-metabolism-sample * interaction-sample -**make list-projects** : list all available sample projects +**`make list-projects`** : list all available sample projects -**make clean** : removes all .o files and the executable, so that the next "make" recompiles the entire project +**`make clean`** : removes all .o files and the executable, so that the next "make" recompiles the entire project -**make data-cleanup** : clears out all simulation data +**`make data-cleanup`** : clears out all simulation data -**make reset** : de-populates the sample project and returns to the original PhysiCell state. Use this when switching to a new PhysiCell sample project. +**`make reset`** : de-populates the sample project and returns to the original PhysiCell state. Use this when switching to a new PhysiCell sample project. -**make jpeg** : uses ImageMagick to convert the SVG files in the output directory to JPG (with appropriate sizing to make movies). Supply `OUTPUT=foldername` to select a different folder. +**`make jpeg`** : uses ImageMagick to convert the SVG files in the output directory to JPG (with appropriate sizing to make movies). Supply `OUTPUT=foldername` to select a different folder. -**make movie** : uses ffmpeg to convert the JPG files in the output directory an mp4 movie. Supply `OUTPUT=foldername` to select a different folder, or `FRAMERATE=framerate` to override the frame rate. +**`make movie`** : uses ffmpeg to convert the JPG files in the output directory an mp4 movie. Supply `OUTPUT=foldername` to select a different folder, or `FRAMERATE=framerate` to override the frame rate. -**make upgrade** : fetch the latest release of PhysiCell and overwrite the core library and sample projects. +**`make upgrade`** : fetch the latest release of PhysiCell and overwrite the core library and sample projects. -**Homepage:** http://PhysiCell.MathCancer.org +### Key Links +**Homepage:** http://PhysiCell.MathCancer.org **Downloads:** http://PhysiCell.sf.net @@ -71,7 +72,7 @@ See changes.md for the full change log. * * * ## Release summary: -Version 1.10.2 introduces bugfixes to the behavior "dictionary" functiouns, data saves, and updating neighbor lists for nearby non-adhesive cells. It also introduces a number of ease-of-access functions to the phenotype for death rates, secretion, and internalized substrates. +Version 1.10.3 primarily fixes bugs and further refines the signal and behavior dictionaries, particularly with access to custom variables. It also allows users to designate custom variables as _conserved quantities_ that are divided evenly among daughter cells as division (e.g., melanosomes). The 1.10.0 release introduced major new phenotype functionality, including standardized support for cell-cell interactions (phagocytosis, cell attack that increases a tracked damage variable, and cell fusion), cell transformations, advanced chemotaxis, and cell adhesion affinities for preferential adhesion. This release also includes new, auto-generated "dictionaries" of signals and behaviors to facilitate writing cell behavioral models and intracellular models, as well as standardized Hill and linear response functions for use in intracellular models. Lastly, this release includes a number of bugfixes, most notably pseudorandom number generators with improved thread safety. @@ -84,6 +85,8 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun **NOTE 2:** Windows users need to follow an updated (from v1.8) MinGW64 installation procedure. This will install an updated version of g++, plus libraries that are needed for some of the intracellular models. See the [Quickstart](documentation/Quickstart.md) for details. ### Major new features and changes in the 1.10.z versions +#### 1.10.3 ++ None in this version. See 1.10.0 #### 1.10.2 + None in this version. See 1.10.0 #### 1.10.1 @@ -193,6 +196,15 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun + With default parameters, bacteria kill off cells ot form abscesses, until death attracts macrophages to activate immune response to kill the invaders, after which the tissue can regrow. ### Minor new features and changes: +#### 1.10.3 ++ Added `attachment_rate` and `detachment_rate` to `phenotype.mechanics` for use in a future standard attachment and detachment model. ++ Modernized output format: + + More complete cell data saved for each cell agent. + + Merged the previously separate cell matlab files for each time save + + Added more metadata to outputs ++ `Variables` and `Vector_Variables` in `Custom_Cell_Data` now have a new Boolean attribute `conserved_quantity` (defaulted to false). If this value is set to true, then the custom variable is divided evenly between daughter cells at division. ++ Custom cell data can now be designated as conserved by settings an attribute `conserved="true"` in the XMO configuration file. + #### 1.10.2 + Added `operator<<` for vectors of ints and vectors of strings. So that `std::cout << v << std::endl;` will work if `v` is `std::vector` of `std::vector`. It was truly annoying that these were missing, so sorry! + Added `dead` to the signals dictionaries, which returns 0.0 or 1.0 based on `phenotype.death.dead`. @@ -212,7 +224,6 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun + Added new ease of access function for internalized substrates: + `double& Molecular::internalized_total_substrate( std::string name )` allows you to easily read/write the total amount of internalized substrate by name. For example: ```pCell->phenotype.molecular.internalized_total_substrate( "oxygen" ) = 0.01`` - #### 1.10.1 + None in this version. See 1.10.0. #### 1.10.0 @@ -225,6 +236,19 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun + `create_cell( Cell_Definition )` now uses "`is_movable`" from the cell definition. ### Beta features (not fully supported): +#### 1.10.3 ++ Each time outputs two cell interaction graphs (as text files): + + neighbor graph records which cells are within interaction distance for each cell agent, with format; + ID: ID1, ID2, ID3, ... (Cell ID: and the IDs of interacting cells) + + attached cell graph records which cells are attached for each cell agent, with format; + ID: ID1, ID2, ID3, ... (Cell ID: and the IDs of attached cells) + + We might split these into 3 files: + + an ID list that has the ID of each cell in order of appearence. + + neighbor list omits the preceding "ID:" since now each row corresponds to the index in the ID list + + attached cell list omits the preceding "ID:" since now each row corresponds to the index in the ID list + + Began experimenting with a planned `integrity` subclass to `phenotype` that will record multiple types of cell damage and associated damage and repair rates. It is not yet clear if we wil provide built-in support for damaged-driven apoptotic death and cycle arrest, as these are generally better left to modeler-driven hypotheses. + +None in this version. See 1.10.0. #### 1.10.2 + None in this version. See 1.10.0. #### 1.10.1 @@ -241,6 +265,11 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun + Added simple contour plotting of a substrate (anim_substrate2D.py in /beta; copy to /output) ### Bugfixes: +#### 1.10.3 ++ Fixed bug in `get_single_behavior` and `get_single_base_behavior` where querying any cycle exit rate or cycle entry mistakenly returned -1. + ++ + #### 1.10.2 + Fixed error in `double get_single_behavior()` where the `cell-cell adhesion elastic constant` behavior was not found. @@ -267,7 +296,8 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun + In response to PR 91 (https://github.com/MathCancer/PhysiCell/pull/91): Previoulsy, if the make jpeg rule fails, the `__*.txt` temporary files are left in place, so a subsequent "make jpeg" fails until these files are manually removed. Replacing `>>` (append) with `>` (overwrite) fixes the problem. Thanks [saikiRA1011](https://github.com/saikiRA1011)! ### Notices for intended changes that may affect backwards compatibility: - ++ We intend to deprecate the unused phenotype variables `relative_maximum_attachment_distance`, `relative_detachment_distance`, and `maximum_attachment_rate` from `phenotype.mechanics.` + + We intend to merge `Custom_Variable` and `Custom_Vector_Variable` in the very near future. + We may change the role of `operator()` and `operator[]` in `Custom_Variable` to more closely mirror the functionality in `Parameters`. diff --git a/VERSION.txt b/VERSION.txt index 70ad429ec..62321afdc 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -1.10.2 \ No newline at end of file +1.10.3 \ No newline at end of file diff --git a/changes.md b/changes.md index 26206273f..db1277037 100644 --- a/changes.md +++ b/changes.md @@ -1,8 +1,8 @@ # PhysiCell: an Open Source Physics-Based Cell Simulator for 3-D Multicellular Systems -**Version:** 1.10.3-beta +**Version:** 1.10.3 -**Release date:** ? June 2022 +**Release date:** 25 June 2022 ## Overview: PhysiCell is a flexible open source framework for building agent-based multicellular models in 3-D tissue environments. @@ -72,7 +72,7 @@ See changes.md for the full change log. * * * ## Release summary: -Version 1.10.3 ... +Version 1.10.3 primarily fixes bugs and further refines the signal and behavior dictionaries, particularly with access to custom variables. It also allows users to designate custom variables as _conserved quantities_ that are divided evenly among daughter cells as division (e.g., melanosomes). The 1.10.0 release introduced major new phenotype functionality, including standardized support for cell-cell interactions (phagocytosis, cell attack that increases a tracked damage variable, and cell fusion), cell transformations, advanced chemotaxis, and cell adhesion affinities for preferential adhesion. This release also includes new, auto-generated "dictionaries" of signals and behaviors to facilitate writing cell behavioral models and intracellular models, as well as standardized Hill and linear response functions for use in intracellular models. Lastly, this release includes a number of bugfixes, most notably pseudorandom number generators with improved thread safety. @@ -198,6 +198,12 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun ### Minor new features and changes: #### 1.10.3 + Added `attachment_rate` and `detachment_rate` to `phenotype.mechanics` for use in a future standard attachment and detachment model. ++ Modernized output format: + + More complete cell data saved for each cell agent. + + Merged the previously separate cell matlab files for each time save + + Added more metadata to outputs ++ `Variables` and `Vector_Variables` in `Custom_Cell_Data` now have a new Boolean attribute `conserved_quantity` (defaulted to false). If this value is set to true, then the custom variable is divided evenly between daughter cells at division. ++ Custom cell data can now be designated as conserved by settings an attribute `conserved="true"` in the XMO configuration file. #### 1.10.2 + Added `operator<<` for vectors of ints and vectors of strings. So that `std::cout << v << std::endl;` will work if `v` is `std::vector` of `std::vector`. It was truly annoying that these were missing, so sorry! @@ -218,7 +224,6 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun + Added new ease of access function for internalized substrates: + `double& Molecular::internalized_total_substrate( std::string name )` allows you to easily read/write the total amount of internalized substrate by name. For example: ```pCell->phenotype.molecular.internalized_total_substrate( "oxygen" ) = 0.01`` - #### 1.10.1 + None in this version. See 1.10.0. #### 1.10.0 @@ -232,7 +237,18 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun ### Beta features (not fully supported): #### 1.10.3 -+ None in this version. See 1.10.0. ++ Each time outputs two cell interaction graphs (as text files): + + neighbor graph records which cells are within interaction distance for each cell agent, with format; + ID: ID1, ID2, ID3, ... (Cell ID: and the IDs of interacting cells) + + attached cell graph records which cells are attached for each cell agent, with format; + ID: ID1, ID2, ID3, ... (Cell ID: and the IDs of attached cells) + + We might split these into 3 files: + + an ID list that has the ID of each cell in order of appearence. + + neighbor list omits the preceding "ID:" since now each row corresponds to the index in the ID list + + attached cell list omits the preceding "ID:" since now each row corresponds to the index in the ID list + + Began experimenting with a planned `integrity` subclass to `phenotype` that will record multiple types of cell damage and associated damage and repair rates. It is not yet clear if we wil provide built-in support for damaged-driven apoptotic death and cycle arrest, as these are generally better left to modeler-driven hypotheses. + +None in this version. See 1.10.0. #### 1.10.2 + None in this version. See 1.10.0. #### 1.10.1 @@ -250,7 +266,12 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun ### Bugfixes: #### 1.10.3 -+ None in this version. ++ Fixed bug in `get_single_behavior` and `get_single_base_behavior` where querying any cycle exit rate or cycle entry mistakenly returned -1. + ++ ++ ++ + #### 1.10.2 + Fixed error in `double get_single_behavior()` where the `cell-cell adhesion elastic constant` behavior was not found. diff --git a/core/PhysiCell.h b/core/PhysiCell.h index d1d17694a..bc8476597 100644 --- a/core/PhysiCell.h +++ b/core/PhysiCell.h @@ -72,7 +72,7 @@ #include #include -static std::string PhysiCell_Version = "1.10.2"; +static std::string PhysiCell_Version = "1.10.3"; static std::string PhysiCell_URL = "http://PhysiCell.MathCancer.org"; static std::string PhysiCell_DOI = "10.1371/journal.pcbi.1005991"; diff --git a/core/PhysiCell_cell.cpp b/core/PhysiCell_cell.cpp index 33c539358..4325d953b 100644 --- a/core/PhysiCell_cell.cpp +++ b/core/PhysiCell_cell.cpp @@ -509,6 +509,21 @@ Cell* Cell::divide( ) // make sure ot remove adhesions remove_all_attached_cells(); + + // version 1.10.3: + // conserved quantitites in custom data aer divided in half + // so that each daughter cell gets half of the original ; + for( int nn = 0 ; nn < custom_data.variables.size() ; nn++ ) + { + if( custom_data.variables[nn].conserved_quantity == true ) + { custom_data.variables[nn].value *= 0.5; } + } + for( int nn = 0 ; nn < custom_data.vector_variables.size() ; nn++ ) + { + if( custom_data.vector_variables[nn].conserved_quantity == true ) + { custom_data.vector_variables[nn].value *= 0.5; } + } + Cell* child = create_cell(); child->copy_data( this ); @@ -2960,10 +2975,12 @@ Cell_Definition* initialize_cell_definition_from_pugixml( pugi::xml_node cd_node std::string name = xml_get_my_name( node1 ); // units - std::string units = node1.attribute( "units").value(); - + std::string units = node1.attribute( "units").value(); std::vector values; // ( length, 0.0 ); - + + // conserved quantity + bool conserved = node1.attribute( "conserved").as_bool(); + // get value(s) std::string str_values = xml_get_my_string_value( node1 ); csv_to_vector( str_values.c_str() , values ); @@ -2981,6 +2998,8 @@ Cell_Definition* initialize_cell_definition_from_pugixml( pugi::xml_node cd_node // otherwise, add else { pCD->custom_data.add_variable( name, units, values[0] ); } + + n = pCD->custom_data.find_variable_index( name ); } // or vector else @@ -2993,7 +3012,11 @@ Cell_Definition* initialize_cell_definition_from_pugixml( pugi::xml_node cd_node // otherwise, add else { pCD->custom_data.add_vector_variable( name, units, values ); } + + n = pCD->custom_data.find_vector_variable_index( name ); } + + // set conserved attribute node1 = node1.next_sibling(); } diff --git a/core/PhysiCell_custom.cpp b/core/PhysiCell_custom.cpp index 7283b4c66..505d42fc4 100644 --- a/core/PhysiCell_custom.cpp +++ b/core/PhysiCell_custom.cpp @@ -79,6 +79,7 @@ Variable::Variable() name = "unnamed"; units = "dimensionless"; value = 0.0; + conserved_quantity = false; return; } @@ -94,6 +95,7 @@ Vector_Variable::Vector_Variable() name = "unnamed"; units = "dimensionless"; value.resize(3, 0.0 ); + conserved_quantity = false; return; } diff --git a/core/PhysiCell_custom.h b/core/PhysiCell_custom.h index a1c264b0f..3200318f4 100644 --- a/core/PhysiCell_custom.h +++ b/core/PhysiCell_custom.h @@ -85,6 +85,7 @@ class Variable std::string name; double value; std::string units; + bool conserved_quantity; Variable(); }; @@ -98,6 +99,7 @@ class Vector_Variable std::string name; std::vector value; std::string units; + bool conserved_quantity; Vector_Variable(); }; diff --git a/core/PhysiCell_phenotype.cpp b/core/PhysiCell_phenotype.cpp index e5a4f8bdc..4af347e4d 100644 --- a/core/PhysiCell_phenotype.cpp +++ b/core/PhysiCell_phenotype.cpp @@ -1335,5 +1335,72 @@ double& Cell_Transformations::transformation_rate( std::string type_name ) return transformation_rates[n]; } +// beta functionality in 1.10.3 +Integrity::Integrity() +{ + damage = 0.0; + damage_rate = 0.0; + damage_repair_rate = 0.0; + + lipid_damage = 0.0; + lipid_damage_rate = 0.0; + lipid_damage_repair_rate = 0.0; + + // DNA damage + DNA_damage = 0.0; + DNA_damage_rate = 0.0; + DNA_damage_repair_rate = 0.0; + + return; +} + +void Integrity::advance_damage_models( double dt ) +{ + double temp1; + double temp2; + static double tol = 1e-8; + + // general damage + if( damage_rate > tol || damage_repair_rate > tol ) + { + temp1 = dt; + temp2 = dt; + temp1 *= damage_rate; + temp2 *= damage_repair_rate; + temp2 += 1; + + damage += temp1; + damage /= temp2; + } + + // lipid damage + if( lipid_damage_rate > tol || lipid_damage_repair_rate > tol ) + { + temp1 = dt; + temp2 = dt; + temp1 *= lipid_damage_rate; + temp2 *= lipid_damage_repair_rate; + temp2 += 1; + + lipid_damage += temp1; + lipid_damage /= temp2; + } + + // DNA damage + if( DNA_damage_rate > tol || DNA_damage_repair_rate > tol ) + { + temp1 = dt; + temp2 = dt; + temp1 *= DNA_damage_rate; + temp2 *= DNA_damage_repair_rate; + temp2 += 1; + + DNA_damage += temp1; + DNA_damage /= temp2; + } + + return; +} + }; diff --git a/core/PhysiCell_phenotype.h b/core/PhysiCell_phenotype.h index 79f84bac5..bc80948c2 100644 --- a/core/PhysiCell_phenotype.h +++ b/core/PhysiCell_phenotype.h @@ -686,6 +686,34 @@ class Cell_Transformations // void perform_transformations( Cell* pCell, Phenotype& phenotype, double dt ); }; +// pre-beta functionality in 1.10.3 +class Integrity +{ + private: + public: + // generic damage variable + double damage; + double damage_rate; + double damage_repair_rate; + + // lipid damage (e.g, cell membrane, organelles) + double lipid_damage; + double lipid_damage_rate; + double lipid_damage_repair_rate; + + // DNA damage + double DNA_damage; + double DNA_damage_rate; + double DNA_damage_repair_rate; + + // other damages? + // mitochondrial? spindle? other? + + Integrity(); + + void advance_damage_models( double dt ); +}; + class Phenotype { private: diff --git a/core/PhysiCell_signal_behavior.cpp b/core/PhysiCell_signal_behavior.cpp index 418a387e7..97b65c72c 100644 --- a/core/PhysiCell_signal_behavior.cpp +++ b/core/PhysiCell_signal_behavior.cpp @@ -213,6 +213,25 @@ void setup_signal_behavior_dictionaries( void ) signal_to_int["current time"] = map_index; signal_to_int["global time"] = map_index; + // custom signals + for( int nc=0 ; nc < cell_defaults.custom_data.variables.size() ; nc++ ) + { + map_index++; + std::string custom_signal_name = "custom:" ; + custom_signal_name += cell_defaults.custom_data.variables[nc].name; + signal_to_int[custom_signal_name] = map_index; + int_to_signal[map_index] = custom_signal_name; + + // synonyms + custom_signal_name = "custom: " ; + custom_signal_name += cell_defaults.custom_data.variables[nc].name; + signal_to_int[custom_signal_name] = map_index; + + custom_signal_name = "custom " ; + custom_signal_name += std::to_string(nc); + signal_to_int[custom_signal_name] = map_index; + } + behavior_to_int.clear(); int_to_behavior.clear(); @@ -425,6 +444,25 @@ void setup_signal_behavior_dictionaries( void ) behavior_to_int[temp] = map_index; } + // custom behaviors + for( int nc=0 ; nc < cell_defaults.custom_data.variables.size() ; nc++ ) + { + map_index++; + std::string custom_behavior_name = "custom:" ; + custom_behavior_name += cell_defaults.custom_data.variables[nc].name; + behavior_to_int[custom_behavior_name] = map_index; + int_to_behavior[map_index] = custom_behavior_name; + + // synonyms + custom_behavior_name = "custom: " ; + custom_behavior_name += cell_defaults.custom_data.variables[nc].name; + behavior_to_int[custom_behavior_name] = map_index; + + custom_behavior_name = "custom " ; + custom_behavior_name += std::to_string(nc); + behavior_to_int[custom_behavior_name] = map_index; + } + // resize scales; signal_scales.resize( int_to_signal.size() , 1.0 ); @@ -621,6 +659,14 @@ std::vector get_signals( Cell* pCell ) static int time_ind = find_signal_index( "time" ); signals[time_ind] = PhysiCell_globals.current_time; + // custom signals + static int first_custom_ind = find_signal_index( "custom 0" ); + if( first_custom_ind > -1 ) + { + for( int nc=0 ; nc < pCell->custom_data.variables.size() ; nc++ ) + { signals[first_custom_ind+nc] = pCell->custom_data.variables[nc].value; } + } + // rescale signals /= signal_scales; @@ -838,6 +884,16 @@ double get_single_signal( Cell* pCell, int index ) return out; } + // custom signals + static int first_custom_ind = find_signal_index( "custom 0" ); + static int max_custom_ind = first_custom_ind+pCell->custom_data.variables.size(); + if( first_custom_ind > -1 && index >= first_custom_ind && index < max_custom_ind ) + { + out = pCell->custom_data.variables[ index-first_custom_ind ].value; + out /= signal_scales[index]; + return out; + } + // unknown after here ! std::cout << "Warning: Requested unknown signal number " << index << "!" << std::endl @@ -994,6 +1050,14 @@ void set_behaviors( Cell* pCell , std::vector parameters ) parameters.begin()+first_transformation_index+n , pCell->phenotype.cell_transformations.transformation_rates.begin() ); + // custom behaviors + static int first_custom_ind = find_behavior_index( "custom 0"); + if( first_custom_ind >= 0 ) + { + for( int nc=0 ; nc < pCell->custom_data.variables.size() ; nc++ ) + { pCell->custom_data.variables[nc].value = parameters[first_custom_ind+nc]; } + } + return; } @@ -1137,6 +1201,12 @@ void set_single_behavior( Cell* pCell, int index , double parameter ) if( index >= first_transformation_index && index < first_transformation_index + n ) { pCell->phenotype.cell_transformations.transformation_rates[index-first_transformation_index] = parameter; return; } + // custom behavior + static int first_custom_ind = find_behavior_index( "custom 0"); + static int max_custom_ind = first_custom_ind + pCell->custom_data.variables.size(); + if( first_custom_ind >= 0 && index >= first_custom_ind && index < max_custom_ind ) + { pCell->custom_data.variables[index-first_custom_ind].value = parameter; } + return; } @@ -1279,6 +1349,15 @@ std::vector get_behaviors( Cell* pCell ) pCell->phenotype.cell_transformations.transformation_rates.end(), parameters.begin()+first_transformation_index ); + // custom behavior + static int first_custom_ind = find_behavior_index( "custom 0"); + static int max_custom_ind = first_custom_ind + pCell->custom_data.variables.size(); + if( first_custom_ind >= 0 ) + { + for( int nc=0; nc < pCell->custom_data.variables.size(); nc++ ) + { parameters[first_custom_ind+nc] = pCell->custom_data.variables[nc].value; } + } + return parameters; } @@ -1325,7 +1404,7 @@ double get_single_behavior( Cell* pCell , int index ) std::cout << "Warning: Standardized behaviors only support exit rate from the first 6 phases of a cell cycle!" << std::endl << " Ignoring any later phase exit rates." << std::endl; } - if( index >= first_cycle_index && index < first_export_index + 6 ) + if( index >= first_cycle_index && index < first_cycle_index + 6 ) { int ind = index - first_cycle_index; if( ind < max_cycle_index ) @@ -1427,6 +1506,12 @@ double get_single_behavior( Cell* pCell , int index ) if( index >= first_transformation_index && index < first_transformation_index+n ) { return pCell->phenotype.cell_transformations.transformation_rates[index-first_transformation_index]; } + // custom behavior + static int first_custom_ind = find_behavior_index( "custom 0"); + static int max_custom_ind = first_custom_ind + pCell->custom_data.variables.size(); + if( first_custom_ind >= 0 && index >= first_custom_ind && index < max_custom_ind ) + { return pCell->custom_data.variables[index-first_custom_ind].value; } + return -1; } @@ -1599,6 +1684,15 @@ std::vector get_base_behaviors( Cell* pCell ) pCD->phenotype.cell_transformations.transformation_rates.end(), parameters.begin()+first_transformation_index ); + // custom behavior + static int first_custom_ind = find_behavior_index( "custom 0"); + static int max_custom_ind = first_custom_ind + pCell->custom_data.variables.size(); + if( first_custom_ind >= 0 ) + { + for( int nc=0; nc < pCell->custom_data.variables.size(); nc++ ) + { parameters[first_custom_ind+nc] = pCD->custom_data.variables[nc].value; } + } + return parameters; } @@ -1647,7 +1741,7 @@ double get_single_base_behavior( Cell* pCell , int index ) std::cout << "Warning: Standardized behaviors only support exit rate from the first 6 phases of a cell cycle!" << std::endl << " Ignoring any later phase exit rates." << std::endl; } - if( index >= first_cycle_index && index < first_export_index + 6 ) + if( index >= first_cycle_index && index < first_cycle_index + 6 ) { int ind = index - first_cycle_index; if( ind < max_cycle_index ) @@ -1749,6 +1843,12 @@ double get_single_base_behavior( Cell* pCell , int index ) if( index >= first_transformation_index && index < first_transformation_index + n ) { return pCD->phenotype.cell_transformations.transformation_rates[index-first_transformation_index]; } + // custom behavior + static int first_custom_ind = find_behavior_index( "custom 0"); + static int max_custom_ind = first_custom_ind + pCell->custom_data.variables.size(); + if( first_custom_ind >= 0 && index >= first_custom_ind && index < max_custom_ind ) + { return pCD->custom_data.variables[index-first_custom_ind].value; } + return -1; } From 1a5ca1c0dc2d6266ffcc88182382634720dd9d76 Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Sun, 26 Jun 2022 17:21:32 -0400 Subject: [PATCH 33/38] =?UTF-8?q?bugfix=20from=20In=C3=AAs=20Gon=C3=A7alve?= =?UTF-8?q?s!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- changes.md | 4 +--- core/PhysiCell_standard_models.h | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 57f20838c..5927930ba 100644 --- a/README.md +++ b/README.md @@ -268,7 +268,7 @@ None in this version. See 1.10.0. #### 1.10.3 + Fixed bug in `get_single_behavior` and `get_single_base_behavior` where querying any cycle exit rate or cycle entry mistakenly returned -1. -+ ++ Corrected declaration of `standard_add_basement_membrane_interactions` in `PhysiCell_standard_models.h` to properly use phenotype by reference. Thank you Inês Gonçalves! #### 1.10.2 + Fixed error in `double get_single_behavior()` where the `cell-cell adhesion elastic constant` behavior was not found. diff --git a/changes.md b/changes.md index db1277037..bf0e675f1 100644 --- a/changes.md +++ b/changes.md @@ -268,9 +268,7 @@ None in this version. See 1.10.0. #### 1.10.3 + Fixed bug in `get_single_behavior` and `get_single_base_behavior` where querying any cycle exit rate or cycle entry mistakenly returned -1. -+ -+ -+ ++ Corrected declaration of `standard_add_basement_membrane_interactions` in `PhysiCell_standard_models.h` to properly use phenotype by reference. Thank you Inês Gonçalves! #### 1.10.2 + Fixed error in `double get_single_behavior()` where the `cell-cell adhesion elastic constant` behavior was not found. diff --git a/core/PhysiCell_standard_models.h b/core/PhysiCell_standard_models.h index c6e45ede4..5e2daf207 100644 --- a/core/PhysiCell_standard_models.h +++ b/core/PhysiCell_standard_models.h @@ -108,7 +108,7 @@ void basic_volume_model( Cell* pCell, Phenotype& phenotype, double dt ); // done // standard mechanics functions void standard_update_cell_velocity( Cell* pCell, Phenotype& phenotype, double dt); // done -void standard_add_basement_membrane_interactions( Cell* pCell, Phenotype phenotype, double dt ); +void standard_add_basement_membrane_interactions( Cell* pCell, Phenotype& phenotype, double dt ); // bounary avoidance functions From bcb4f16d054c84c1643bda54364a9570bebe88f5 Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Sun, 26 Jun 2022 17:23:25 -0400 Subject: [PATCH 34/38] Update PhysiCell_settings.xml --- sample_projects/template/config/PhysiCell_settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample_projects/template/config/PhysiCell_settings.xml b/sample_projects/template/config/PhysiCell_settings.xml index f00a8301a..335a8a916 100644 --- a/sample_projects/template/config/PhysiCell_settings.xml +++ b/sample_projects/template/config/PhysiCell_settings.xml @@ -315,7 +315,7 @@ - 1.0 + 1.0 From 30ad4d32927ea1767c155a0b3f48e22dad75c370 Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Sun, 26 Jun 2022 17:32:14 -0400 Subject: [PATCH 35/38] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5927930ba..d4d418a33 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,10 @@ Visit http://MathCancer.org/blog for the latest tutorials and help. **Quick Start:** Look at QuickStart.md in the documentation folder. **User Guide:** Look at UserGuide.pdf in the documentation folder. + +**Setup and Training:** See last year's workshop and hackathon at https://github.com/PhysiCell-Training/ws2021 -**Tutorials:** http://www.mathcancer.org/blog/physicell-tutorials/ +**Old Tutorials:** http://www.mathcancer.org/blog/physicell-tutorials/ **Latest info:** follow [@PhysiCell](https://twitter.com/PhysiCell) on Twitter (http://twitter.com/PhysiCell) @@ -72,7 +74,7 @@ See changes.md for the full change log. * * * ## Release summary: -Version 1.10.3 primarily fixes bugs and further refines the signal and behavior dictionaries, particularly with access to custom variables. It also allows users to designate custom variables as _conserved quantities_ that are divided evenly among daughter cells as division (e.g., melanosomes). +Version 1.10.3 primarily fixes bugs and further refines the signal and behavior dictionaries, particularly with access to custom variables. It also allows users to designate custom variables as _conserved quantities_ that are divided evenly among daughter cells as division (e.g., melanosomes). Lastly, this release continues updates to PhysiBoSS and libRoadrunner to leverage newer core features and improve compatibiltiy, while also improving support for newer Mac (M1 and M2) architectures. The 1.10.0 release introduced major new phenotype functionality, including standardized support for cell-cell interactions (phagocytosis, cell attack that increases a tracked damage variable, and cell fusion), cell transformations, advanced chemotaxis, and cell adhesion affinities for preferential adhesion. This release also includes new, auto-generated "dictionaries" of signals and behaviors to facilitate writing cell behavioral models and intracellular models, as well as standardized Hill and linear response functions for use in intracellular models. Lastly, this release includes a number of bugfixes, most notably pseudorandom number generators with improved thread safety. @@ -204,6 +206,8 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun + Added more metadata to outputs + `Variables` and `Vector_Variables` in `Custom_Cell_Data` now have a new Boolean attribute `conserved_quantity` (defaulted to false). If this value is set to true, then the custom variable is divided evenly between daughter cells at division. + Custom cell data can now be designated as conserved by settings an attribute `conserved="true"` in the XMO configuration file. ++ Improved support for Apple M1 and M2 chips. ++ Refinements to PhysiBoSS. #### 1.10.2 + Added `operator<<` for vectors of ints and vectors of strings. So that `std::cout << v << std::endl;` will work if `v` is `std::vector` of `std::vector`. It was truly annoying that these were missing, so sorry! From a45fe2500503c586fa940aa21b978b5bda82cc95 Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Sun, 26 Jun 2022 17:32:17 -0400 Subject: [PATCH 36/38] Update changes.md --- changes.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/changes.md b/changes.md index bf0e675f1..5469da2a1 100644 --- a/changes.md +++ b/changes.md @@ -64,7 +64,9 @@ Visit http://MathCancer.org/blog for the latest tutorials and help. **User Guide:** Look at UserGuide.pdf in the documentation folder. -**Tutorials:** http://www.mathcancer.org/blog/physicell-tutorials/ +**Setup and Training:** See last year's workshop and hackathon at https://github.com/PhysiCell-Training/ws2021 + +**Older Tutorials:** http://www.mathcancer.org/blog/physicell-tutorials/ **Latest info:** follow [@PhysiCell](https://twitter.com/PhysiCell) on Twitter (http://twitter.com/PhysiCell) @@ -72,12 +74,11 @@ See changes.md for the full change log. * * * ## Release summary: -Version 1.10.3 primarily fixes bugs and further refines the signal and behavior dictionaries, particularly with access to custom variables. It also allows users to designate custom variables as _conserved quantities_ that are divided evenly among daughter cells as division (e.g., melanosomes). +Version 1.10.3 primarily fixes bugs and further refines the signal and behavior dictionaries, particularly with access to custom variables. It also allows users to designate custom variables as _conserved quantities_ that are divided evenly among daughter cells as division (e.g., melanosomes). Lastly, this release continues updates to PhysiBoSS and libRoadrunner to leverage newer core features and improve compatibiltiy, while also improving support for newer Mac (M1 and M2) architectures. The 1.10.0 release introduced major new phenotype functionality, including standardized support for cell-cell interactions (phagocytosis, cell attack that increases a tracked damage variable, and cell fusion), cell transformations, advanced chemotaxis, and cell adhesion affinities for preferential adhesion. This release also includes new, auto-generated "dictionaries" of signals and behaviors to facilitate writing cell behavioral models and intracellular models, as well as standardized Hill and linear response functions for use in intracellular models. Lastly, this release includes a number of bugfixes, most notably pseudorandom number generators with improved thread safety. A blog post and tutorial on the new phenotype elements can be found at http://www.mathcancer.org/blog/introducing-cell-interactions-and-transformations. - A blog post and tutorial on the new signal and behavior dictionaries can be found at http://www.mathcancer.org/blog/introducing-cell-signal-and-behavior-dictionaries. **NOTE 1:** MacOS users need to define a PHYSICELL_CPP environment variable to specify their OpenMP-enabled g++. See the [Quickstart](documentation/Quickstart.md) for details. @@ -204,6 +205,8 @@ A blog post and tutorial on the new signal and behavior dictionaries can be foun + Added more metadata to outputs + `Variables` and `Vector_Variables` in `Custom_Cell_Data` now have a new Boolean attribute `conserved_quantity` (defaulted to false). If this value is set to true, then the custom variable is divided evenly between daughter cells at division. + Custom cell data can now be designated as conserved by settings an attribute `conserved="true"` in the XMO configuration file. ++ Improved support for Apple M1 and M2 chips. ++ Refinements to PhysiBoSS. #### 1.10.2 + Added `operator<<` for vectors of ints and vectors of strings. So that `std::cout << v << std::endl;` will work if `v` is `std::vector` of `std::vector`. It was truly annoying that these were missing, so sorry! From 0db3f4379c5a30b0fcd467a10444c1c3ca038536 Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Sun, 26 Jun 2022 22:41:04 -0400 Subject: [PATCH 37/38] last bugfix --- BioFVM/BioFVM_microenvironment.cpp | 2 +- README.md | 4 ++-- changes.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BioFVM/BioFVM_microenvironment.cpp b/BioFVM/BioFVM_microenvironment.cpp index 0b3caf6d7..a93eb50aa 100644 --- a/BioFVM/BioFVM_microenvironment.cpp +++ b/BioFVM/BioFVM_microenvironment.cpp @@ -269,7 +269,7 @@ void Microenvironment::apply_dirichlet_conditions( void ) { density_vector( dirichlet_indices[i] ) = dirichlet_value_vectors[i]; } */ - #pragma omp parallel for + // #pragma omp parallel for for( unsigned int i=0 ; i < mesh.voxels.size() ;i++ ) { /* diff --git a/README.md b/README.md index d4d418a33..0bef58397 100644 --- a/README.md +++ b/README.md @@ -271,9 +271,9 @@ None in this version. See 1.10.0. ### Bugfixes: #### 1.10.3 + Fixed bug in `get_single_behavior` and `get_single_base_behavior` where querying any cycle exit rate or cycle entry mistakenly returned -1. - + Corrected declaration of `standard_add_basement_membrane_interactions` in `PhysiCell_standard_models.h` to properly use phenotype by reference. Thank you Inês Gonçalves! - ++ Removed the OpenMP pragma in `void Microenvironment::apply_dirichlet_conditions( void )` (around line 272) that tends to perform more poorly than serial code. + #### 1.10.2 + Fixed error in `double get_single_behavior()` where the `cell-cell adhesion elastic constant` behavior was not found. diff --git a/changes.md b/changes.md index 5469da2a1..bbc582c2f 100644 --- a/changes.md +++ b/changes.md @@ -270,8 +270,8 @@ None in this version. See 1.10.0. ### Bugfixes: #### 1.10.3 + Fixed bug in `get_single_behavior` and `get_single_base_behavior` where querying any cycle exit rate or cycle entry mistakenly returned -1. - + Corrected declaration of `standard_add_basement_membrane_interactions` in `PhysiCell_standard_models.h` to properly use phenotype by reference. Thank you Inês Gonçalves! ++ Removed the OpenMP pragma in `void Microenvironment::apply_dirichlet_conditions( void )` (around line 272) that tends to perform more poorly than serial code. #### 1.10.2 + Fixed error in `double get_single_behavior()` where the `cell-cell adhesion elastic constant` behavior was not found. From 319414f8fef91054132056d327f0410b8760cae1 Mon Sep 17 00:00:00 2001 From: Paul Macklin Date: Sun, 26 Jun 2022 22:42:02 -0400 Subject: [PATCH 38/38] Delete pyMCDS2.py --- pyMCDS2.py | 520 ----------------------------------------------------- 1 file changed, 520 deletions(-) delete mode 100644 pyMCDS2.py diff --git a/pyMCDS2.py b/pyMCDS2.py deleted file mode 100644 index 7b386d5a4..000000000 --- a/pyMCDS2.py +++ /dev/null @@ -1,520 +0,0 @@ -import xml.etree.ElementTree as ET -import numpy as np -import pandas as pd -import scipy.io as sio -import sys -import warnings -from pathlib import Path - -class pyMCDS2: - """ - This class contains a dictionary of dictionaries that contains all of the - output from a single time step of a PhysiCell Model. This class assumes that - all output files are stored in the same directory. Data is loaded by reading - the .xml file for a particular timestep. - - Parameters - ---------- - xml_name: str - String containing the name of the xml file without the path - output_path: str, optional - String containing the path (relative or absolute) to the directory - where PhysiCell output files are stored (default= ".") - - Attributes - ---------- - data : dict - Hierarchical container for all of the data retrieved by parsing the xml - file and the files referenced therein. - """ - def __init__(self, xml_file, output_path='.'): - self.data = self._read_xml(xml_file, output_path) - - ## METADATA RELATED FUNCTIONS - - def get_time(self): - return self.data['metadata']['current_time'] - - ## MESH RELATED FUNCTIONS - - def get_mesh(self, flat=False): - """ - Return a meshgrid of the computational domain. Can return either full - 3D or a 2D plane for contour plots. - - Parameters - ---------- - flat : bool - If flat is set to true, we return only the x and y meshgrid. - Otherwise we return x, y, and z - - Returns - ------- - splitting : list length=2 if flat=True, else length=3 - Contains arrays of voxel center coordinates as meshgrid with shape - [nx_voxel, ny_voxel, nz_voxel] or [nx_voxel, ny_voxel] if flat=True. - """ - if flat == True: - xx = self.data['mesh']['x_coordinates'][:, :, 0] - yy = self.data['mesh']['y_coordinates'][:, :, 0] - - return [xx, yy] - - # if we dont want a plane just return appropriate values - else: - xx = self.data['mesh']['x_coordinates'] - yy = self.data['mesh']['y_coordinates'] - zz = self.data['mesh']['z_coordinates'] - - return [xx, yy, zz] - - def get_2D_mesh(self): - """ - This function returns the x, y meshgrid as two numpy arrays. It is - identical to get_mesh with the option flat=True - - Returns - ------- - splitting : list length=2 - Contains arrays of voxel center coordinates in x and y dimensions - as meshgrid with shape [nx_voxel, ny_voxel] - """ - xx = self.data['mesh']['x_coordinates'][:, :, 0] - yy = self.data['mesh']['y_coordinates'][:, :, 0] - - return [xx, yy] - - def get_linear_voxels(self): - """ - Helper function to quickly grab voxel centers array stored linearly as - opposed to meshgrid-style. - """ - return self.data['mesh']['voxels']['centers'] - - def get_mesh_spacing(self): - """ - Returns the space in between voxel centers for the mesh in terms of the - mesh's spatial units. Assumes that voxel centers fall on integer values. - - Returns - ------- - dx : float - Distance between voxel centers in the same units as the other - spatial measurements - """ - centers = self.get_linear_voxels() - X = np.unique(centers[0, :]) - Y = np.unique(centers[1, :]) - Z = np.unique(centers[2, :]) - - dx = (X.max() - X.min()) / X.shape[0] - dy = (Y.max() - Y.min()) / Y.shape[0] - dz = (Z.max() - Z.min()) / Z.shape[0] - - if np.abs(dx - dy) > 1e-10 or np.abs(dy - dz) > 1e-10 \ - or np.abs(dx - dz) > 1e-10: - print('Warning: grid spacing may be axis dependent.') - - return round(dx) - - def get_containing_voxel_ijk(self, x, y, z): - """ - Internal function to get the meshgrid indices for the center of a voxel - that contains the given position. - - Note that pyMCDS stores meshgrids as 'cartesian' - (indexing='xy' in np.meshgrid) which means that we will have - to use these indices as [j, i, k] on the actual meshgrid objects - - Parameters - ---------- - x : float - x-coordinate for the position - y : float - y-coordinate for the position - z : float - z-coordinate for the position - - Returns - ------- - ijk : list length=3 - contains the i, j, and k indices for the containing voxel's center - """ - xx, yy, zz = self.get_mesh() - ds = self.get_mesh_spacing() - - if x > xx.max(): - warnings.warn('Position out of bounds: x out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting x = x_max!'.format(x, y, z)) - x = xx.max() - elif x < xx.min(): - warnings.warn('Position out of bounds: x out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting x = x_min!'.format(x, y, z)) - x = xx.min() - elif y > yy.max(): - warnings.warn('Position out of bounds: y out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting y = y_max!'.format(x, y, z)) - y = yy.max() - elif y < yy.min(): - warnings.warn('Position out of bounds: y out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting y = y_min!'.format(x, y, z)) - y = yy.min() - elif z > zz.max(): - warnings.warn('Position out of bounds: z out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting z = z_max!'.format(x, y, z)) - z = zz.max() - elif z < zz.min(): - warnings.warn('Position out of bounds: z out of bounds in pyMCDS._get_voxel_idx({0}, {1}, {2}). Setting z = z_min!'.format(x, y, z)) - z = zz.min() - - i = np.round((x - xx.min()) / ds) - j = np.round((y - yy.min()) / ds) - k = np.round((z - zz.min()) / ds) - - ii, jj, kk = int(i), int(j), int(k) - - return [ii, jj, kk] - - ## MICROENVIRONMENT RELATED FUNCTIONS - - def get_substrate_names(self): - """ - Returns list of chemical species in microenvironment - - Returns - ------- - species_list : array (str), shape=[n_species,] - Contains names of chemical species in microenvironment - """ - species_list = [] - for name in self.data['continuum_variables']: - species_list.append(name) - - return species_list - - def get_concentrations(self, species_name, z_slice=None): - """ - Returns the concentration array for the specified chemical species - in the microenvironment. Can return either the whole 3D picture, or - a 2D plane of concentrations. - - Parameters - ---------- - species_name : str - Name of the chemical species for which to get concentrations - - z_slice : float - z-axis position to use as plane for 2D output. This value must match - a plane of voxel centers in the z-axis. - Returns - ------- - conc_arr : array (np.float) shape=[nx_voxels, ny_voxels, nz_voxels] - Contains the concentration of the specified chemical in each voxel. - The array spatially maps to a meshgrid of the voxel centers. - """ - if z_slice is not None: - # check to see that z_slice is a valid plane - zz = self.data['mesh']['z_coordinates'] - assert z_slice in zz, 'Specified z_slice {} not in z_coordinates'.format(z_slice) - - # do the processing if its ok - mask = zz == z_slice - full_conc = self.data['continuum_variables'][species_name]['data'] - conc_arr = full_conc[mask].reshape((zz.shape[0], zz.shape[1])) - else: - conc_arr = self.data['continuum_variables'][species_name]['data'] - - return conc_arr - - def get_concentrations_at(self, x, y, z): - """ - Return concentrations of each chemical species inside a particular voxel - that contains the point described in the arguments. - - Parameters - ---------- - x : float - x-position for the point of interest - y : float - y_position for the point of interest - z : float - z_position for the point of interest - - Returns - ------- - concs : array, shape=[n_substrates,] - array of concentrations in the order given by get_substrate_names() - """ - i, j, k = self.get_containing_voxel_ijk(x, y, z) - sub_name_list = self.get_substrate_names() - concs = np.zeros(len(sub_name_list)) - - for ix in range(len(sub_name_list)): - concs[ix] = self.get_concentrations(sub_name_list[ix])[j, i, k] - - return concs - - - ## CELL RELATED FUNCTIONS - - def get_cell_df(self): - """ - Builds DataFrame from data['discrete_cells'] - - Returns - ------- - cells_df : pd.Dataframe, shape=[n_cells, n_variables] - Dataframe containing the cell data for all cells at this time step - """ - cells_df = pd.DataFrame(self.data['discrete_cells']) - return cells_df - - def get_cell_variables(self): - """ - Returns the names of all of the cell variables tracked in ['discrete cells'] - dictionary - - Returns - ------- - var_list : list, shape=[n_variables] - Contains the names of the cell variables - """ - var_list = [] - for name in self.data['discrete_cells']: - var_list.append(name) - return var_list - - def get_cell_df_at(self, x, y, z): - """ - Returns a dataframe for cells in the same voxel as the position given by - x, y, and z. - - Parameters - ---------- - x : float - x-position for the point of interest - y : float - y_position for the point of interest - z : float - z_position for the point of interest - - Returns - ------- - vox_df : pd.DataFrame, shape=[n_cell_in_voxel, n_variables] - cell dataframe containing only cells in the same voxel as the point - specified by x, y, and z. - """ - ds = self.get_mesh_spacing() - xx, yy, zz = self.get_mesh() - i, j, k = self.get_containing_voxel_ijk(x, y, z) - x_vox = xx[j, i, k] - y_vox = yy[j, i, k] - z_vox = zz[j, i, k] - - cell_df = self.get_cell_df() - inside_voxel = ( (cell_df['position_x'] < x_vox + ds/2.) & - (cell_df['position_x'] > x_vox - ds/2.) & - (cell_df['position_y'] < y_vox + ds/2.) & - (cell_df['position_y'] > y_vox - ds/2.) & - (cell_df['position_z'] < z_vox + ds/2.) & - (cell_df['position_z'] > z_vox - ds/2.) ) - vox_df = cell_df[inside_voxel] - return vox_df - - def _read_xml(self, xml_file, output_path='.'): - """ - Does the actual work of initializing MultiCellDS by parsing the xml - """ - - output_path = Path(output_path) - xml_file = output_path / xml_file - tree = ET.parse(xml_file) - - print('Reading {}'.format(xml_file)) - - root = tree.getroot() - MCDS = {} - - # Get current simulated time - metadata_node = root.find('metadata') - time_node = metadata_node.find('current_time') - MCDS['metadata'] = {} - MCDS['metadata']['current_time'] = float(time_node.text) - MCDS['metadata']['time_units'] = time_node.get('units') - - # Get current runtime - time_node = metadata_node.find('current_runtime') - MCDS['metadata']['current_runtime'] = float(time_node.text) - MCDS['metadata']['runtime_units'] = time_node.get('units') - - # find the microenvironment node - me_node = root.find('microenvironment') - me_node = me_node.find('domain') - - # find the mesh node - mesh_node = me_node.find('mesh') - MCDS['metadata']['spatial_units'] = mesh_node.get('units') - MCDS['mesh'] = {} - - # while we're at it, find the mesh - coord_str = mesh_node.find('x_coordinates').text - delimiter = mesh_node.find('x_coordinates').get('delimiter') - x_coords = np.array(coord_str.split(delimiter), dtype=np.float) - - coord_str = mesh_node.find('y_coordinates').text - delimiter = mesh_node.find('y_coordinates').get('delimiter') - y_coords = np.array(coord_str.split(delimiter), dtype=np.float) - - coord_str = mesh_node.find('z_coordinates').text - delimiter = mesh_node.find('z_coordinates').get('delimiter') - z_coords = np.array(coord_str.split(delimiter), dtype=np.float) - - # reshape into a mesh grid - xx, yy, zz = np.meshgrid(x_coords, y_coords, z_coords) - - MCDS['mesh']['x_coordinates'] = xx - MCDS['mesh']['y_coordinates'] = yy - MCDS['mesh']['z_coordinates'] = zz - - # Voxel data must be loaded from .mat file - voxel_file = mesh_node.find('voxels').find('filename').text - voxel_path = output_path / voxel_file - try: - initial_mesh = sio.loadmat(voxel_path)['mesh'] - except: - raise FileNotFoundError( - "No such file or directory:\n'{}' referenced in '{}'".format(voxel_path, xml_file)) - sys.exit(1) - - print('Reading {}'.format(voxel_path)) - - # center of voxel specified by first three rows [ x, y, z ] - # volume specified by fourth row - MCDS['mesh']['voxels'] = {} - MCDS['mesh']['voxels']['centers'] = initial_mesh[:3, :] - MCDS['mesh']['voxels']['volumes'] = initial_mesh[3, :] - - # Continuum_variables, unlike in the matlab version the individual chemical - # species will be primarily accessed through their names e.g. - # MCDS['continuum_variables']['oxygen']['units'] - # MCDS['continuum_variables']['glucose']['data'] - MCDS['continuum_variables'] = {} - variables_node = me_node.find('variables') - file_node = me_node.find('data').find('filename') - - # micro environment data is shape [4+n, len(voxels)] where n is the number - # of species being tracked. the first 3 rows represent (x, y, z) of voxel - # centers. The fourth row contains the voxel volume. The 5th row and up will - # contain values for that species in that voxel. - me_file = file_node.text - me_path = output_path / me_file - # Changes here - try: - me_data = sio.loadmat(me_path)['multiscale_microenvironment'] - except: - raise FileNotFoundError( - "No such file or directory:\n'{}' referenced in '{}'".format(me_path, xml_file)) - sys.exit(1) - - print('Reading {}'.format(me_path)) - - var_children = variables_node.findall('variable') - - # we're going to need the linear x, y, and z coordinates later - # but we dont need to get them in the loop - X, Y, Z = np.unique(xx), np.unique(yy), np.unique(zz) - - for si, species in enumerate(var_children): - species_name = species.get('name') - MCDS['continuum_variables'][species_name] = {} - MCDS['continuum_variables'][species_name]['units'] = species.get( - 'units') - - print('Parsing {:s} data'.format(species_name)) - - # initialize array for concentration data - MCDS['continuum_variables'][species_name]['data'] = np.zeros(xx.shape) - - # travel down one level on tree - species = species.find('physical_parameter_set') - - # diffusion data for each species - MCDS['continuum_variables'][species_name]['diffusion_coefficient'] = {} - MCDS['continuum_variables'][species_name]['diffusion_coefficient']['value'] \ - = float(species.find('diffusion_coefficient').text) - MCDS['continuum_variables'][species_name]['diffusion_coefficient']['units'] \ - = species.find('diffusion_coefficient').get('units') - - # decay data for each species - MCDS['continuum_variables'][species_name]['decay_rate'] = {} - MCDS['continuum_variables'][species_name]['decay_rate']['value'] \ - = float(species.find('decay_rate').text) - MCDS['continuum_variables'][species_name]['decay_rate']['units'] \ - = species.find('decay_rate').get('units') - - # store data from microenvironment file as numpy array - # iterate over each voxel - for vox_idx in range(MCDS['mesh']['voxels']['centers'].shape[1]): - # find the center - center = MCDS['mesh']['voxels']['centers'][:, vox_idx] - - i = np.where(np.abs(center[0] - X) < 1e-10)[0][0] - j = np.where(np.abs(center[1] - Y) < 1e-10)[0][0] - k = np.where(np.abs(center[2] - Z) < 1e-10)[0][0] - - MCDS['continuum_variables'][species_name]['data'][j, i, k] \ - = me_data[4+si, vox_idx] - - # in order to get to the good stuff we have to pass through a few different - # hierarchal levels - cell_node = root.find('cellular_information') - cell_node = cell_node.find('cell_populations') - cell_node = cell_node.find('cell_population') - cell_node = cell_node.find('custom') - # we want the PhysiCell data, there is more of it - for child in cell_node.findall('simplified_data'): - if child.get('source') == 'PhysiCell': - cell_node = child - break - - print( 'working on discrete cell data...\n') - - MCDS['discrete_cells'] = {} - data_labels = [] - # iterate over 'label's which are children of 'labels' these will be used to - # label data arrays - n = 0; - for label in cell_node.find('labels').findall('label'): - # I don't like spaces in my dictionary keys - fixed_label = label.text.replace(' ', '_') - nlabels = int(label.get('size')) - if nlabels > 1: - # tags to differentiate repeated labels (usually space related) - print("n=",n) - if( nlabels == 3 ): - dir_label = ['_x', '_y', '_z'] - else: - dir_label = []; - for nn in range(100): - dir_label.append( '_%u' % nn ) - print("dir_label= ", dir_label ) - print("label= ",label) - print("label.get('size')= ",nlabels) - for i in range(nlabels): - print( fixed_label + dir_label[i] ) - data_labels.append(fixed_label + dir_label[i]) - else: - data_labels.append(fixed_label) - print(fixed_label) - n += 1 - # load the file - cell_file = cell_node.find('filename').text - cell_path = output_path / cell_file - try: - cell_data = sio.loadmat(cell_path)['cells'] - except: - raise FileNotFoundError( - "No such file or directory:\n'{}' referenced in '{}'".format(cell_path, xml_file)) - sys.exit(1) - - print('Reading {}'.format(cell_path)) - - for col in range(len(data_labels)): - MCDS['discrete_cells'][data_labels[col]] = cell_data[col, :] - - return MCDS