Source code for tvb.simulator.common

# -*- coding: utf-8 -*-
#
#
# TheVirtualBrain-Scientific Package. This package holds all simulators, and
# analysers necessary to run brain-simulations. You can use it stand alone or
# in conjunction with TheVirtualBrain-Framework Package. 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
#
#

"""
A module of classes and functions of common use.

.. moduleauthor:: Marmaduke Woodman <marmaduke.woodman@univ-amu.fr>
.. moduleauthor:: Stuart A. Knock <Stuart@tvb.invalid>
.. moduleauthor:: Paula Sanz Leon <Paula@tvb.invalid>

"""

import numpy
import os
import re
import six
import logging
from tvb.basic.logger.builder import GLOBAL_LOGGER_BUILDER, get_logger
from .backend.ref import ReferenceBackend
from deprecated import deprecated



[docs]@deprecated(reason="Use builder.set_logger_level instead") def log_debug(debug=False, timestamp=False, prefix=''): level_name = 'DEBUG' if debug else 'INFO' level = getattr(logging, level_name) GLOBAL_LOGGER_BUILDER.set_loggers_level(level) LOG = get_logger(__name__) for handler in LOG.root.handlers: handler.setLevel(level) # reset formatter more friendly for console work if isinstance(handler, logging.StreamHandler) and not timestamp: if prefix: prefix += ' ' handler.setFormatter(logging.Formatter(prefix + '%(levelname)07s %(message)s')) LOG.info('log level set to %s' % (level_name,))
[docs]def astr(ary): """Make short str repr of numerical value.""" if isinstance(ary, numpy.ndarray): if ary.size == 1: val = ary[0] else: val = 'ndarray(%s, %s)' % (ary.shape, ary.dtype) elif isinstance(ary, bool): val = str(ary) elif isinstance(ary, float) or isinstance(ary, six.integer_types): val = ary else: val = str(ary) if isinstance(val, str): return val else: is_py_int = isinstance(val, six.integer_types) is_np_int = hasattr(val, 'dtype') and numpy.issubdtype(ary.dtype, numpy.integer) if is_py_int or is_np_int: return '%d' % (val,) else: return '%g' % (val,)
[docs]def map_astr(self, names): """Helper for generating a sequence of astr representation of attributes on self""" strs = [] for name in names.split(): strs.append(astr(getattr(self, name))) return tuple(strs)
[docs]def simple_gen_astr(self, names): """Helper for generating str for object with only numerical attributes.""" strs = [] for name, str_ in zip(names.split(), map_astr(self, names)): strs.append('%s=%s' % (name, str_)) clsname = self.__class__.__name__ return '%s(%s)' % (clsname, ', '.join(strs))
numpy_add_at = ReferenceBackend.add_at # loose couple psutil so it's an optional dependency try: import psutil except ImportError: msg = """psutil module not available: no warnings will be issued when a simulation may require more memory than available""" LOG = get_logger(__name__) LOG.warning(msg) psutil = None
[docs]class Struct(dict): """ the Struct class is a dictionary with matlab/C struct-like access to its fields: >>> parameters = Struct(x=23.4345, alpha=1.522e-4) >>> parameters.x + 1 24.4345 >>> parameters.x_init = 6 >>> parameters.x_init + 1 7 >>> print(parameters.y) None note that this class returns None if the field does not exist! """ def __getattr__(self, attr): return self.get(attr, None) __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__
linear_interp1d = ReferenceBackend.linear_interp1d heaviside = ReferenceBackend.heaviside iround = ReferenceBackend.iround
[docs]def zip_directory(path, zip_file): """ Zip a given directory... Didn't know where to put this. I need to pack zips from the scripting interface. To avoid duplicating code I leave this small function here. :param path -- where to store the zip :param zip_file """ for dirname, subdirs, files in os.walk(path): zip_file.write(dirname) for filename in files: zip_file.write(os.path.join(dirname, filename)) zip_file.close()
[docs]def total_ms(duration="", hours=0, minutes=0, seconds=0): re_times = re.compile(r'\s*(\d+\.?\d*)\s*(sec|ms|hr|min|s|m|h)\s*$') re_decimals = re.compile(r'^[0-9]+([,.][0-9]+)?$') total_milliseconds = 0 if duration == "": if not hours == 0: total_milliseconds = hours * 3600000 elif not minutes == 0: total_milliseconds = minutes * 60000 elif not seconds == 0: total_milliseconds = seconds * 1000 elif re_decimals.search(duration): total_milliseconds = float(duration) else: match = re_times.match(duration) if not match: raise ValueError("unable to parse duration %r" % duration) s_time, s_unit = match.group(1, 2) s_time = float(s_time) if s_unit in ('s', 'sec'): total_milliseconds = s_time * 1000 elif s_unit in ('m', 'min'): total_milliseconds = s_time * 60000 elif s_unit in ('hr', 'h'): total_milliseconds = s_time * 3600000 elif s_unit in ('ms'): total_milliseconds = s_time return total_milliseconds