AbstractSimulator interface
The extension point every simulator backend implements.
ModelManager.AbstractSimulator — Type
AbstractSimulatorAbstract supertype for simulator backends.
Concrete subtypes supply the command that runs a single simulation via simulationCommand — ModelManager executes it, locally or as a SLURM job — and provide simulator-specific metadata (version schema, display info, etc.).
This is the primary extension point for using the ModelManager infrastructure with any simulator. To support a new simulator:
- Define
MySimulator <: AbstractSimulator - Implement the required interface methods listed below
Required interface methods
simulationCommand(::MySimulator, spec::SimulationSpec)::Union{Nothing,Cmd}simulatorDir(::MySimulator)::StringsimulatorVersionSchema(::MySimulator)::StringsimulatorVersionIDName(::MySimulator)::StringsimulatorVersionTableName(::MySimulator)::StringresolveSimulatorVersionID(::MySimulator)::IntcurrentSimulatorVersionID(::MySimulator)::IntsimulatorInfo(::MySimulator)::StringsetupMonad(::MySimulator, M::AbstractMonad; kwargs...)::BoolsetupSampling(::MySimulator, S::AbstractSampling; kwargs...)::Bool
runSimulation has a default that runs the command from simulationCommand locally or as a SLURM job; override it only for a simulator that is not an external process.
Note: variationLocation is not part of the ModelManager interface. The calling framework (e.g. PhysiCellModelManager) is responsible for resolving variation targets to their locations before constructing variation objects — the location::Symbol argument must be passed explicitly when constructing DiscreteVariation or DistributedVariation.
ModelManager.centralDBFileName — Method
centralDBFileName(sim::AbstractSimulator)::StringReturn the filename (not full path) of the central SQLite database for this simulator. The file will be created inside dataDir(). The default is "mm.db". Simulator packages can override this to use a different name or implement legacy-name detection.
ModelManager.clearSimulatorArtifacts — Method
clearSimulatorArtifacts(sim::AbstractSimulator)Remove all simulator-generated build artifacts from input folders during a database reset. The default implementation is a no-op.
Called by resetDatabase after all output folders have been deleted. Implementations should remove compiled executables, object files, and any other files generated by the simulator that do not belong to the base inputs.
ModelManager.currentSimulatorVersionID — Method
currentSimulatorVersionID(sim::AbstractSimulator)::IntReturn the integer row ID of the currently active simulator version.
ModelManager.dbVersionTableName — Method
dbVersionTableName(sim::AbstractSimulator)::StringReturn the name of the SQLite table used to persist the package version in the project database (e.g. "pcmm_version"). The generic upgrade machinery reads and writes this table to track which version a given database was last migrated to.
ModelManager.getInputFolderDescription — Method
getInputFolderDescription(sim::AbstractSimulator, path_to_folder::String)::StringReturn a human-readable description for the input folder at path_to_folder.
Called by insertFolder when inserting a new folder into the database. The default implementation returns "". Simulator packages may override this to read metadata from a file in the folder (e.g. a metadata.xml or TOML file).
ModelManager.initializeInputFolder — Method
initializeInputFolder(sim::AbstractSimulator, input_folder)Perform any simulator-specific initialization for a newly-inserted input folder.
Called by insertFolder after the folder row has been written to the database and the per-folder variations SQLite database has been created. The default implementation is a no-op.
Implementations may, for example, compile an initial XML parameter file from a template, create derived assets, etc.
ModelManager.postInitDisplay — Method
postInitDisplay(sim::AbstractSimulator)Print initialization information. The default implementation prints the generic ModelManager fields (data directory, database path, inputs config, HPC status, parallelism). Simulator packages can specialize this method to prepend a logo, version banner, and simulator-specific fields.
ModelManager.postSimulationCleanup — Method
postSimulationCleanup(sim::AbstractSimulator, simulation_process; kwargs...)Perform simulator-specific cleanup immediately after a simulation finishes and after the user post_processor (see run) has run — the last per-simulation step.
Called by processSimulationTask for every completed simulation, regardless of success (so failed simulations are still cleaned up). This is where destructive work belongs — pruning/deleting output files, removing error files, etc. — because by this point any user post_processor has already read whatever it needed from the intact output folder.
The default implementation is a no-op.
Common keyword arguments (simulator-defined):
prune_options— options controlling which output files to delete (used byPhysiCellModelManager).
ModelManager.postSimulationProcessing — Method
postSimulationProcessing(sim::AbstractSimulator, simulation_process; kwargs...)Perform simulator-specific, non-destructive processing immediately after a simulation finishes and before the user post_processor (see run) runs.
Called by processSimulationTask for every completed simulation. This is the slot for work whose results a user post_processor may want to read — e.g. transforming or standardizing raw output. It must not delete simulation output, or a user callback downstream would be handed an incomplete folder; destructive cleanup belongs in postSimulationCleanup, which runs after the callback.
The default implementation is a no-op.
ModelManager.resolveSimulatorVersionID — Method
resolveSimulatorVersionID(sim::AbstractSimulator)::IntResolve the current simulator version against the database, inserting a new row if necessary. Returns the resolved integer version ID.
ModelManager.setupMonad — Method
setupMonad(sim::AbstractSimulator, M::AbstractMonad; kwargs...)::BoolPerform monad-level setup (prepare varied input folders, etc.) for M. Called by prepareTrialHierarchy after setupSampling has already run for the enclosing sampling or directly for the monad. Return true on success, false on failure.
Accepts AbstractMonad so it handles both Simulation and Monad inputs without requiring a wrapping Sampling to be created.
ModelManager.setupSampling — Method
setupSampling(sim::AbstractSimulator, S::AbstractSampling; kwargs...)::BoolPerform sampling-level setup (typically: compile the shared custom code once for all monads sharing the same InputFolders). Called once per unique input-folder group by prepareTrialHierarchy. Return true on success, false on failure.
Accepts AbstractSampling so it can be called on a Simulation, Monad, or Sampling without requiring a wrapping object to be created.
ModelManager.simulationCommand — Method
simulationCommand(::AbstractSimulator, spec::SimulationSpec) -> Union{Nothing,Cmd}Return the command that runs the simulation described by spec: the one thing about launching a simulation that only the backend knows.
Return nothing if no command can be built for this simulation – a missing input, a failed lookup. That records this one simulation as failed and lets the rest of the trial continue, so it is the right way to report a per-simulation problem; raising instead aborts the whole run. Say why in a log message before returning, because ModelManager has nothing to add.
Everything else – running it locally or submitting it to SLURM, the working directory, where output.log and output.err go, waiting for it, and reporting the outcome – is done by ModelManager's default runSimulation, the same way for every backend. Setup (compilation, varied input folders) has already run via prepareTrialHierarchy, so the monad's inputs are in place.
Return a bare Cmd. Set its dir if the command must run somewhere other than simulatorDir; do not attach an environment or wrap it in a pipeline – see runSimulation for why both are rejected.
ModelManager.simulationCommand(::MySimulator, spec::SimulationSpec) =
`./my_sim $(pathToOutputFolder(spec.simulation.id))`ModelManager.simulatorDir — Method
simulatorDir(sim::AbstractSimulator)::StringReturn the path to the simulator's root directory.
ModelManager.simulatorInfo — Method
simulatorInfo(sim::AbstractSimulator)::StringReturn a human-readable string describing the current simulator version.
ModelManager.simulatorVersionIDName — Method
simulatorVersionIDName(sim::AbstractSimulator)::StringReturn the SQL column name used for the simulator version FK in the simulations, monads, and samplings tables (e.g. "physicell_version_id").
ModelManager.simulatorVersionSchema — Method
simulatorVersionSchema(sim::AbstractSimulator)::StringReturn the SQL sub-schema (as a String) for the simulator version table. Used when initializing the database.
ModelManager.simulatorVersionTableName — Method
simulatorVersionTableName(sim::AbstractSimulator)::StringReturn the name of the simulator version table in the database (e.g. "physicell_versions").
ModelManager.upgradeMilestones — Method
upgradeMilestones(sim::AbstractSimulator)::Vector{VersionNumber}Return a sorted vector of milestone VersionNumbers that have associated database schema changes. upgradeToMilestone is called for each milestone between the current database version and the target package version.
ModelManager.upgradeToMilestone — Method
upgradeToMilestone(sim::AbstractSimulator, version::VersionNumber, auto_upgrade::Bool)::BoolApply the database schema migration required to bring the project database up to version. Called by upgradePackage for each milestone that needs to be crossed. Return true on success, false to abort the upgrade chain.
Implementations are responsible for:
- Prompting the user (when
auto_upgradeisfalse) for any large/destructive migrations. - Making all necessary DDL/DML changes to the database.
- Not updating the version table —
upgradePackagedoes that after a successful return.