Example #1
0
def define_sub_model(d, inputs, outputs, models, **kwargs):
    missing = set(outputs).difference(d.nodes)
    if missing:
        outputs = set(outputs).difference(missing)
    if inputs is not None:
        inputs = set(inputs).union(models)
    return dsp_utl.SubDispatch(d.shrink_dsp(inputs, outputs))
Example #2
0
def _selector(name, data_in, data_out, setting):

    d = dsp.Dispatcher(
        name='%s selector' % name,
        description='Select the calibrated %s.' % name,
    )

    errors, setting = [], setting or {}
    _sort_models = setting.pop('sort_models', sort_models)

    if 'weights' in setting:
        _weights = dsp_utl.map_list(setting['targets'], *setting.pop('weights'))
    else:
        _weights = None

    _get_best_model = functools.partial(
        setting.pop('get_best_model', get_best_model),
        models_wo_err=setting.pop('models_wo_err', None),
        selector_id=d.name
    )

    d.add_data(
        data_id='selector_settings',
        default_value={})

    node_ids = ['error_settings', 'best_model_settings']

    d.add_function(
        function=functools.partial(define_selector_settings, node_ids=node_ids),
        inputs=['selector_settings'],
        outputs=node_ids
    )

    for i in data_in:
        e = 'error/%s' % i

        errors.append(e)

        d.add_function(
            function=_errors(name, i, data_out, setting),
            inputs=['error_settings', i] + [k for k in data_out if k != i],
            outputs=[e]
        )

    d.add_function(
        function_id='sort_models',
        function=functools.partial(_sort_models, weights=_weights),
        inputs=errors,
        outputs=['rank']
    )

    d.add_function(
        function_id='get_best_model',
        function=_get_best_model,
        inputs=['rank', 'best_model_settings'],
        outputs=['model', 'errors']
    )

    return dsp_utl.SubDispatch(d, outputs=['model', 'errors'],
                               output_type='list')
Example #3
0
def run_plan():
    """
    Defines the plan model.

    .. dispatcher:: d

        >>> d = run_plan()

    :return:
        The plan model.
    :rtype: Dispatcher
    """

    d = dsp.Dispatcher(name='run_plan',
                       description='Processes a vehicle plan.')

    d.add_data(data_id='engineering_mode', default_value=False)

    d.add_data(data_id='use_selector', default_value=False)

    d.add_data(data_id='soft_validation', default_value=False)

    d.add_function(function=dsp_utl.add_args(schema.validate_plan),
                   inputs=[
                       'run_plan', 'data', 'engineering_mode',
                       'soft_validation', 'use_selector'
                   ],
                   outputs=['validated_plan'],
                   input_domain=check_first_arg)

    d.add_function(function=default_start_time, outputs=['start_time'])

    d.add_function(function=default_timestamp,
                   inputs=['start_time'],
                   outputs=['timestamp'])

    from .plan import make_simulation_plan
    d.add_function(function=make_simulation_plan,
                   inputs=['validated_plan', 'timestamp', 'variation', 'flag'],
                   outputs=['summary'])

    return dsp_utl.SubDispatch(d)
Example #4
0
def co2_params_selector(
        name='co2_params', data_in=('wltp_h', 'wltp_l'),
        data_out=('wltp_h', 'wltp_l'), setting=None):
    """
    Defines the co2_params model selector.

    .. dispatcher:: d

        >>> d = co2_params_selector()

    :return:
        The co2_params model selector.
    :rtype: SubDispatch
    """
    from . import _selector
    d = _selector(name, data_in + ('ALL',), data_out, setting).dsp
    n = d.get_node('sort_models', node_attr=None)[0]
    errors, sort_models = n['inputs'], n['function']
    d.dmap.remove_node('sort_models')

    d.add_function(
        function=sort_models,
        inputs=errors[:-1],
        outputs=['rank<0>']
    )

    d.add_function(
        function=functools.partial(calibrate_co2_params_all, data_id=data_in),
        inputs=['rank<0>'] + errors[:-1],
        outputs=['ALL']
    )

    d.add_function(
        function=functools.partial(co2_sort_models, **sort_models.keywords),
        inputs=['rank<0>'] + [errors[-1]],
        outputs=['rank']
    )

    return dsp_utl.SubDispatch(d, outputs=['model', 'errors'],
                               output_type='list')
