You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Each Module subclass defines a list of PROPERTIES that it "owns" in the population DataFrame. During the initialise_population method, each Module subclass then sets the initial values for said columns.
However, the majority of Module subclasses seem to perform the same actions in this method - which is to just set the columns (defined in self.PROPERTIES) to the default value for the variable type of the property in question. As an example, consider the chronicsyndrome module - the PROPERTIES match up identically to the columns set in the population DataFrame during initialise_population. There a few other cases where a module will set the initial value of a column to something other than the default value defined by the Property class, but will still explicitly set all other property columns to the default value.
Other modules do this and a bit more; Alri for example has 10 properties which sets an additional group of columns on top of those defined in it's PROPERTIES. However, it still needs to set the PROPERTIES columns to their defaults too.
We can likely automate this process for the vast majority of modules by implementing initialise_population generally in the Module class itself:
definitialise_population(self, population: Population) ->None:
df=population.propsforproperty_name, propertyinself.PROPERTIES.items():
df.loc[df.is_alive, property_name] = (
property._default_value# If the property is a CATEGORICAL, we might have to lookup the correct default value to assign here
)
And then allowing Property to take an override at instantiation with the default value to assign to a series;
classProperty(Specifiable):
def__init__(
self,
type_: Types,
description: str,
categories: Set[Any] =None,
*,
ordered: bool=False,
default_property_value: Optional[Any] =None,
) ->None:
# All the usual stuff we already do
...
# Set supplied default value, if appropriateself._default_property_value= (
default_property_valueifdefault_property_valueisnotNoneand (
(
self.type_isTypes.CATEGORICALanddefault_property_valueincategories
)
orisinstance(default_property_value, self.python_type)
)
elseNone
)
@propertydef_default_value(self) ->Type[Any]:
return (
self.PANDAS_TYPE_DEFAULT_VALUE_MAP[self.pandas_type] # Fall back to dtype map if no explicit default was given.ifself._default_property_valueisNoneelseself._default_property_value
)
Disease Modules that then need to do something different to this can still overwrite initialise_population as usual. Modules that need to do something in addition to this can invoke super().initialise_population to copy these steps, before running the custom instructions they need in advance. Modules that just need to do these steps then don't even need to implement initialise_population explicitly.
This also means that if the names of the PROPERTIES for a given module are ever updated, they don't need to be changed in two places (within PROPERTIES and again in initialise_population).
The text was updated successfully, but these errors were encountered:
Related to the above; the on_birth method in most modules also does something similar for the newborn child: sets all of their properties in the DF to be the defaults. We could again have the Module class define on_birth by default:
classModule:
....
defon_birth(self, mother_id: int, child_id: int) ->None:
forproperty_name, propertyinself.PROPERTIES.items():
df.loc[child_id, property_name] =property._default_value# Or maybe more efficientdf.loc[child_id, [p_nameforp_nameinself.PROPERTIES.keys()]] = [p._default_valueforpinself.PROPERTIES.values()]
And again, modules can:
Not explicitly define this method if they want to do exactly this on a new birth
Use super() to do this and then run some additional commands specific to the subclass
Overwrite the method explicitly if they need to do something completely different
Each
Module
subclass defines a list ofPROPERTIES
that it "owns" in the population DataFrame. During theinitialise_population
method, eachModule
subclass then sets the initial values for said columns.However, the majority of
Module
subclasses seem to perform the same actions in this method - which is to just set the columns (defined inself.PROPERTIES
) to the default value for the variable type of the property in question. As an example, consider the chronicsyndrome module - thePROPERTIES
match up identically to the columns set in the population DataFrame duringinitialise_population
. There a few other cases where a module will set the initial value of a column to something other than the default value defined by theProperty
class, but will still explicitly set all other property columns to the default value.Other modules do this and a bit more;
Alri
for example has 10 properties which sets an additional group of columns on top of those defined in it'sPROPERTIES
. However, it still needs to set thePROPERTIES
columns to their defaults too.We can likely automate this process for the vast majority of modules by implementing
initialise_population
generally in theModule
class itself:And then allowing
Property
to take an override at instantiation with the default value to assign to a series;Disease
Module
s that then need to do something different to this can still overwriteinitialise_population
as usual.Module
s that need to do something in addition to this can invokesuper().initialise_population
to copy these steps, before running the custom instructions they need in advance.Module
s that just need to do these steps then don't even need to implementinitialise_population
explicitly.This also means that if the names of the
PROPERTIES
for a given module are ever updated, they don't need to be changed in two places (withinPROPERTIES
and again ininitialise_population
).The text was updated successfully, but these errors were encountered: