BioFVM warmup: 2D continuum simulation of tumor growth

Note: This is part of a series of “how-to” blog posts to help new users and developers of BioFVM. See also the guides to setting up a C++ compiler in Windows or OSX.

What you’ll need

1. A working C++ development environment with support for OpenMP. See these prior tutorials if you need help.
2. A download of BioFVM, available at http://BioFVM.MathCancer.org and http://BioFVM.sf.net. Use Version 1.0.3 or later.
3. Matlab or Octave for visualization. Matlab might be available for free at your university. Octave is open source and available from a variety of sources.

We will implement a basic 2-D model of tumor growth in a heterogeneous microenvironment, with inspiration by glioblastoma models by Kristin Swanson, Russell Rockne and others (e.g., this work), and continuum tumor growth models by Hermann Frieboes, John Lowengrub, and our own lab (e.g., this paper and this paper).

We will model tumor growth driven by a growth substrate, where cells die when the growth substrate is insufficient. The tumor cells will have motility. A continuum blood vasculature will supply the growth substrate, but tumor cells can degrade this existing vasculature. We will revisit and extend this model from time to time in future tutorials.

Mathematical model

Taking inspiration from the groups mentioned above, we’ll model a live cell density ρ of a relatively low-adhesion tumor cell species (e.g., glioblastoma multiforme). We’ll assume that tumor cells move randomly towards regions of low cell density (modeled as diffusion with motility μ). We’ll assume that that the net birth rate rB is proportional to the concentration of growth substrate σ, which is released by blood vasculature with density b. Tumor cells can degrade the tissue and hence this existing vasculature. Tumor cells die at rate rD when the growth substrate level is too low. We assume that the tumor cell density cannot exceed a max level ρmax. A model that includes these effects is:

$\frac{ \partial \rho}{\partial t} = \mu \nabla^2 \rho + r_B(\sigma)\rho \left( 1 – \frac{ \rho}{\rho_\textrm{max}} \right) – r_D(\sigma) \rho$

$\frac{ \partial b}{\partial t} = – r_\textrm{degrade} \rho b$

$\frac{\partial \sigma}{ \partial t} = D\nabla^2 \sigma – \lambda_a \sigma – \lambda_2 \rho \sigma + r_\textrm{deliv}b \left( \sigma_\textrm{max} – \sigma \right)$
where for the birth and death rates, we’ll use the constitutive relations:
$r_B(\sigma) = r_B \textrm{ max} \left( \frac{\sigma – \sigma_\textrm{min}}{ \sigma_\textrm{ max} – \sigma_\textrm{min} } , 0 \right)$
$r_D(\sigma) = r_D \textrm{ max} \left( \frac{ \sigma_\textrm{min} – \sigma}{\sigma_\textrm{min}} , 0 \right)$

Mapping the model onto BioFVM

BioFVM solves on a vector u of substrates. We’ll set u = [ρ , b, σ ]. The code expects PDEs of the general form:

$\frac{\partial q}{\partial t} = D\nabla^2 q – \lambda q + S\left( q^* – q \right) – Uq$
So, we determine the decay rate (λ), source function (S), and uptake function (U) for the cell density ρ and the growth substrate σ.

Cell density

We first slightly rewrite the PDE:

$\frac{ \partial \rho}{\partial t} = \mu \nabla^2 \rho + r_B(\sigma) \frac{ \rho}{\rho_\textrm{max}} \left( \rho_\textrm{max} – \rho \right) – r_D(\sigma)\rho$
and then try to match to the general form term-by-term. While BioFVM wasn’t intended for solving nonlinear PDEs of this form, we can make it work by quasi-linearizing, with the following functions:
$S = r_B(\sigma) \frac{ \rho }{\rho_\textrm{max}} \hspace{1in} U = r_D(\sigma).$

When implementing this, we’ll evaluate σ and ρ at the previous time step. The diffusion coefficient is μ, and the decay rate is zero. The target or saturation density is ρmax.

Growth substrate

Similarly, by matching the PDE for σ term-by-term with the general form, we use:

$S = r_\textrm{deliv}b, \hspace{1in} U = \lambda_2 \rho.$

The diffusion coefficient is D, the decay rate is λ1, and the saturation density is σmax.

Blood vessels

Lastly, a term-by-term matching of the blood vessel equation gives the following functions:

$S=0 \hspace{1in} U = r_\textrm{degrade}\rho.$
The diffusion coefficient, decay rate, and saturation density are all zero.

Implementation in BioFVM