Example #5
0
def _yield_folder_files_results(start_time,
                                input_files,
                                output_folder,
                                overwrite_cache=False,
                                model=None,
                                variation=None,
                                type_approval_mode=False,
                                modelconf=None):
    model = model or vehicle_processing_model()
    kw = {
        'output_folder': output_folder,
        'overwrite_cache': overwrite_cache,
        'modelconf': modelconf,
        'timestamp': start_time.strftime('%Y%m%d_%H%M%S'),
        'variation': variation or {},
        'type_approval_mode': type_approval_mode
    }

    _process_vehicle = dsp_utl.SubDispatch(model)

    for fpath in _custom_tqdm(input_files, bar_format='{l_bar}{bar}{r_bar}'):
        yield _process_vehicle({'input_file_name': fpath}, kw)
Example #6
0
def _error(name, data_id, data_out, setting):

    d = dsp.Dispatcher(
        name='%s-%s error vs %s' % (name, data_id, data_out),
        description='Calculates the error of calibrated model of a reference.',
    )

    default_settings = {
        'inputs_map': {},
        'targets': [],
        'metrics_inputs': {},
        'up_limit': None,
        'dn_limit': None
    }

    default_settings.update(setting)

    it = dsp_utl.selector(['up_limit', 'dn_limit'], default_settings).items()

    for k, v in it:
        if v is not None:
            default_settings[k] = dsp_utl.map_list(setting['targets'], *v)

    d.add_function(
        function_id='select_inputs',
        function=dsp_utl.map_dict,
        inputs=['inputs_map', 'data'],
        outputs=['inputs<0>']
    )

    d.add_function(
        function_id='select_inputs',
        function=functools.partial(dsp_utl.selector, allow_miss=True),
        inputs=['inputs', 'inputs<0>'],
        outputs=['inputs<1>']
    )

    d.add_function(
        function=dsp_utl.combine_dicts,
        inputs=['calibrated_models', 'inputs<1>'],
        outputs=['prediction_inputs']
    )

    d.add_function(
        function_id='select_targets',
        function=functools.partial(dsp_utl.selector, allow_miss=True),
        inputs=['targets', 'data'],
        outputs=['references']
    )

    d.add_function(
        function=functools.partial(
            default_settings.pop('dsp', lambda x: x), {}
        ),
        inputs=['prediction_inputs', 'calibrated_models'],
        outputs=['results']
    )

    d.add_function(
        function_id='select_outputs',
        function=select_outputs,
        inputs=['outputs', 'targets', 'results'],
        outputs=['predictions']
    )

    d.add_function(
        function_id='select_metrics_inputs',
        function=functools.partial(dsp_utl.selector, allow_miss=True),
        inputs=['metrics_inputs', 'data'],
        outputs=['metrics_args']
    )

    d.add_function(
        function=make_metrics,
        inputs=['metrics', 'references', 'predictions', 'metrics_args'],
        outputs=['errors']
    )

    d.add_function(
        function=check_limits,
        inputs=['errors', 'up_limit', 'dn_limit'],
        outputs=['status']
    )

    for k, v in default_settings.items():
        d.add_data(k, v)

    func = dsp_utl.SubDispatch(
        dsp=d,
        outputs=['errors', 'status'],
        output_type='list'
    )

    return func
