# -*- 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
#
#
"""
Entities to be used with an overlay on Operation or DataType, are defined here.
.. moduleauthor:: Lia Domide <lia.domide@codemart.ro>
"""
import numpy
import six
from tvb.basic.config.utils import EnhancedDictionary
from tvb.core.entities.model.model_datatype import DataTypeGroup
from tvb.core.utils import date2string
[docs]class CommonDetails(EnhancedDictionary):
"""
Enhanced dictionary holding details about an entity.
It also contains metadata on how this details will be displayed in UI (disabled/readonly/hidden input field).
"""
CODE_GID = "gid"
CODE_OPERATION_TAG = "operation_label"
CODE_OPERATION_GROUP_ID = 'operation_group_id'
CODE_OPERATION_GROUP_NAME = 'operation_group_name'
def __init__(self):
super(CommonDetails, self).__init__()
self.metadata = dict()
self.scientific_details = dict()
self.gid = None
self.metadata[self.CODE_GID] = {"name": "Unique Global Identifier", "readonly": "True"}
self.author = None
self.metadata['author'] = {"name": "Author", "disabled": "True"}
self.operation_type = None
self.metadata['operation_type'] = {"name": "Operation Algorithm", "disabled": "True"}
self.operation_label = None
self.metadata[self.CODE_OPERATION_TAG] = {"name": "Operation Label"}
self.count = 1
self.metadata['count'] = {"name": "No. of entities in group", "disabled": "True"}
self.operation_group_id = None
self.metadata[self.CODE_OPERATION_GROUP_ID] = {"name": "groupId", "hidden": "True"}
self.operation_group_name = None
self.metadata[self.CODE_OPERATION_GROUP_NAME] = {"name": "operationGroupName", "hidden": "True"}
self.burst_name = None
self.metadata['burst_name'] = {"name": "Simulation", "disabled": "True"}
[docs] def add_scientific_fields(self, extra_fields_dict):
"""
:param extra_fields_dict a dictionary of fields to be added in a distinct category.
"""
for key, value in six.iteritems(extra_fields_dict):
if value is not None and isinstance(value, numpy.ndarray):
# Make sure arrays are displayed in a compatible form: [1, 2, 3]
value = str(value.tolist())
elif value is not None and isinstance(value, list) and len(value) > 0 and isinstance(value[0], str):
value = [str(v) for v in value]
self.scientific_details[key] = {"name": key, "value": str(value), "disabled": "True"}
@property
def meta_attributes_list(self):
"""
A list with all attributes for a DataType which are expected to be submitted from UI.
"""
result = list(self)
result.remove('metadata')
result.remove('scientific_details')
return result
[docs] @staticmethod
def compute_operation_name(category_name, algorithm_name):
"""
Compute Operation display name, based on Operation Category and Algorithm.
"""
display_name = ''
if category_name:
display_name = category_name
if algorithm_name:
display_name = display_name + "->" + algorithm_name
return display_name
[docs] def get_ui_fields(self):
"""
:returns: list of dictionaries to be used for UI display. \
Each entry in the list will be displayed as a UI group of fields.
"""
framework_metadata = self.metadata
for key in self.meta_attributes_list:
framework_metadata[key]['value'] = getattr(self, key)
if len(self.scientific_details) > 0:
return [self.scientific_details, framework_metadata]
return [framework_metadata]
[docs]class OperationOverlayDetails(CommonDetails):
"""
Entity used for displaying in an overlay details about an operation.
"""
def __init__(self, operation, user_display_name, count_inputs, count_results, burst, no_of_op_in_group, op_pid):
super(OperationOverlayDetails, self).__init__()
self.operation_id = operation.id
self.metadata['operation_id'] = {"name": "Entity id", "disabled": "True"}
self.operation_status = operation.status
self.metadata['operation_status'] = {"name": "Status", "disabled": "True"}
self.start_date = date2string(operation.start_date)
self.metadata['start_date'] = {"name": "Start date", "disabled": "True"}
self.end_date = "None" if operation.completion_date is None else date2string(operation.completion_date)
self.metadata['end_date'] = {"name": "End date", "disabled": "True"}
self.result_datatypes = count_results
self.metadata['result_datatypes'] = {"name": "No. of resulted DataTypes", "disabled": "True"}
self.input_datatypes = count_inputs
self.metadata['input_datatypes'] = {"name": "No. of input DataTypes", "disabled": "True"}
# If the operation was executed in another process or as a cluster then show the pid/job_id
if op_pid is not None:
if op_pid.pid is not None:
self.pid = op_pid.pid
self.metadata['pid'] = {"name": "Process pid", "disabled": "True"}
elif op_pid.job_id is not None:
self.job_id = op_pid.job_id
self.metadata['job_id'] = {"name": "Cluster job Id", "disabled": "True"}
# Now set/update generic fields
self.gid = operation.gid
self.author = user_display_name
self.count = no_of_op_in_group
self.burst_name = burst.name if burst is not None else ""
self.operation_type = self.compute_operation_name(operation.algorithm.algorithm_category.displayname,
operation.algorithm.displayname)
group_id = operation.operation_group.id if operation.operation_group is not None else None
self.operation_group_id = group_id
self.operation_label = (operation.operation_group.name if operation.operation_group is not None
else operation.user_group)
self.metadata[self.CODE_OPERATION_TAG]["disabled"] = 'True'
group_value = operation.operation_group.name if operation.operation_group is not None else None
self.operation_group_name = group_value
self.metadata[self.CODE_OPERATION_GROUP_NAME]["disabled"] = 'True'
[docs]class DataTypeOverlayDetails(CommonDetails):
"""
Entity used for displaying in an overlay details about a DataType.
"""
DATA_SUBJECT = "subject"
DATA_STATE = "data_state"
DATA_TITLE = "datatype_title"
DATA_TAG_1 = "datatype_tag_1"
DATA_TAG_2 = "datatype_tag_2"
DATA_TAG_3 = "datatype_tag_3"
DATA_TAG_4 = "datatype_tag_4"
DATA_TAG_5 = "datatype_tag_5"
def __init__(self):
super(DataTypeOverlayDetails, self).__init__()
self.data_state = None
self.metadata[self.DATA_STATE] = {"name": "State"}
self.datatype_title = None
self.metadata[self.DATA_TITLE] = {"name": "Display Name", "disabled": "True"}
self.subject = None
self.metadata[self.DATA_SUBJECT] = {"name": "Subject"}
self.data_type = None
self.metadata['data_type'] = {"name": "Data Type", "disabled": "True"}
self.data_type_id = None
self.metadata['data_type_id'] = {"name": "Entity id", "disabled": "True"}
self.create_date = None
self.metadata['create_date'] = {"name": "Creation Date", "disabled": "True"}
self.datatype_tag_1 = None
self.metadata[self.DATA_TAG_1] = {"name": "DataType Tag 1"}
self.datatype_tag_2 = None
self.metadata[self.DATA_TAG_2] = {"name": "DataType Tag 2"}
self.datatype_tag_3 = None
self.metadata[self.DATA_TAG_3] = {"name": "DataType Tag 3"}
self.datatype_tag_4 = None
self.metadata[self.DATA_TAG_4] = {"name": "DataType Tag 4"}
self.datatype_tag_5 = None
self.metadata[self.DATA_TAG_5] = {"name": "DataType Tag 5"}
self.datatype_size = None
self.metadata['datatype_size'] = {"name": "Size on Disk (KB)", "disabled": "True"}
[docs] def fill_from_datatype(self, datatype_result, parent_burst):
"""
Fill current dictionary with information from a loaded DB DataType.
:param datatype_result DB loaded DataType
:param parent_burst Burst entity in which current dataType was generated
"""
self.gid = datatype_result.gid
self.data_type_id = datatype_result.id
self.data_state = datatype_result.state
self.datatype_title = datatype_result.display_name
self.subject = datatype_result.subject
self.data_type = datatype_result.display_type
self.datatype_tag_1 = datatype_result.user_tag_1
self.datatype_tag_2 = datatype_result.user_tag_2
self.datatype_tag_3 = datatype_result.user_tag_3
self.datatype_tag_4 = datatype_result.user_tag_4
self.datatype_tag_5 = datatype_result.user_tag_5
self.datatype_size = datatype_result.disk_size
self.author = datatype_result.parent_operation.user.display_name
parent_algorithm = datatype_result.parent_operation.algorithm
operation_name = self.compute_operation_name(parent_algorithm.algorithm_category.displayname,
parent_algorithm.displayname)
self.operation_type = operation_name
create_date_str = ''
if datatype_result.parent_operation.completion_date is not None:
create_date_str = date2string(datatype_result.parent_operation.completion_date)
self.create_date = create_date_str
if parent_burst is not None:
self.burst_name = parent_burst.name
else:
self.burst_name = ''
# Populate Group attributes
if isinstance(datatype_result, DataTypeGroup):
self.count = datatype_result.count_results
self.operation_group_name = datatype_result.parent_operation.operation_group.name
self.operation_label = datatype_result.parent_operation.operation_group.name
self.operation_group_id = datatype_result.parent_operation.operation_group.id
else:
self.operation_label = datatype_result.parent_operation.user_group
# Populate Scientific attributes
self.add_scientific_fields(datatype_result.summary_info)