1. Start a project: Create a new directory for your project (I’d recommend “BioFVM_2D_tumor”), and enter the directory. Place a copy of BioFVM (the zip file) into your directory. Unzip BioFVM, and copy BioFVM*.h, BioFVM*.cpp, and pugixml* files into that directory.
2. Copy the matlab visualization files: To help read and plot BioFVM data, we have provided matlab files. Copy all the *.m files from the matlab subdirectory to your project.
3. Copy the empty project: BioFVM Version 1.0.3 or later includes a template project and Makefile to make it easier to get started. Copy the Makefile and template_project.cpp file to your project. Rename template_project.cpp to something useful, like 2D_tumor_example.cpp.
4. Edit the makefile: Open a terminal window and browse to your project. Tailor the makefile to your new project:
notepad++ Makefile

Change the PROGRAM_NAME to 2Dtumor.

Also, rename main to 2D_tumor_example throughout the Makefile.

Lastly, note that if you are using OSX, you’ll probably need to change from “g++” to your installed compiler. See these tutorials.

5. Start adapting 2D_tumor_example.cpp: First, open 2D_tumor_example.cpp:
notepad++ 2D_tumor_example.cpp

Just after the “using namespace BioFVM” section of the code, define useful globals. Here and throughout, new and/or modified code is in blue:

using namespace BioFVM:

// helpful -- have indices for each "species"
int live_cells  = 0;
int blood_vessels = 1;
int oxygen    = 2;

// some globals
double prolif_rate = 1.0 /24.0;
double death_rate = 1.0 / 6; //
double cell_motility = 50.0 / 365.25 / 24.0 ;
// 50 mm^2 / year --> mm^2 / hour
double o2_uptake_rate = 3.673 * 60.0; // 165 micron length scale
double vessel_degradation_rate = 1.0 / 2.0 / 24.0 ;
// 2 days to disrupt tissue

double max_cell_density = 1.0;

double o2_supply_rate = 10.0;
double o2_normoxic  = 1.0;
double o2_hypoxic   = 0.2;

6. Set up the microenvironment: Within main(), make sure we have the right number of substrates, and set them up:
// create a microenvironment, and set units

Microenvironment M;
M.name = "Tumor microenvironment";
M.time_units = "hr";
M.spatial_units = "mm";
M.mesh.units = M.spatial_units;

// set up and add all the densities you plan

M.set_density( 0 , "live cells" , "cells" );
M.add_density( "blood vessels" , "vessels/mm^2" );

// set the properties of the diffusing substrates

M.diffusion_coefficients[live_cells] = cell_motility;

M.diffusion_coefficients[blood_vessels] = 0;
M.diffusion_coefficients[oxygen] = 6.0;

// 1e5 microns^2/min in units mm^2 / hr

M.decay_rates[live_cells] = 0;
M.decay_rates[blood_vessels] = 0;
M.decay_rates[oxygen] = 0.01 * o2_uptake_rate;
// 1650 micron length scale


Notice how our earlier global definitions of “live_cells”, “blood_vessels”, and “oxygen” makes it easier to make sure we’re referencing the correct substrates in lines like these.

7. Resize the domain and test: For this example (and so the code runs very quickly), we’ll work in 2D in a 2 cm × 2 cm domain:
// set the mesh size

double dx = 0.05; // 50 microns
M.resize_space( 0.0 , 20.0 , 0, 20.0 , -dx/2.0, dx/2.0 , dx, dx, dx );


Notice that we use a tissue thickness of dx/2 to use the 3D code for a 2D simulation. Now, let’s test:

make
2Dtumor


Go ahead and cancel the simulation [Control]+C after a few seconds. You should see something like this:

Starting program ...

Microenvironment summary: Tumor microenvironment:

Mesh information:
type: uniform Cartesian
Domain: [0,20] mm x [0,20] mm x [-0.025,0.025] mm
resolution: dx = 0.05 mm
voxels: 160000
voxel faces: 0
volume: 20 cubic mm
Densities: (3 total)
live cells:
units: cells
diffusion coefficient: 0.00570386 mm^2 / hr
decay rate: 0 hr^-1
diffusion length scale: 75523.9 mm

blood vessels:
units: vessels/mm^2
diffusion coefficient: 0 mm^2 / hr
decay rate: 0 hr^-1
diffusion length scale: 0 mm

oxygen:
units: cells
diffusion coefficient: 6 mm^2 / hr
decay rate: 2.2038 hr^-1
diffusion length scale: 1.65002 mm

simulation time: 0 hr (100 hr max)

Using method diffusion_decay_solver__constant_coefficients_LOD_3D (implicit 3-D LOD with Thomas Algorithm) ...

simulation time: 10 hr (100 hr max)
simulation time: 20 hr (100 hr max)