Example #7
0
def sub_models():
    models = {}

    from ..physical.engine.thermal import thermal
    models['engine_coolant_temperature_model'] = {
        'd': thermal(),
        'models': ['engine_temperature_regression_model',
                   'max_engine_coolant_temperature'],
        'inputs': ['times', 'accelerations', 'final_drive_powers_in',
                   'engine_speeds_out_hot', 'initial_engine_temperature'],
        'outputs': ['engine_coolant_temperatures'],
        'targets': ['engine_coolant_temperatures'],
        'metrics': [sk_met.mean_absolute_error],
        'up_limit': [3],
    }

    from ..physical.engine.start_stop import start_stop
    models['start_stop_model'] = {
        'd': start_stop(),
        'models': ['start_stop_model', 'use_basic_start_stop'],
        'inputs': ['times', 'velocities', 'accelerations',
                   'engine_coolant_temperatures', 'state_of_charges',
                   'gears', 'correct_start_stop_with_gears',
                   'start_stop_activation_time',
                   'min_time_engine_on_after_start', 'has_start_stop'],
        'outputs': ['on_engine', 'engine_starts'],
        'targets': ['on_engine', 'engine_starts'],
        'metrics': [sk_met.accuracy_score] * 2,
        'weights': [-1, -1],
        'dn_limit': [0.7] * 2,
    }

    from ..physical import physical

    models['engine_speed_model'] = {
        'd': physical(),
        'select_models': tyre_models_selector,
        'models': ['final_drive_ratio', 'gear_box_ratios',
                   'idle_engine_speed_median', 'idle_engine_speed_std',
                   'CVT', 'max_speed_velocity_ratio',
                   'tyre_dynamic_rolling_coefficient'],
        'inputs': ['velocities', 'gears', 'times', 'on_engine', 'gear_box_type',
                   'accelerations', 'final_drive_powers_in',
                   'engine_thermostat_temperature', 'tyre_code'],
        'outputs': ['engine_speeds_out_hot'],
        'targets': ['engine_speeds_out'],
        'metrics_inputs': ['times', 'velocities', 'gear_shifts', 'on_engine',
                           'stop_velocity'],
        'metrics': [metric_engine_speed_model],
        'up_limit': [40],
    }

    from ..physical.engine import calculate_engine_speeds_out
    from ..physical.engine.cold_start import cold_start
    d = cold_start()

    d.add_function(
        function=calculate_engine_speeds_out,
        inputs=['on_engine', 'idle_engine_speed', 'engine_speeds_out_hot',
                'cold_start_speeds_delta'],
        outputs=['engine_speeds_out']
    )

    models['engine_cold_start_speed_model'] = {
        'd': d,
        'models': ['cold_start_speed_model'],
        'inputs': ['engine_speeds_out_hot', 'engine_coolant_temperatures',
                   'on_engine', 'idle_engine_speed'],
        'outputs': ['engine_speeds_out'],
        'targets': ['engine_speeds_out'],
        'metrics_inputs': ['cold_start_speeds_phases'],
        'metrics': [metric_engine_cold_start_speed_model],
        'up_limit': [100],
    }

    from ..physical.clutch_tc import clutch_torque_converter

    d = clutch_torque_converter()

    d.add_function(
        function=calculate_engine_speeds_out,
        inputs=['on_engine', 'idle_engine_speed', 'engine_speeds_out_hot',
                'clutch_tc_speeds_delta'],
        outputs=['engine_speeds_out']
    )

    models['clutch_torque_converter_model'] = {
        'd': d,
        'models': ['clutch_window', 'clutch_model', 'torque_converter_model'],
        'inputs': ['gear_box_speeds_in', 'on_engine', 'idle_engine_speed',
                   'gear_box_type', 'gears', 'accelerations', 'times',
                   'gear_shifts', 'engine_speeds_out_hot', 'velocities',
                   'lock_up_tc_limits', 'has_torque_converter'],
        'define_sub_model': lambda d, **kwargs: dsp_utl.SubDispatch(d),
        'outputs': ['engine_speeds_out'],
        'targets': ['engine_speeds_out'],
        'metrics_inputs': ['on_engine'],
        'metrics': [metric_clutch_torque_converter_model],
        'up_limit': [100],
    }

    from ..physical.engine.co2_emission import co2_emission
    from .co2_params import co2_params_selector
    models['co2_params'] = {
        'd': co2_emission(),
        'model_selector': co2_params_selector,
        'models': ['co2_params_calibrated', 'calibration_status',
                   'initial_friction_params', 'engine_idle_fuel_consumption'],
        'inputs': ['co2_emissions_model'],
        'outputs': ['co2_emissions', 'calibration_status'],
        'targets': ['identified_co2_emissions', 'calibration_status'],
        'metrics': [sk_met.mean_absolute_error, metric_calibration_status],
        'up_limit': [0.5, None],
        'weights': [1, None]
    }

    from ..physical.electrics import electrics

    models['alternator_model'] = {
        'd': electrics(),
        'models': ['alternator_status_model', 'alternator_nominal_voltage',
                   'alternator_current_model', 'max_battery_charging_current',
                   'start_demand', 'electric_load', 'alternator_nominal_power',
                   'alternator_efficiency', 'alternator_initialization_time'],
        'inputs': [
            'battery_capacity', 'alternator_nominal_voltage',
            'initial_state_of_charge', 'times', 'gear_box_powers_in',
            'on_engine', 'engine_starts', 'accelerations'],
        'outputs': ['alternator_currents', 'battery_currents',
                    'state_of_charges', 'alternator_statuses'],
        'targets': ['alternator_currents', 'battery_currents',
                    'state_of_charges', 'alternator_statuses'],
        'metrics': [sk_met.mean_absolute_error] * 3 + [sk_met.accuracy_score],
        'up_limit': [60, 60, None, None],
        'weights': [1, 1, 0, 0]
    }

    from ..physical.gear_box.at_gear import at_gear
    at_pred_inputs = [
        'engine_max_power', 'engine_max_speed_at_max_power',
        'idle_engine_speed', 'full_load_curve', 'road_loads', 'vehicle_mass',
        'accelerations', 'motive_powers', 'engine_speeds_out',
        'engine_coolant_temperatures', 'time_cold_hot_transition', 'times',
        'use_dt_gear_shifting', 'specific_gear_shifting',
        'velocity_speed_ratios', 'velocities', 'MVL', 'fuel_saving_at_strategy',
        'change_gear_window_width', 'stop_velocity', 'plateau_acceleration',
        'max_velocity_full_load_correction', 'cycle_type'
    ]

    models['at_model'] = {
        'd': at_gear(),
        'select_models': functools.partial(
            at_models_selector, at_gear(), at_pred_inputs
        ),
        'models': ['MVL', 'CMV', 'CMV_Cold_Hot', 'DT_VA', 'DT_VAT', 'DT_VAP',
                   'DT_VATP', 'GSPV', 'GSPV_Cold_Hot',
                   'specific_gear_shifting', 'change_gear_window_width',
                   'max_velocity_full_load_correction', 'plateau_acceleration'],
        'inputs': at_pred_inputs,
        'define_sub_model': lambda d, **kwargs: dsp_utl.SubDispatch(d),
        'outputs': ['gears', 'max_gear'],
        'targets': ['gears', 'max_gear'],
        'metrics': [sk_met.accuracy_score, None],
        'weights': [-1, 0]
    }

    return models
