Source code for tvb.adapters.forms.simulator_fragments

# -*- coding: utf-8 -*-
#
#
# TheVirtualBrain-Framework Package. This package holds all Data Management, and
# Web-UI helpful to run brain-simulations. To use it, you also need to download
# TheVirtualBrain-Scientific Package (for simulators). See content of the
# documentation-folder for more details. See also http://www.thevirtualbrain.org
#
# (c) 2012-2023, Baycrest Centre for Geriatric Care ("Baycrest") and others
#
# This program is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.  See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this
# program.  If not, see <http://www.gnu.org/licenses/>.
#
#
#   CITATION:
# When using The Virtual Brain for scientific publications, please cite it as explained here:
# https://www.thevirtualbrain.org/tvb/zwei/neuroscience-publications
#
#

import uuid
import formencode
from formencode import validators

from tvb.adapters.datatypes.db.patterns import StimuliRegionIndex, SpatioTemporalPatternIndex
from tvb.adapters.forms.form_with_ranges import FormWithRanges
from tvb.adapters.forms.integrator_forms import get_form_for_integrator, get_integrator_name_list
from tvb.adapters.forms.model_forms import ModelsEnum
from tvb.adapters.forms.monitor_forms import get_ui_name_to_monitor_dict, get_monitor_to_ui_name_dict
from tvb.basic.profile import TvbProfile
from tvb.basic.neotraits.api import Attr, EnumAttr, Range, List, Float, Int
from tvb.core.adapters.abcadapter import ABCAdapterForm
from tvb.core.entities.file.simulator.view_model import CortexViewModel, SimulatorAdapterModel, IntegratorViewModelsEnum
from tvb.core.entities.filters.chain import FilterChain
from tvb.core.entities.load import load_entity_by_gid
from tvb.core.entities.transient.range_parameter import RangeParameter
from tvb.core.neocom import h5
from tvb.core.neotraits.forms import ArrayField, SelectField, MultiSelectField, \
    TraitDataTypeSelectField, HiddenField, FloatField, StrField, DynamicSelectField
from tvb.core.neotraits.view_model import Str
from tvb.core.services.algorithm_service import AlgorithmService
from tvb.core.services.burst_service import BurstService
from tvb.datatypes.surfaces import SurfaceTypesEnum


