Data4DM / stanify

Bridging System dynamics tool (Vensim) and Bayesian computation tool (Stan)
https://data4dm.github.io/stanify/
2 stars 1 forks source link

Documenting context type classification #21

Open hyunjimoon opened 1 year ago

hyunjimoon commented 1 year ago

SBC inputs are classified into three, which are typified as python classes. Precision and Stan_model context are dataclass, and only VensimModelContext receives absstract_model (ode structure) during its initialization.

For prey-predator model's data2darws (different from draws2data e.g. _obs family), stan_model_context consists of

StanModelContext(

    initial_time=0.0, 

    integration_times=array([0.01,.., 0.58]), 

    stan_data = {
        'process_noise_uniform_driving': StanDataEntry(data_name='process_noise_uniform_driving', stan_type='vector[20]'), 
                'process_noise_scale': StanDataEntry(data_name='process_noise_scale', stan_type='real'), 
        'prey_obs': StanDataEntry(data_name='prey_obs', stan_type='vector[20]'), 
        'predator_obs': StanDataEntry(data_name='predator_obs', stan_type='vector[20]')}, 

    sample_statements
        =[<stanify.builders.stan_model.SamplingStatement object at 0x14b94ae30>, 
          <stanify.builders.stan_model.SamplingStatement object at 0x14b94a980>, 
          <stanify.builders.stan_model.SamplingStatement object at 0x14b94ae60>, 
          <stanify.builders.stan_model.SamplingStatement object at 0x14b94a740>, 
          <stanify.builders.stan_model.SamplingStatement object at 0x14b94aef0>], 

    exposed_parameters={'pred_birth_frac', 'prey_birth_frac',  'process_noise_scale', 'time_step'}, 
    all_stan_variables={'prey_obs', 'predator_obs', 'prey_birth_frac', 'pred_birth_frac',  'm_noise_scale'}
)

SamplingStatement consists of estiatmated parameter's distribution info.

Below is VensimModelContext structure.

class VensimModelContext:
    def __init__(self, abstract_model):
        self.variable_names = set()  # stanified
        self.stock_variable_names = set()
        self.abstract_model = abstract_model

        # Some basic checks to make sure the AM is compatible
        assert len(abstract_model.sections) == 1, "Number of sections in AbstractModel must be 1."

        for element in abstract_model.sections[0].elements:
            assert len(element.components) == 1, f"Number of components in AbstractElement must be 1, but {element.name} has {len(element.components)}"
            self.variable_names.add(vensim_name_to_identifier(element.name))

        for element in abstract_model.sections[0].elements:
            for component in element.components:
                if isinstance(component.ast, IntegStructure):
                    self.stock_variable_names.add(vensim_name_to_identifier(element.name))
                    break
hyunjimoon commented 1 year ago

While writing draws2datagq block,

ignored_variables {'predator', 'prey', 'process_noise', 'process_noise_uniform_driving', 'process_noise_scale'} is union of stan_context.stan_data(['process_noise_uniform_driving', 'process_noise_scale']) and vensim_model_context.integ_outcome_vector_names ['predator', 'prey', 'process_noise']

from param_draw_order ['pred_birth_frac', 'prey_birth_frac', 'm_noise_scale', 'prey_obs', 'predator_obs'], we should filter out prey_obs, predator_obs out, which leaves us prey_birth_frac, pred_birth_frac, m_noise_scale, for generation from prior