Example #8
0
def run_base():
    """
    Defines the vehicle-processing model.

    .. dispatcher:: d

        >>> d = run_base()

    :return:
        The vehicle-processing model.
    :rtype: Dispatcher
    """

    d = dsp.Dispatcher(
        name='run_base',
        description='Processes a vehicle from the file path to the write of its'
        ' outputs.')

    d.add_data(data_id='engineering_mode', default_value=False)

    d.add_data(data_id='output_folder', default_value='.')

    d.add_data(data_id='use_selector', default_value=False)

    d.add_data(data_id='soft_validation', default_value=False)

    d.add_function(function=dsp_utl.add_args(schema.validate_base),
                   inputs=[
                       'run_base', 'data', 'engineering_mode',
                       'soft_validation', 'use_selector'
                   ],
                   outputs=['validated_base'],
                   input_domain=check_first_arg,
                   weight=10)

    d.add_data(data_id='only_summary', default_value=False)

    d.add_function(function=default_vehicle_name,
                   inputs=['input_file_name'],
                   outputs=['vehicle_name'])

    d.add_function(function=default_start_time, outputs=['start_time'])

    d.add_function(function=default_timestamp,
                   inputs=['start_time'],
                   outputs=['timestamp'])

    d.add_function(function=default_output_file_name,
                   inputs=['output_folder', 'vehicle_name', 'timestamp'],
                   outputs=['output_file_name'])

    from .model import model
    d.add_function(
        function=dsp_utl.SubDispatch(model()),
        inputs=['validated_base'],
        outputs=['dsp_solution'],
    )

    d.add_function(function=parse_dsp_solution,
                   inputs=['dsp_solution'],
                   outputs=['output_data'])

    from .report import report
    d.add_function(
        function=report(),
        inputs=['output_data', 'vehicle_name'],
        outputs=['report', 'summary'],
    )

    d.add_function(function=get_template_file_name,
                   inputs=['output_template', 'input_file_name'],
                   outputs=['template_file_name'])

    d.add_data(data_id='output_template',
               default_value=_get_co2mpas_output_template_fpath(),
               initial_dist=10)

    from .io import write_outputs
    d.add_function(function=dsp_utl.add_args(write_outputs()),
                   inputs=[
                       'only_summary', 'output_file_name',
                       'template_file_name', 'report', 'start_time', 'flag'
                   ],
                   outputs=[dsp_utl.SINK],
                   input_domain=lambda *args: not args[0])

    d.add_function(
        function=dsp_utl.add_args(plot_model_workflow),
        inputs=['plot_workflow', 'output_file_name', 'vehicle_name'],
        outputs=[dsp_utl.PLOT],
        weight=30,
        input_domain=check_first_arg)

    return dsp_utl.SubDispatch(d)