8. Set up initial conditions: We’re going to make a small central focus of tumor cells, and a “bumpy” field of blood vessels.
// set initial conditions
// use this syntax to create a zero vector of length 3
// std::vector<double> zero(3,0.0);

std::vector<double> center(3);
center[0] = M.mesh.x_coordinates[M.mesh.x_coordinates.size()-1] /2.0;
center[1] = M.mesh.y_coordinates[M.mesh.y_coordinates.size()-1] /2.0;
center[2] = 0;

std::vector<double> one( M.density_vector(0).size() , 1.0 );

double pi = 2.0 * asin( 1.0 );

// use this syntax for a parallelized loop over all the
#pragma omp parallel for
for( int i=0; i < M.number_of_voxels() ; i++ )
{
std::vector<double> displacement = M.voxels(i).center – center;
double distance = norm( displacement );

{
M.density_vector(i)[live_cells] = 0.1;
}
M.density_vector(i)[blood_vessels]= 0.5
+ 0.5*cos(0.4* pi * M.voxels(i).center[0])*cos(0.3*pi *M.voxels(i).center[1]);
M.density_vector(i)[oxygen] = o2_normoxic;
}

9. Change to a 2D diffusion solver:
// set up the diffusion solver, sources and sinks

M.diffusion_decay_solver = diffusion_decay_solver__constant_coefficients_LOD_2D;

10. Set the simulation times: We’ll simulate 10 days, with output every 12 hours.
double t = 0.0;
double t_max = 10.0 * 24.0; // 10 days
double dt = 0.1;

double output_interval = 12.0; // how often you save data
double next_output_time = t; // next time you save data

11. Set up the source function:
void supply_function( Microenvironment* microenvironment, int voxel_index, std::vector<double>* write_here )
{
// use this syntax to access the jth substrate write_here
// (*write_here)[j]
// use this syntax to access the jth substrate in voxel voxel_index of microenvironment:
// microenvironment->density_vector(voxel_index)[j]

static double temp1 = prolif_rate / ( o2_normoxic – o2_hypoxic );

(*write_here)[live_cells] =
microenvironment->density_vector(voxel_index)[oxygen];
(*write_here)[live_cells] -= o2_hypoxic;

if( (*write_here)[live_cells] < 0.0 )
{
(*write_here)[live_cells] = 0.0;
}
else
{
(*write_here)[live_cells] = temp1;
(*write_here)[live_cells] *=
microenvironment->density_vector(voxel_index)[live_cells];
}

(*write_here)[blood_vessels] = 0.0;
(*write_here)[oxygen] = o2_supply_rate;
(*write_here)[oxygen] *=
microenvironment->density_vector(voxel_index)[blood_vessels];

return;
}


Notice the use of the static internal variable temp1: the first time this function is called, it declares this helper variable (to save some multiplication operations down the road). The static variable is available to all subsequent calls of this function.

12. Set up the target function (substrate saturation densities):
void supply_target_function( Microenvironment* microenvironment, int voxel_index, std::vector<double>* write_here )
{
// use this syntax to access the jth substrate write_here
// (*write_here)[j]
// use this syntax to access the jth substrate in voxel voxel_index of microenvironment:
// microenvironment->density_vector(voxel_index)[j]

(*write_here)[live_cells] = max_cell_density;
(*write_here)[blood_vessels] =  1.0;
(*write_here)[oxygen] = o2_normoxic;

return;
}

13. Set up the uptake function:
void uptake_function( Microenvironment* microenvironment, int voxel_index,
std::vector<double>* write_here )
{
// use this syntax to access the jth substrate write_here
// (*write_here)[j]
// use this syntax to access the jth substrate in voxel voxel_index of microenvironment:
// microenvironment->density_vector(voxel_index)[j]

(*write_here)[live_cells] = o2_hypoxic;
(*write_here)[live_cells] -=
microenvironment->density_vector(voxel_index)[oxygen];
if( (*write_here)[live_cells] < 0.0 )
{
(*write_here)[live_cells] = 0.0;
}
else
{
(*write_here)[live_cells] *= death_rate;
}

(*write_here)[oxygen] = o2_uptake_rate ;
(*write_here)[oxygen] *=
microenvironment->density_vector(voxel_index)[live_cells];

(*write_here)[blood_vessels] *=
microenvironment->density_vector(voxel_index)[live_cells];

return;
}


And that’s it. The source should be ready to go!

Using the code

Running the code

First, compile and run the code:

make
2Dtumor


The output should look like this.

Starting program …

Microenvironment summary: Tumor microenvironment:

