Package nlisim
A multiscale simulation framework of Aspergillus fumigatus.
Introduction
Installing
While not required, it is recommended you use pipenv to create an isolated environment for running and developing. To do so, run
pipenv install --dev
See pipenv for details.
Once this is done,
you can run pipenv shell to enter the newly created environment.
Running
Run with Python virtual environment
With the simulation package installed, you should have a new command-line
program called nlisim available.
Try running nlisim --help to get
more information.
To run a simulation, you will need configure a configuration.
There is an example configuration in the repository to get you started.
Now run simulation up to 50 hours using the first example config:
nlisim --config config.ini run 50
Run with Docker
As an alternative to local installation, the simulation may be run within a Docker container. This will download the simulation code from the latest published version.
To run the same simulation up to 50 hours using the first example config:
mkdir -p output
docker run \
--rm \
--mount type=bind,source="$(pwd)/config.ini.example",destination=/opt/nlisim/config.ini,readonly \
--mount type=bind,source="$(pwd)/output/",destination=/opt/nlisim/output/ \
nutritionallungimmunity/nlisim run 50
You should now have files like output/simulation-000001.000.hdf5 containing
the simulation state at 1 hour intervals through the full simulation.
Note, since the application requires read access to files,
Docker must mount
them within the container; this example uses --mount to
prevent nonexistent host paths from being accidentally created.
Testing
There is a basic test suite included in the package using tox as a test runner. Try running the tests now with
tox
This will install the simulation code into a new isolated environment and run all of the tests. It will even test against multiple Python versions if you have them installed.
You can selectively run test environments, or add additional options to test environments. Useful sub-commands include:
tox -e lint: Run only the style checks.tox -e type: Run only the type checks.tox -e py3: Run only the unit tests.tox -e py3 -- --cov: Run the unit tests and output coverage information.
Finally, you can run tox -e format to automatically reformat your code to
comply with some (but unfortunately not all) of the style checks.
Code organization
-
state.pyThis module defines classes intended to contain all of the variables that make up the simulation state. An object of the "State" type is passed around through all of the simulation methods.
By design, the state class does not contain any methods that mutate its own data. The state object is primarily a container that can be serialized and deserialized easily for simulation diagnostic output and checkpoints.
-
grid.pyThis module defines a class representing the discretization of the 3D simulation domain. Any variable representing a quantity that exists over the entire spatial domain should be split into chunks defined by this grid. For more details, see
nlisim.grid. -
cell.pyThis module contains high level, but efficient, data structures representing "cells" in the simulation. At minimum, a cell is an object containing two attributes representing the position of the cell in the domain and whether or not it is alive. This data structure is intended to be extended by modules to create cells with additional attributes and behavior.
-
config.pyThis module defines a subclass of a Python ConfigParser which parses ".ini" style files for runtime configuration of the simulation. While not currently enforced, it is expected that all values in the configuration object are immutable. This is the primary distinction between the simulation config and the simulation state.
-
module.pyThis defines the "module" API for extending the simulation. See below for a detailed description of this API.
-
modules/*Modules under
nlisim.modulesare "optional" extensions to the main simulation. They contain functions that are called in one of the extension points in the main solver: initialization and iteration. These functions could be moved to an external package, but for simplicity in this proof of concept are included with the main simulation. -
validation.pyThis module contains a custom exception type dedicated for errors thrown by validation methods. This along with a custom context generator defined here are intended to provide extra information about the source of errors (e.g. which module was executing) after they are thrown.
-
cli.pyThis module uses click to generate a command-line interface for executing the simulation. Click provides a flexible API for designing high quality CLIs.
Simulation state
Absent any additional modules, the simulation state is an object containing only the following attributes:
- time: The simulation time as a floating point number
- grid: An instance of
RectangularGriddefining the simulation discretization - config: An instance of
SimulationConfigproviding configuration options
When a module is included in the runtime configuration, its own state is
included as an additional "dynamic" attribute on this object.
For example when
the "afumigatus" module is included, you have access to state.afumigatus
containing the afumigatus module's state.
The State object API directly uses the API of the attr library. This provides things like type annotation integration, data validation, initialization, and many more features. Developers should read the attrs documentation to learn more about how to work with the state object.
Extension modules
At a high level, an extension module contains the following features:
- configuration options
- state variables
- simulation lifecycle handlers:
- construction (state memory allocation)
- initialization (initial conditions)
- iteration (advancing the state in time)
An extension module is registered with the simulation by providing a subclass
of nlisim.module.Module.
Features are added by overriding attributes on
this class.
The following is small example demonstrating some of the features:
import attr
from nlisim.module import ModuleModel, ModuleState
class HelloWorld(ModuleModel):
name = 'hello_world'
@attr.s(kw_only=True, auto_attribs=True)
class StateClass(ModuleState):
target: str = attr.ib(default='')
def initialize(self, state):
state.hello_world.target = self.config.get('target_string')
return state
def advance(self, state, previous_time):
print(f'Hello {state.hello_world.target}!')
return state
When enabled, this module will
- add its
hello_worldnamespace to the simulation state containing a new scalar value,target - add a configuration option under the section
[hello_world] - initialize the state variable
targetto what is provided in the config file - print a message on every time step
Visualization Config
To visualize the output of the simulation, please add the variable names to the list visual_variables in the config file, under the [visualization] section:
[visualization]
# vtk_type: STRUCTURED_POINTS, STRUCTURED_GRID, RECTILINEAR_GRID, UNSTRUCTURED_GRID, POLY_DATA
visual_variables = [
{
"module":"afumigatus",
"variable":"tree",
"vtk_type":"POLY_DATA",
"attributes":["iron_pool", "iteration"]
},
{
"module":"geometry",
"variable":"lung_tissue",
"vtk_type":"STRUCTURED_POINTS",
"attributes":[]
}
]
For example, to visualize the aspergillus and the alveolar geometry, the variable afumigatus.tree with attributes iron_pool and iteration and the variable geometry.lung_tissue are added to the list, followed by their VTK dataset formats.
- structured point: points data are regularly and uniformly spaced
- rectilinear grid: points data are regularly spaced but can be not uniform
- structured grid: points data are not regularly and not uniformly spaced
- unstructured grid: consists of arbitrary combinations of any possible cell type
- polygonal data: consists of a set of discrete points, vertices, lines or polygons
Expand source code
"""
A multiscale simulation framework of *Aspergillus fumigatus*.
.. include:: ../README.md
"""
try:
from importlib.metadata import version # type: ignore
except ImportError:
from importlib_metadata import version # type: ignore
__version__ = version('nlisim')
Sub-modules
nlisim.cellnlisim.clinlisim.confignlisim.coordinatesnlisim.diffusionnlisim.geometrynlisim.grid-
Domain discretization interface …
nlisim.modulenlisim.modulesnlisim.moleculenlisim.oldmodulesnlisim.postprocessnlisim.randomnlisim.solvernlisim.statenlisim.utilnlisim.validation