Example #9
0
def model():
    """
    Defines the CO2MPAS model.

    .. dispatcher:: d

        >>> d = model()

    :return:
        The CO2MPAS model.
    :rtype: co2mpas.dispatcher.Dispatcher
    """

    from .physical import physical
    d = dsp.Dispatcher(
        name='CO2MPAS model',
        description='Calibrates the models with WLTP data and predicts NEDC '
        'cycle.')

    ############################################################################
    #                          PRECONDITIONING CYCLE
    ############################################################################

    d.add_data(
        data_id='input.precondition.wltp_p',
        description='Dictionary that has all inputs of the calibration cycle.',
        default_value={})

    d.add_function(
        function_id='calculate_precondition_output',
        function=dsp_utl.SubDispatch(physical()),
        inputs=['input.precondition.wltp_p'],
        outputs=['output.precondition.wltp_p'],
        description='Wraps all functions needed to calculate the precondition '
        'outputs.')

    ############################################################################
    #                          WLTP - HIGH CYCLE
    ############################################################################

    d.add_data(data_id='input.calibration.wltp_h', default_value={})

    d.add_function(
        function=select_calibration_data,
        inputs=['input.calibration.wltp_h', 'output.precondition.wltp_p'],
        outputs=['data.calibration.wltp_h'],
    )

    d.add_function(
        function_id='calibrate_with_wltp_h',
        function=dsp_utl.SubDispatch(physical()),
        inputs=['data.calibration.wltp_h'],
        outputs=['output.calibration.wltp_h'],
        description='Wraps all functions needed to calibrate the models to '
        'predict light-vehicles\' CO2 emissions.')

    d.add_data(data_id='input.prediction.wltp_h', default_value={})

    d.add_function(
        function=select_prediction_data,
        inputs=['output.calibration.wltp_h', 'input.prediction.wltp_h'],
        outputs=['data.prediction.wltp_h'])

    d.add_function(
        function_id='predict_wltp_h',
        function=dsp_utl.SubDispatch(physical()),
        inputs=['data.prediction.models_wltp_h', 'data.prediction.wltp_h'],
        outputs=['output.prediction.wltp_h'],
        description='Wraps all functions needed to predict CO2 emissions.')

    ############################################################################
    #                          WLTP - LOW CYCLE
    ############################################################################

    d.add_data(data_id='input.calibration.wltp_l', default_value={})

    d.add_function(
        function=select_calibration_data,
        inputs=['input.calibration.wltp_l', 'output.precondition.wltp_p'],
        outputs=['data.calibration.wltp_l'],
    )

    d.add_function(
        function_id='calibrate_with_wltp_l',
        function=dsp_utl.SubDispatch(physical()),
        inputs=['data.calibration.wltp_l'],
        outputs=['output.calibration.wltp_l'],
        description='Wraps all functions needed to calibrate the models to '
        'predict light-vehicles\' CO2 emissions.')

    d.add_data(data_id='input.prediction.wltp_l', default_value={})

    d.add_function(
        function=select_prediction_data,
        inputs=['output.calibration.wltp_l', 'input.prediction.wltp_l'],
        outputs=['data.prediction.wltp_l'])

    d.add_function(
        function_id='predict_wltp_l',
        function=dsp_utl.SubDispatch(physical()),
        inputs=['data.prediction.models_wltp_l', 'data.prediction.wltp_l'],
        outputs=['output.prediction.wltp_l'],
        description='Wraps all functions needed to predict CO2 emissions.')

    ############################################################################
    #                            MODEL SELECTOR
    ############################################################################

    from .selector import selector

    pred_cyl_ids = ('nedc_h', 'nedc_l', 'wltp_h', 'wltp_l')
    sel = selector('wltp_h', 'wltp_l', pred_cyl_ids=pred_cyl_ids)

    d.add_data(data_id='config.selector.all', default_value={})

    d.add_data(data_id='input.prediction.models', default_value={})

    d.add_function(function_id='extract_calibrated_models',
                   function=sel,
                   inputs=[
                       'config.selector.all', 'input.prediction.models',
                       'output.calibration.wltp_h', 'output.calibration.wltp_l'
                   ],
                   outputs=['data.calibration.model_scores'] +
                   ['data.prediction.models_%s' % k for k in pred_cyl_ids])

    ############################################################################
    #                            NEDC - HIGH CYCLE
    ############################################################################

    d.add_function(
        function_id='predict_nedc_h',
        function=dsp_utl.SubDispatch(physical()),
        inputs=['data.prediction.models_nedc_h', 'input.prediction.nedc_h'],
        outputs=['output.prediction.nedc_h'],
    )

    ############################################################################
    #                            NEDC - LOW CYCLE
    ############################################################################

    d.add_function(
        function_id='predict_nedc_l',
        function=dsp_utl.SubDispatch(physical()),
        inputs=['data.prediction.models_nedc_l', 'input.prediction.nedc_l'],
        outputs=['output.prediction.nedc_l'],
    )

    return d