Mesh information:
type: uniform Cartesian
Domain: [0,20] mm x [0,20] mm x [-0.025,0.025] mm
resolution: dx = 0.05 mm
voxels: 160000
voxel faces: 0
volume: 20 cubic mm
Densities: (3 total)
live cells:
units: cells
diffusion coefficient: 0.00570386 mm^2 / hr
decay rate: 0 hr^-1
diffusion length scale: 75523.9 mm

blood vessels:
units: vessels/mm^2
diffusion coefficient: 0 mm^2 / hr
decay rate: 0 hr^-1
diffusion length scale: 0 mm

oxygen:
units: cells
diffusion coefficient: 6 mm^2 / hr
decay rate: 2.2038 hr^-1
diffusion length scale: 1.65002 mm

simulation time: 0 hr (240 hr max)

Using method diffusion_decay_solver__constant_coefficients_LOD_2D (2D LOD with Thomas Algorithm) …

simulation time: 12 hr (240 hr max)
simulation time: 24 hr (240 hr max)
simulation time: 36 hr (240 hr max)
simulation time: 48 hr (240 hr max)
simulation time: 60 hr (240 hr max)
simulation time: 72 hr (240 hr max)
simulation time: 84 hr (240 hr max)
simulation time: 96 hr (240 hr max)
simulation time: 108 hr (240 hr max)
simulation time: 120 hr (240 hr max)
simulation time: 132 hr (240 hr max)
simulation time: 144 hr (240 hr max)
simulation time: 156 hr (240 hr max)
simulation time: 168 hr (240 hr max)
simulation time: 180 hr (240 hr max)
simulation time: 192 hr (240 hr max)
simulation time: 204 hr (240 hr max)
simulation time: 216 hr (240 hr max)
simulation time: 228 hr (240 hr max)
simulation time: 240 hr (240 hr max)
Done!


Looking at the data

Now, let’s pop it open in matlab (or octave):

matlab


To load and plot a single time (e.g., the last tim)

!ls *.mat
plot_microenvironment( M );


labels{1} = 'tumor cells';
labels{2} = 'blood vessel density';
labels{3} = 'growth substrate';
plot_microenvironment( M ,labels );


Your output should look a bit like this:

Lastly, you might want to script the code to create and save plots of all the times.

labels{1} = 'tumor cells';
labels{2} = 'blood vessel density';
labels{3} = 'growth substrate';
for i=0:20
t = i*12;
input_file = sprintf( 'output_%3.6f.mat', t );
output_file = sprintf( 'output_%3.6f.png', t );
plot_microenvironment( M , labels );
print( gcf , '-dpng' , output_file );
end


What’s next

We’ll continue posting new tutorials on adapting BioFVM to existing and new simulators, as well as guides to new features as we roll them out.
Stay tuned and watch this blog!

Setting up gcc / OpenMP on OSX (Homebrew edition)

Note: This is part of a series of “how-to” blog posts to help new users and developers of BioFVM and PhysiCell. This guide is for OSX users. Windows users should use this guide instead. A Linux guide is expected soon.

These instructions should get you up and running with a minimal environment for compiling 64-bit C++ projects with OpenMP (e.g., BioFVM and PhysiCell) using gcc. These instructions were tested with OSX 10.11 (El Capitan) and 10.12 (Sierra), but they should work on any reasonably recent version of OSX.

In the end result, you’ll have a compiler and key makefile capabilities. The entire toolchain is free and open source.

Of course, you can use other compilers and more sophisticated integrated desktop environments, but these instructions will get you a good baseline system with support for 64-bit binaries and OpenMP parallelization.

Note 1: OSX / Xcode appears to have gcc out of the box (you can type “gcc” in a Terminal window), but this really just maps back onto Apple’s build of clang. Alas, this will not support OpenMP for parallelization.

Note 2: In this post, we showed how to set up gcc using the popular MacPorts package manager. Because MacPorts builds gcc (and all its dependencies!) from source, it takes a very, very long time. On my 2012 Macbook Air, this step took 16 hours.  This tutorial uses Homebrew to dramatically speed up the process!

Note 3: This is an update over the previous version. It incorporates new information that Xcode command line tools can be installed without the full 4.41 GB download / installation of Xcode. Many thanks to Walter de Back and Tim at the Homebrew project for their help!

What you’ll need:

• XCode Command Line Tools: These command line tools are needed for Homebrew and related package managers. Installation instructions are now very simple and included below. As of January 18, 2016, this will install Version 2343.
• Homebrew: This is a package manager for OSX, which will let you easily download and install many linux utilities without building them from source. You’ll particularly need it for getting gcc. Installation is a simple command-line script, as detailed below. As of August 2, 2017, this will download Version 1.3.0.
• gcc (from Homebrew): This will be an up-to-date 64-bit version of gcc, with support for OpenMP. As of August 2, 2017, this will download Version 7.1.0.