[docs]class SimulatorSurfaceFragment(ABCAdapterForm): def __init__(self): super(SimulatorSurfaceFragment, self).__init__() conditions = FilterChain(fields=[FilterChain.datatype + '.surface_type'], operations=["=="], values=[SurfaceTypesEnum.CORTICAL_SURFACE.value]) self.surface = TraitDataTypeSelectField(CortexViewModel.surface_gid, name='surface_gid', conditions=conditions)
[docs] def fill_trait(self, datatype): surface_gid = self.surface.value if surface_gid: if not datatype.surface or (datatype.surface and datatype.surface.surface_gid != surface_gid): datatype.surface = CortexViewModel() datatype.surface.surface_gid = surface_gid else: datatype.surface = None
[docs] @staticmethod def prepare_next_fragment_after_surface(simulator, rendering_rules, project_id, cortex_url, stimulus_url): if simulator.surface: return SimulatorRMFragment.prepare_cortex_fragment(simulator, rendering_rules, cortex_url, project_id) return SimulatorStimulusFragment.prepare_stimulus_fragment(simulator, rendering_rules, False, stimulus_url, project_id)
[docs]class SimulatorRMFragment(FormWithRanges): def __init__(self, surface_index=None, connectivity_gid=None): super(SimulatorRMFragment, self).__init__() rm_conditions = None lc_conditions = None if surface_index: rm_conditions = FilterChain(fields=[FilterChain.datatype + '.fk_surface_gid', FilterChain.datatype + '.fk_connectivity_gid'], operations=["==", "=="], values=[str(surface_index.gid), str(connectivity_gid.hex)]) lc_conditions = FilterChain(fields=[rm_conditions.fields[0]], operations=[rm_conditions.operations[0]], values=[rm_conditions.values[0]]) self.rm = TraitDataTypeSelectField(CortexViewModel.region_mapping_data, name='region_mapping_data', conditions=rm_conditions) self.lc = TraitDataTypeSelectField(CortexViewModel.local_connectivity, name='local_connectivity', conditions=lc_conditions) self.coupling_strength = ArrayField(CortexViewModel.coupling_strength)
[docs] @staticmethod def prepare_cortex_fragment(simulator, rendering_rules, form_action_url, project_id): surface_index = load_entity_by_gid(simulator.surface.surface_gid) form = SimulatorRMFragment(surface_index, simulator.connectivity) rm_fragment = AlgorithmService().prepare_adapter_form(form_instance=form, project_id=project_id) rm_fragment.fill_from_trait(simulator.surface) rendering_rules.form = rm_fragment rendering_rules.form_action_url = form_action_url return rendering_rules.to_dict()
[docs]class SimulatorStimulusFragment(ABCAdapterForm): def __init__(self, is_surface_simulation=False): super(SimulatorStimulusFragment, self).__init__() stimuli_index_class = StimuliRegionIndex if is_surface_simulation: stimuli_index_class = SpatioTemporalPatternIndex traited_field = Attr(stimuli_index_class, doc=SimulatorAdapterModel.stimulus.doc, label=SimulatorAdapterModel.stimulus.label, required=SimulatorAdapterModel.stimulus.required) self.stimulus = TraitDataTypeSelectField(traited_field, name='stimulus')
[docs] def fill_trait(self, datatype): setattr(datatype, self.stimulus.name, self.stimulus.data)
[docs] def fill_from_trait(self, trait): self.stimulus.from_trait(trait, self.stimulus.name)
[docs] @staticmethod def prepare_stimulus_fragment(simulator, rendering_rules, is_surface_simulation, form_action_url, project_id): form = SimulatorStimulusFragment(is_surface_simulation) stimuli_fragment = AlgorithmService().prepare_adapter_form(form_instance=form, project_id=project_id) stimuli_fragment.fill_from_trait(simulator) rendering_rules.form = stimuli_fragment rendering_rules.form_action_url = form_action_url return rendering_rules.to_dict()
[docs]class SimulatorModelFragment(ABCAdapterForm): def __init__(self): super(SimulatorModelFragment, self).__init__() default_model = ModelsEnum.GENERIC_2D_OSCILLATOR self.model = SelectField( EnumAttr(default=default_model, label=SimulatorAdapterModel.model.label, doc=SimulatorAdapterModel.model.doc), name='model')
[docs] def fill_from_trait(self, trait): # type: (SimulatorAdapterModel) -> None self.model.data = type(trait.model)
[docs] def fill_trait(self, datatype): if type(datatype.model) != self.model.value: datatype.model = self.model.value.instance
[docs]class SimulatorIntegratorFragment(ABCAdapterForm): def __init__(self): super(SimulatorIntegratorFragment, self).__init__() self.integrator = SelectField( EnumAttr(default=IntegratorViewModelsEnum.HEUN, label=SimulatorAdapterModel.integrator.label, doc=SimulatorAdapterModel.integrator.doc), name='integrator', subform=get_form_for_integrator(IntegratorViewModelsEnum.HEUN.value), ui_values=get_integrator_name_list())
[docs] def fill_from_trait(self, trait): # type: (SimulatorAdapterModel) -> None self.integrator.data = type(trait.integrator)
[docs] def fill_trait(self, datatype): datatype.integrator = self.integrator.value.instance
[docs]class SimulatorMonitorFragment(ABCAdapterForm): def __init__(self, is_surface_simulation=False): super(SimulatorMonitorFragment, self).__init__() self.monitor_choices = get_ui_name_to_monitor_dict(is_surface_simulation) self.is_surface_simulation = is_surface_simulation self.monitors = MultiSelectField(List(of=str, label='Monitors', choices=tuple(self.monitor_choices.keys())), name='monitors')
[docs] def fill_from_trait(self, trait): # type: (SimulatorAdapterModel) -> None self.monitors.data = [ get_monitor_to_ui_name_dict(self.is_surface_simulation)[type(monitor)] for monitor in trait]
[docs]class SimulatorFinalFragment(ABCAdapterForm): def __init__(self, default_simulation_name="simulation_1"): super(SimulatorFinalFragment, self).__init__() self.simulation_length = FloatField(SimulatorAdapterModel.simulation_length) self.simulation_name = StrField(Attr(str, doc='Name for the current simulation configuration', default=default_simulation_name, label='Simulation name'), name='input_simulation_name_id')
[docs] def fill_from_post(self, form_data): super(SimulatorFinalFragment, self).fill_from_post(form_data) validation_result = SimulatorFinalFragment.is_burst_name_ok(self.simulation_name.value) if validation_result is not True: raise ValueError(validation_result)
[docs] @staticmethod def is_burst_name_ok(burst_name): class BurstNameForm(formencode.Schema): """ Validate Burst name string """ burst_name = formencode.All(validators.UnicodeString(not_empty=True), validators.Regex(regex=r"^[a-zA-Z\. _\-0-9]*$")) try: form = BurstNameForm() form.to_python({'burst_name': burst_name}) return True except formencode.Invalid: validation_error = "Invalid simulation name %s. Please use only letters, numbers, or _ " % str(burst_name) return validation_error
[docs] @staticmethod def prepare_final_fragment(simulator, burst_config, project_id, rendering_rules, setup_pse_url): simulation_name, simulation_number = BurstService.prepare_simulation_name(burst_config, project_id) form = SimulatorFinalFragment(default_simulation_name=simulation_name) form.fill_from_trait(simulator) rendering_rules.form = form rendering_rules.form_action_url = setup_pse_url rendering_rules.is_launch_fragment = True rendering_rules.is_pse_launch = burst_config.is_pse_burst() return rendering_rules.to_dict()
[docs]class SimulatorPSEConfigurationFragment(ABCAdapterForm): def __init__(self, choices): super(SimulatorPSEConfigurationFragment, self).__init__() default_choice = choices[0] self.pse_param1 = DynamicSelectField(Str(default=default_choice, label="PSE param1"), choices=choices, name='pse_param1') self.pse_param2 = DynamicSelectField(Str(label="PSE param2", required=False), choices=choices, name='pse_param2')
[docs]class SimulatorPSERangeFragment(ABCAdapterForm): KEY_PARAM1 = 'param1' KEY_PARAM2 = 'param2' NAME_FIELD = 'pse_{}_name' LO_FIELD = 'pse_{}_lo' HI_FIELD = 'pse_{}_hi' STEP_FIELD = 'pse_{}_step' GID_FIELD = 'pse_{}_guid' def __init__(self, pse_param1, pse_param2): # type: (RangeParameter, RangeParameter) -> None super(SimulatorPSERangeFragment, self).__init__() self._add_pse_field(pse_param1) if pse_param2: self._add_pse_field(pse_param2, self.KEY_PARAM2) self.max_pse_number = HiddenField(Int(default=TvbProfile.current.MAX_RANGE_NUMBER, required=False), "max_range_number") def _add_pse_field(self, param, param_key=KEY_PARAM1): # type: (RangeParameter, str) -> None pse_param_name = HiddenField(Str(default=param.name, required=False), self.NAME_FIELD.format(param_key)) self.__setattr__(self.NAME_FIELD.format(param_key), pse_param_name) if param.type is float: self._add_fields_for_float(param, param_key) else: self._add_field_for_gid(param, param_key) def _add_fields_for_float(self, param, param_key): # type: (RangeParameter, str) -> None pse_param_lo = FloatField(Float(label='LO for {}'.format(param.name), default=param.range_definition.lo, required=True), name=self.LO_FIELD.format(param_key)) self.__setattr__(self.LO_FIELD.format(param_key), pse_param_lo) pse_param_hi = FloatField(Float(label='HI for {}'.format(param.name), default=param.range_definition.hi, required=True), name=self.HI_FIELD.format(param_key)) self.__setattr__(self.HI_FIELD.format(param_key), pse_param_hi) pse_param_step = FloatField(Float(label='STEP for {}'.format(param.name), default=param.range_definition.step, required=True), name=self.STEP_FIELD.format(param_key)) self.__setattr__(self.STEP_FIELD.format(param_key), pse_param_step) def _add_field_for_gid(self, param, param_key): # type: (RangeParameter, str) -> None traited_attr = Attr(h5.REGISTRY.get_index_for_datatype(param.type), label='Choice for {}'.format(param.name)) pse_param_dt = TraitDataTypeSelectField(traited_attr, name=self.GID_FIELD.format(param_key), conditions=param.range_definition, has_all_option=True, show_only_all_option=True) self.__setattr__(self.GID_FIELD.format(param_key), pse_param_dt) @staticmethod def _prepare_pse_uuid_list(pse_uuid_str): pse_uuid_str_list = pse_uuid_str.split(',') pse_uuid_list = [uuid.UUID(uuid_str) for uuid_str in pse_uuid_str_list] return pse_uuid_list @staticmethod def _fill_param_from_post(all_range_parameters, param_key, **data): # type: (dict, str, dict) -> RangeParameter param_name = data.get(SimulatorPSERangeFragment.NAME_FIELD.format(param_key)) param = BurstService.get_range_param_by_name(param_name, all_range_parameters) if param.type is float: param_lo = data.get(SimulatorPSERangeFragment.LO_FIELD.format(param_key)) param_hi = data.get(SimulatorPSERangeFragment.HI_FIELD.format(param_key)) param_step = data.get(SimulatorPSERangeFragment.STEP_FIELD.format(param_key)) param_range = RangeParameter(param_name, param.type, Range(float(param_lo), float(param_hi), float(param_step)), is_array=param.is_array) else: param_range_str = data.get(SimulatorPSERangeFragment.GID_FIELD.format(param_key)) param_range = RangeParameter(param_name, param.type, param.range_definition, False, SimulatorPSERangeFragment._prepare_pse_uuid_list(param_range_str)) return param_range
[docs] @staticmethod def fill_from_post(all_range_parameters, **data): # type: (dict, dict) -> tuple param1 = SimulatorPSERangeFragment._fill_param_from_post(all_range_parameters, SimulatorPSERangeFragment.KEY_PARAM1, **data) pse_param2_name = data.get(SimulatorPSERangeFragment.NAME_FIELD.format(SimulatorPSERangeFragment.KEY_PARAM2)) param2 = None if pse_param2_name: param2 = SimulatorPSERangeFragment._fill_param_from_post(all_range_parameters, SimulatorPSERangeFragment.KEY_PARAM2, **data) return param1, param2