Example #10
0
def vehicle_processing_model():
    """
    Defines the vehicle-processing model.

    .. dispatcher:: dsp

        >>> dsp = vehicle_processing_model()

    :return:
        The vehicle-processing model.
    :rtype: Dispatcher
    """

    dsp = Dispatcher(
        name='CO2MPAS vehicle_processing_model',
        description='Processes a vehicle from the file path to the write of its'
        ' outputs.')

    dsp.add_data(data_id='overwrite_cache', default_value=False)

    dsp.add_data(data_id='soft_validation', default_value=False)

    dsp.add_data(data_id='with_output_file', default_value=False)

    dsp.add_function(function=default_vehicle_name,
                     inputs=['input_file_name'],
                     outputs=['vehicle_name'])

    dsp.add_function(function=default_start_time, outputs=['start_time'])

    dsp.add_function(function=default_timestamp,
                     inputs=['start_time'],
                     outputs=['timestamp'])

    dsp.add_function(function=dsp_utl.add_args(default_output_file_name),
                     inputs=[
                         'with_output_file', 'output_folder', 'vehicle_name',
                         'timestamp'
                     ],
                     outputs=['output_file_name'],
                     input_domain=lambda *args: args[0])

    from .io import load_inputs, write_outputs

    dsp.add_dispatcher(dsp=load_inputs(),
                       inputs={
                           'input_file_name': 'input_file_name',
                           'overwrite_cache': 'overwrite_cache',
                           'soft_validation': 'soft_validation'
                       },
                       outputs={
                           'validated_data': 'validated_data',
                           'validated_plan': 'validated_plan'
                       })

    from .model import model
    dsp.add_function(function=dsp_utl.add_args(
        dsp_utl.SubDispatch(model(), output_type='dsp')),
                     inputs=['plan', 'validated_data'],
                     outputs=['dsp_model'],
                     input_domain=lambda *args: not args[0])

    dsp.add_function(function=parse_dsp_model,
                     inputs=['dsp_model'],
                     outputs=['output_data'])

    from .report import report
    dsp.add_function(
        function=report(),
        inputs=['output_data', 'vehicle_name'],
        outputs=['report', 'summary'],
    )

    dsp.add_function(function=dsp_utl.bypass,
                     inputs=['output_data'],
                     outputs=['report'],
                     weight=1)

    dsp.add_function(function=get_template_file_name,
                     inputs=['output_template', 'input_file_name'],
                     outputs=['template_file_name'])

    dsp.add_data(data_id='output_template', default_value='', initial_dist=10)

    main_flags = ('template_file_name', 'overwrite_cache', 'soft_validation',
                  'with_output_file', 'plot_workflow')

    dsp.add_function(function=partial(dsp_utl.map_list, main_flags),
                     inputs=main_flags,
                     outputs=['main_flags'])

    dsp.add_function(function=write_outputs(),
                     inputs=[
                         'output_file_name', 'template_file_name', 'report',
                         'start_time', 'main_flags'
                     ],
                     outputs=[dsp_utl.SINK],
                     input_domain=check_first_arg)

    dsp.add_function(function_id='has_plan',
                     function=check_first_arg,
                     inputs=['validated_plan'],
                     outputs=['plan'])

    from .plan import make_simulation_plan
    dsp.add_function(function=dsp_utl.add_args(make_simulation_plan),
                     inputs=[
                         'plan', 'validated_plan', 'timestamp',
                         'output_folder', 'main_flags'
                     ],
                     outputs=['summary'],
                     input_domain=check_first_arg)

    return dsp