Main steps:

1) Install the XCode Command Line Tools

Open a terminal window (Open Launchpad, then “Other”, then “Terminal”), and run:

user$xcode-select --install  A window should pop up asking you to either get Xcode or install. Choose the “install” option to avoid the huge 4+ GB Xcode download. It should only take a few minutes to complete. 2) Install Homebrew Open a terminal window (Open Launchpad, then “Other”, then “Terminal”), and run: user$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"  Let the script run, and answer “y” whenever asked. This will not take very long. 3) Get, install, and prepare gcc Open a terminal window (see above), and search for gcc, version 7.x or above user$ brew search gcc


You should see a list of packages, including gcc7. (In 2015, this looked like “gcc5”. In 2017, this looks like “gcc@7”.)

user$brew install gcc  This will download whatever dependencies are needed, generally already pre-compiled. The whole process should only take five or ten minutes. Lastly, you need to get the exact name of your compiler. In your terminal window, type g++, and then hit tab twice to see a list. On my system, I see this: Pauls-MBA:~ pmacklin$ g++
g++       g++-7     g++-mp-7


Look for the version of g++ without an “mp” (from MacPorts) in its name. In my case, it’s g++-7. Double-check that you have the right one by checking its version. It should look something like this:

Pauls-MBA:~ pmacklin$g++-7 --version g++-7 (Homebrew GCC 7.1.0) 7.1.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Notice that Homebrew shows up in the information. The correct compiler is g++-7. PhysiCell Version 1.2.2 and greater use a system variable to record your compiler version, so that you don’t need to modify the CC line in PhysiCell Makefiles. Set the PHYSICELL_CPP variable to record the compiler you just found above. For example, on the bash shell: export PHYSICELL_CPP=g++-7 echo export PHYSICELL_CPP=g++-7 >> ~/.bash_profile  One last thing: If you don’t update your paths, make will may fail as it continues to combine Apple’s “gcc” toolchain with real gcc. (This seems to happen most often if you installed an older gcc like gcc5 with MacPorts earlier.) You may see errors like this: user$ make
g++-7 -march=core2 -O3 -fomit-frame-pointer -fopenmp -std=c++11 -c BioFVM_vector.cpp
FATAL:/opt/local/bin/../libexec/as/x86_64/as: I don't understand 'm' flag!
make: *** [BIOFVM_vector.o] Error 1


To avoid this, run:

echo export PATH=/usr/local/bin:$PATH >> ~/.bash_profile  Note that you’ll need to open a new Terminal window for this fix to apply. 4) Test your setup I wrote a sample C++ program that tests OpenMP parallelization (32 threads). If you can compile and run it, it means that everything (including make) is working! 🙂 Make a new directory, and enter it Open Terminal (see above). You should be in your user profile’s root directory. Make a new subdirectory called GCC_test, and enter it. mkdir GCC_test cd GCC_test Grab a sample parallelized program: Download a Makefile and C++ source file, and save them to the GCC_test directory. Here are the links: 1. Makefile: [click here] 2. C++ source: [click here] Note: The Makefiles in PhysiCell (versions > 1.2.1) can use an environment variable to specify an OpenMP-capable g++ compiler. If you have not yet done so, you should go ahead and set that now, e.g., for the bash shell: export PHYSICELL_CPP=g++-7 echo export PHYSICELL_CPP=g++-7 >> ~/.bash_profile  Compile and run the test: Go back to your (still open) command prompt. Compile and run the program: make ./my_test  The output should look something like this: Allocating 4096 MB of memory ... Done! Entering main loop ... Done!  Note 1: If the make command gives errors like “**** missing separator”, then you need to replace the white space (e.g., one or more spaces) at the start of the “$(COMPILE_COMMAND)” and “rm -f” lines with a single tab character.

Note 2: If the compiler gives an error like “fatal error: ‘omp.h’ not found”, you probably used Apple’s build of clang, which does not include OpenMP support. You’ll need to make sure that you set the environment variable PHYSICELL_CPP as above (for PhysiCell 1.2.2 or later), or specify your compiler on the CC line of your makefile (for PhysiCell 1.2.1 or earlier).

Now, let’s verify that the code is using OpenMP.

Open another Terminal window. While the code is running, run top. Take a look at the performance, particularly CPU usage. While your program is running, you should see CPU usage fairly close to ‘100% user’. (This is a good indication that your code is running the OpenMP parallelization as expected.)

What’s next?

Download a copy of PhysiCell and try out the included examples! Visit BioFVM at MathCancer.org.

