Architectural Notes: Config Structure and API Design
Context
The v0.1.0 config refactor (PR #38) introduced instance-based MalariaConfig for thread-safe parallel simulations. This issue documents
architectural considerations for future reference.
1. Module Structure and Run_Number Placement
Current State
emodlib/
├── params.py # Params dict class, deep_update utility
└── malaria/
├── __init__.py # create_config(), update() wrappers
└── MalariaConfig # All params including Run_Number/random_seed
Observation
The original project structure anticipated potential additional submodules beyond malaria. However, MalariaConfig now contains Run_Number
(random seed), which is conceptually a general concern not specific to malaria.
If future submodules were added (e.g., emodlib.hiv, emodlib.tb), the current design would require each to independently handle Run_Number and
RNG initialization.
Potential Future Design
A base config at the emodlib level could own shared concerns:
emodlib.BaseConfig # Run_Number, RNG, SUID generator
└── emodlib.malaria.MalariaConfig # Inherits base, adds malaria params
└── emodlib.other.OtherConfig # Inherits base, adds other params
Recommendation
No action needed now. Current design is pragmatic for a malaria-only library. Document this consideration if/when additional disease modules are
planned.
2. Configuration API Redundancy
Current API Surface
| Method |
Layer |
Role |
MalariaConfig() |
C++ |
Default constructor |
MalariaConfig.configure(pset) |
C++ |
Configure from ParamSet dict |
MalariaConfig.from_params(pset) |
C++ |
Static factory: construct + configure |
create_config(params) |
Python |
User API: merge with defaults, create config |
config.update(params) |
Python |
User API: incremental merge, reconfigure |
Analysis
C++ level redundancy: from_params is a convenience wrapper around constructor + configure:
static std::shared_ptr<MalariaConfig> FromParamSet(const ParamSet& pset) {
auto config = std::make_shared<MalariaConfig>();
config->Configure(pset);
return config;
}
Both from_params and configure are exposed via pybind11, but configure alone would suffice.
Python wrappers add value:
create_config(): Merges user params with YAML defaults, stores _params for yaml property
config.update(): Incremental merge on existing config (equivalent to old update_params)
These are not redundant with the C++ methods—they provide the user-friendly API with defaults handling.
Potential Simplification
Could reduce C++ public API to just configure(), with Python create_config() handling all construction:
def create_config(params=None):
merged = deep_update(defaults, params or {})
cfg = MalariaConfig() # default constructor
cfg.configure(merged) # configure instance
cfg._params = merged
return cfg
This would remove from_params from public API without breaking functionality.
Recommendation
Low priority. Current API works correctly. If simplifying, could deprecate from_params in favor of Python-side factory pattern, but the marginal
benefit is small.
Summary
These are documentation notes, not bugs. The current architecture is functional and thread-safe. These considerations are relevant only if:
- Additional disease submodules are planned
- API surface reduction becomes a priority
Related: config-refactor branch, v0.1.0 release
Architectural Notes: Config Structure and API Design
Context
The v0.1.0 config refactor (PR #38) introduced instance-based
MalariaConfigfor thread-safe parallel simulations. This issue documentsarchitectural considerations for future reference.
1. Module Structure and Run_Number Placement
Current State
Observation
The original project structure anticipated potential additional submodules beyond
malaria. However,MalariaConfignow containsRun_Number(random seed), which is conceptually a general concern not specific to malaria.
If future submodules were added (e.g.,
emodlib.hiv,emodlib.tb), the current design would require each to independently handleRun_NumberandRNG initialization.
Potential Future Design
A base config at the
emodliblevel could own shared concerns:Recommendation
No action needed now. Current design is pragmatic for a malaria-only library. Document this consideration if/when additional disease modules are
planned.
2. Configuration API Redundancy
Current API Surface
MalariaConfig()MalariaConfig.configure(pset)MalariaConfig.from_params(pset)create_config(params)config.update(params)Analysis
C++ level redundancy:
from_paramsis a convenience wrapper around constructor +configure:Both
from_paramsandconfigureare exposed via pybind11, butconfigurealone would suffice.Python wrappers add value:
create_config(): Merges user params with YAML defaults, stores_paramsforyamlpropertyconfig.update(): Incremental merge on existing config (equivalent to oldupdate_params)These are not redundant with the C++ methods—they provide the user-friendly API with defaults handling.
Potential Simplification
Could reduce C++ public API to just
configure(), with Pythoncreate_config()handling all construction:This would remove
from_paramsfrom public API without breaking functionality.Recommendation
Low priority. Current API works correctly. If simplifying, could deprecate
from_paramsin favor of Python-side factory pattern, but the marginalbenefit is small.
Summary
These are documentation notes, not bugs. The current architecture is functional and thread-safe. These considerations are relevant only if:
Related: config-refactor branch, v0.1.0 release