1. PhysiCell Method Paper at bioRxiv: https://doi.org/10.1101/088773
2. PhysiCell on MathCancer: http://PhysiCell.MathCancer.org
3. PhysiCell on SourceForge: http://PhysiCell.sf.net
4. PhysiCell on github: http://github.com/MathCancer/PhysiCell
2. BioFVM on MathCancer.org: http://BioFVM.MathCancer.org
3. BioFVM on SourceForge: http://BioFVM.sf.net
4. BioFVM Method Paper in BioInformatics: http://dx.doi.org/10.1093/bioinformatics/btv730

Setting up gcc / OpenMP on OSX (Homebrew edition) (outdated)

Note 1: This is the part of a series of “how-to” blog posts to help new users and developers of BioFVM and PhysiCell. This guide is for OSX users. Windows users should use this guide instead. A Linux guide is expected soon.

Note 2: This tutorial is outdated. Please see this updated version.

These instructions should get you up and running with a minimal environment for compiling 64-bit C++ projects with OpenMP (e.g., BioFVM and PhysiCell) using gcc. These instructions were tested with OSX 10.11 (El Capitan), but they should work on any reasonably recent version of OSX.

In the end result, you’ll have a compiler and key makefile capabilities. The entire toolchain is free and open source.

Of course, you can use other compilers and more sophisticated integrated desktop environments, but these instructions will get you a good baseline system with support for 64-bit binaries and OpenMP parallelization.

Note 3: OSX / Xcode appears to have gcc out of the box (you can type “gcc” in a Terminal window), but this really just maps back onto Apple’s build of clang. Alas, this will not support OpenMP for parallelization.

Note 4: Yesterday in this post, we showed how to set up gcc using the popular MacPorts package manager. Because MacPorts builds gcc (and all its dependencies!) from source, it takes a very, very long time. On my 2012 Macbook Air, this step took 16 hours.  This tutorial uses Homebrew to dramatically speed up the process!

What you’ll need:

• XCode: This includes command line development tools. Evidently, it is required for both Homebrew and its competitors (e.g., MacPorts). Download the latest version in the App Store. (Search for xcode.) As of January 15, 2016, the App Store will install Version 7.2. Please note that this is a 4.41 GB download!
• Homebrew: This is a package manager for OSX, which will let you easily download and install many linux utilities without building them from source. You’ll particularly need it for getting gcc. Installation is a simple command-line script, as detailed below. As of January 17, 2016, this will download Version 0.9.5.
• gcc5 (from Homebrew): This will be an up-to-date 64-bit version of gcc, with support for OpenMP. As of January 17, 2016, this will download Version 5.2.0.

Main steps:

As mentioned above, open the App Store, search for Xcode, and start the download / install. Go ahead and grab a coffee while it’s downloading and installing 4+ GB. Once it has installed, open Xcode, agree to the license, and let it install whatever components it needs.

Now, you need to get the command line tools. Go to the Xcode menu, select “Open Developer Tool”, and choose “More Developer Tools …”. This will open up a site in Safari and prompt you to log in.

Sign on with your AppleID, agree to yet more licensing terms, and then search for “command line tools” for your version of Xcode and OSX. (In my case, this is OSX 10.11 with Xcode 7.2) Click the + next to the correct version, and then the link for the dmg file. (Command_Line_Tools_OS_X_10.11_for_Xcode_7.2.dmg).

Double-click the dmg file. Double-click pkg file it contains. Click “continue”, “OK”, and “agree” as much as it takes to install. Once done, go ahead and exit the installer and close the dmg file.

2) Install Homebrew

Open a terminal window (Open Launchpad, then “Other”, then “Terminal”), and run:

> ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"  Let the script run, and answer “y” whenever asked. This will not take very long. 3) Get, install, and prepare gcc Open a terminal window (see above), and search for gcc, version 5.x or above > brew search gcc5  You should see a list of packages, including gcc5. Take a note of what is found. (In my case, it found homebrew/versions/gcc5.) Then, download and install gcc5: > brew install homebrew/versions/gcc5  This will download whatever dependencies are needed, generally already pre-compiled. The whole process should only take five or ten minutes. Lastly, you need to get the exact name of your compiler. In your terminal window, type g++, and then hit tab twice to see a list. On my system, I see this: Pauls-MBA:~ pmacklin$ g++
g++       g++-5       g++-mp-5


Look for the version of g++ without an “mp” (for MacPorts) in its name. In my case, it’s g++-5. Double-check that you have the right one by checking its version. It should look something like this:

Pauls-MBA:~ pmacklin$g++-5 --version g++-5 (Homebrew gcc5 5.2.0) 5.2.0 Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Notice that Homebrew shows up in the information. The correct compiler is g++-5. 5) Test the compiler Write a basic parallelized program: Open Terminal (see above). You should be in your user profile’s root directory. Make a new subdirectory, enter it, and create a new file: > mkdir omp_test > cd omp_test > nano omp_test.cpp  Then, write your basic OpenMP test: #include <iostream> #include <cmath> #include <vector> #include <omp.h> int main( int argc, char* argv[] ) { omp_set_num_threads( 8 ); double pi = acos( -1.0 ); std::cout << "Allocating memory ..." << std::endl; std::vector<double> my_vector( 128000000, 0.0 ); std::cout << "Done!" << std::endl << std::endl; std::cout << "Entering main loop ... " << std::endl; #pragma omp parallel for for( int i=0; i < my_vector.size(); i++ ) { my_vector[i] = exp( -sin( i*i + pi*log(i+1) ) ); } std::cout << "Done!" << std::endl; return 0; }  Save the file (as omp_test.cpp). (In nano, use [Control]+X, Y, and then confirm the choice of filename.) In the omp_set_num_threads() line above, replace 8 with the maximum number of virtual processors on your CPU. (For a quad-core CPU with hyperthreading, this number is 8. On a hex-core CPU without hyperthreading, this number is 6.) If in doubt, leave it alone for now. Write a makefile: Next, create a Makefile to start editing: > nano Makefile  Add the following contents: CC := g++-5 # replace this with your correct compiler as identified above ARCH := core2 # Replace this with your CPU architecture. # core2 is pretty safe for most modern machines. CFLAGS := -march=$(ARCH) -O3 -fopenmp -m64 -std=c++11

COMPILE_COMMAND := $(CC)$(CFLAGS)

OUTPUT := my_test

all: omp_test.cpp
$(COMPILE_COMMAND) -o$(OUTPUT) omp_test.cpp

clean:
rm -f *.o $(OUTPUT).*  Go ahead and save this (as Makefile). ([Control]-X, Y, confirm the filename.) Compile and run the test: Go back to your (still open) command prompt. Compile and run the program: > make > ./my_test  The output should look something like this: Allocating memory ... Done! Entering main loop ... Done!  Note 1: If the make command gives errors like “**** missing separator”, then you need to replace the white space (e.g., one or more spaces) at the start of the “$(COMPILE_COMMAND)” and “rm -f” lines with a single tab character.

Note 2: If the compiler gives an error like “fatal error: ‘omp.h’ not found”, you probably used Apple’s build of clang, which does not include OpenMP support. You’ll need to make sure that you specify your compiler on the CC line of your makefile.

Now, let’s verify that the code is using OpenMP.

Open another Terminal window. While the code is running, run top. Take a look at the performance, particularly CPU usage. While your program is running, you should see CPU usage fairly close to ‘100% user’. (This is a good indication that your code is running the OpenMP parallelization as expected.)

What’s next?

Download a copy of BioFVM and try out the included examples! Visit BioFVM at MathCancer.org.

2. BioFVM on MathCancer.org: http://BioFVM.MathCancer.org
3. BioFVM on SourceForge: http://BioFVM.sf.net
4. BioFVM Method Paper in BioInformatics: http://dx.doi.org/10.1093/bioinformatics/btv730

Setting up gcc / OpenMP on OSX (MacPorts edition)

Note: This is the part of a series of “how-to” blog posts to help new users and developers of BioFVM and PhysiCell. This guide is for OSX users. Windows users should use this guide instead. A Linux guide is expected soon.

These instructions should get you up and running with a minimal environment for compiling 64-bit C++ projects with OpenMP (e.g., BioFVM and PhysiCell) using gcc. These instructions were tested with OSX 10.11 (El Capitan), but they should work on any reasonably recent version of OSX.

In the end result, you’ll have a compiler and key makefile capabilities. The entire toolchain is free and open source.

Of course, you can use other compilers and more sophisticated integrated desktop environments, but these instructions will get you a good baseline system with support for 64-bit binaries and OpenMP parallelization.

Note 1: OSX / Xcode appears to have gcc out of the box (you can type “gcc” in a Terminal window), but this really just maps back onto Apple’s build of clang. Alas, this will not support OpenMP for parallelization.

Note 2: This process is somewhat painful because MacPorts compiles everything from source, rather than using pre-compiled binaries. This tutorial uses Homebrew: a newer package manager that uses pre-compiled binaries to dramatically speed up the process. I highly recommend using the Homebrew version of this tutorial.

What you’ll need:

1. XCode: This includes command line development tools. Evidently, it is required for both Macports and its competitors (e.g., Homebrew). Download the latest version in the App Store. (Search for xcode.) As of January 15, 2016, the App Store will install Version 7.2. Please note that this is a 4.41 GB download!
2. MacPorts: This is a package manager for OSX, which will let you easily download, build and install many linux utilities. You’ll particularly need it for getting gcc. Download the latest installer (MacPorts-2.3.4-10.11-ElCapitan.pkg) here. As of August 2, 2017, this will download Version 2.4.1.
3. gcc7 (from MacPorts): This will be an up-to-date 64-bit version of gcc, with support for OpenMP. As of August 2, 2017, this will download Version 7.1.1.

Main steps:

As mentioned above, open the App Store, search for Xcode, and start the download / install. Go ahead and grab a coffee while it’s downloading and installing 4+ GB. Once it has installed, open Xcode, agree to the license, and let it install whatever components it needs.

Now, you need to get the command line tools. Go to the Xcode menu, select “Open Developer Tool”, and choose “More Developer Tools …”. This will open up a site in Safari and prompt you to log in.

Sign on with your AppleID, agree to yet more licensing terms, and then search for “command line tools” for your version of Xcode and OSX. (In my case, this is OSX 10.11 with Xcode 7.2) Click the + next to the correct version, and then the link for the dmg file. (Command_Line_Tools_OS_X_10.11_for_Xcode_7.2.dmg).

Double-click the dmg file. Double-click pkg file it contains. Click “continue”, “OK”, and “agree” as much as it takes to install. Once done, go ahead and exit the installer and close the dmg file.

2) Install Macports

Double-click the MacPorts pkg file you downloaded above. OSX may complain with a message like this:

“MacPorts-2.4.1-10.11-ElCapitan.pkg” can’t be opened because it is from an unidentified developer.

If so, follow the directions here.

Leave all the default choices as they are in the installer. Click OK a bunch of times. The package scripts might take awhile.

Open a terminal window (Open Launchpad, then “Other”, then “Terminal”), and run:

sudo port -v selfupdate


to make sure that everything is up-to-date.

3) Get, install, and prepare gcc

Open a terminal window (see above), and search for gcc, version 7.x or above

port search gcc7


You should see a list of packages, including gcc7.

sudo port install gcc7


You should see a list of packages, including gcc7.

This will download, build, and install any dependencies necessary for gcc7, including llvm and many, many other things. This takes even longer than the 4.4 GB download of Xcode. Go get dinner and a coffee. You may well need to let this run overnight. (On my 2012 Macbook Air, it required 16 hours to fully build gcc7 and its dependencies in a prior tutorial. We’ll discuss this point further below.)

Lastly, you need to get the exact name of your compiler. In your terminal window, type g++, and then hit tab twice to see a list. On my system, I see this:

Pauls-MBA:~ pmacklin$g++ g++ g++-mp-7  Look for the version of g++ with an “mp” in its name. In my case, it’s g++-mp-7. Double-check that you have the right one by checking its version. It should look something like this: Pauls-MBA:~ pmacklin$ g++-mp-7 --version

g++-mp-7 (MacPorts gcc7 7-20170622_0) 7.1.1 20170622
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO warranty; not even
for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Notice that MacPorts shows up in the information. The correct compiler is g++-mp-7.

PhysiCell Version 1.2.2 and greater use a system variable to record your compiler version, so that you don’t need to modify the CC line in PhysiCell Makefiles. Set the PHYSICELL_CPP variable to record the compiler you just found above. For example, on the bash shell:

export PHYSICELL_CPP=g++-mp-7
echo export PHYSICELL_CPP=g++-mp-7 >> ~/.bash_profile


I wrote a sample C++ program that tests OpenMP parallelization (32 threads). If you can compile and run it, it means that everything (including make) is working! 🙂

Make a new directory, and enter it

Open Terminal (see above). You should be in your user profile’s root directory. Make a new subdirectory called GCC_test, and enter it.

mkdir GCC_test
cd GCC_test
Grab a sample parallelized program:

Download a Makefile and C++ source file, and save them to the GCC_test directory. Here are the links:

Note: The Makefiles in PhysiCell (versions > 1.2.1) can use an environment variable to specify an OpenMP-capable g++ compiler. If you have not yet done so, you should go ahead and set that now, e.g., for the bash shell:

export PHYSICELL_CPP=g++-mp-7
echo export PHYSICELL_CPP=g++-mp-7 >> ~/.bash_profile

Compile and run the test:

Go back to your (still open) command prompt. Compile and run the program:

make
./my_test


The output should look something like this:

Allocating 4096 MB of memory ...
Done!

Entering main loop ...
Done!


What’s next?

Download a copy of PhysiCell and try out the included examples! Visit BioFVM at MathCancer.org.