def check_log_config(self):
        """ Checks and converts all settings if necessary passed to the Manager.

        Searches for multiprocessing options as well.

        """
        if self.report_progress:
            if self.report_progress is True:
                self.report_progress = (5, 'pypet', logging.INFO)
            elif isinstance(self.report_progress, (int, float)):
                self.report_progress = (self.report_progress, 'pypet', logging.INFO)
            elif isinstance(self.report_progress, str):
                self.report_progress = (5, self.report_progress, logging.INFO)
            elif len(self.report_progress) == 2:
                self.report_progress = (self.report_progress[0], self.report_progress[1],
                                        logging.INFO)

        if self.log_config:
            if self.log_config == pypetconstants.DEFAULT_LOGGING:
                pypet_path = os.path.abspath(os.path.dirname(__file__))
                init_path = os.path.join(pypet_path, 'logging')
                self.log_config = os.path.join(init_path, 'default.ini')

            if isinstance(self.log_config, str):
                if not os.path.isfile(self.log_config):
                    raise ValueError('Could not find the logger init file '
                                     '`%s`.' % self.log_config)
                parser = NoInterpolationParser()
                parser.read(self.log_config)
            elif isinstance(self.log_config, cp.RawConfigParser):
                parser = self.log_config
            else:
                parser = None

            if parser is not None:
                self._sp_config = self._parser_to_string_io(parser)
                self._mp_config = self._find_multiproc_options(parser)
                if self._mp_config is not None:
                    self._mp_config = self._parser_to_string_io(self._mp_config)

            elif isinstance(self.log_config, dict):
                self._sp_config = self.log_config
                self._mp_config = self._find_multiproc_dict(self._sp_config)

        if self.log_stdout:
            if self.log_stdout is True:
                self.log_stdout = ('STDOUT', logging.INFO)
            if isinstance(self.log_stdout, str):
                self.log_stdout = (self.log_stdout, logging.INFO)
            if isinstance(self.log_stdout, int):
                self.log_stdout = ('STDOUT', self.log_stdout)

def
check_log_config
(
self
)
:
if
self
.
report_progress
:
if
self
.
report_progress
is
True
:
self
.
report_progress
=
(
5
,
'pypet'
,
logging
.
INFO
)
elif
isinstance
(
self
.
report_progress
,
(
int
,
float
)
)
:
self
.
report_progress
=
(
self
.
report_progress
,
'pypet'
,
logging
.
INFO
)
elif
isinstance
(
self
.
report_progress
,
str
)
:
self
.
report_progress
=
(
5
,
self
.
report_progress
,
logging
.
INFO
)
elif
len
(
self
.
report_progress
)
==
2
:
self
.
report_progress
=
(
self
.
report_progress
[
0
]
,
self
.
report_progress
[
1
]
,
logging
.
INFO
)
if
self
.
log_config
:
if
self
.
log_config
==
pypetconstants
.
DEFAULT_LOGGING
:
pypet_path
=
os
.
path
.
abspath
(
os
.
path
.
dirname
(
__file__
)
)
init_path
=
os
.
path
.
join
(
pypet_path
,
'logging'
)
self
.
log_config
=
os
.
path
.
join
(
init_path
,
'default.ini'
)
if
isinstance
(
self
.
log_config
,
str
)
:
if
not
os
.
path
.
isfile
(
self
.
log_config
)
:
raise
ValueError
(
'Could not find the logger init file '
'`%s`.'
%
self
.
log_config
)
parser
=
NoInterpolationParser
(
)
parser
.
read
(
self
.
log_config
)
elif
isinstance
(
self
.
log_config
,
cp
.
RawConfigParser
)
:
parser
=
self
.
log_config
else
:
parser
=
if
parser
is
not
:
self
.
_sp_config
=
self
.
_parser_to_string_io
(
parser
)
self
.
_mp_config
=
self
.
_find_multiproc_options
(
parser
)
if
self
.
_mp_config
is
not
:
self
.
_mp_config
=
self
.
_parser_to_string_io
(
self
.
_mp_config
)
elif
isinstance
(
self
.
log_config
,
dict
)
:
self
.
_sp_config
=
self
.
log_config
self
.
_mp_config
=
self
.
_find_multiproc_dict
(
self
.
_sp_config
)
if
self
.
log_stdout
:
if
self
.
log_stdout
is
True
:
self
.
log_stdout
=
(
'STDOUT'
,
logging
.
INFO
)
if
isinstance
(
self
.
log_stdout
,
str
)
:
self
.
log_stdout
=
(
self
.
log_stdout
,
logging
.
INFO
)
if
isinstance
(
self
.
log_stdout
,
int
)
:
self
.
log_stdout
=
(
'STDOUT'
,
self
.
log_stdout
)

Checks and converts all settings if necessary passed to the Manager .


def _handle_config_parsing(self, log_config):
        """ Checks for filenames within a config file and translates them.

        Moreover, directories for the files are created as well.

        :param log_config: Config file as a stream (like StringIO)

        """
        parser = NoInterpolationParser()
        parser.readfp(log_config)

        rename_func = lambda string: rename_log_file(string,
                                                     env_name=self.env_name,
                                                     traj_name=self.traj_name,
                                                     set_name=self.set_name,
                                                     run_name=self.run_name)

        sections = parser.sections()
        for section in sections:
            options = parser.options(section)
            for option in options:
                if option == 'args':
                    self._check_and_replace_parser_args(parser, section, option,
                                                        rename_func=rename_func)
        return parser

def _handle_config_parsing ( self , log_config ) : parser = NoInterpolationParser ( ) parser . readfp ( log_config ) rename_func = lambda string : rename_log_file ( string , env_name = self . env_name , traj_name = self . traj_name , set_name = self . set_name , run_name = self . run_name ) sections = parser . sections ( ) for section in sections : options = parser . options ( section ) for option in options : if option == 'args' : self . _check_and_replace_parser_args ( parser , section , option , rename_func = rename_func ) return parser

Checks for filenames within a config file and translates them .


def _handle_dict_config(self, log_config):
        """Recursively walks and copies the `log_config` dict and searches for filenames.

        Translates filenames and creates directories if necessary.

        """
        new_dict = dict()
        for key in log_config.keys():
            if key == 'filename':
                filename = log_config[key]
                filename = rename_log_file(filename,
                                           env_name=self.env_name,
                                           traj_name=self.traj_name,
                                           set_name=self.set_name,
                                           run_name=self.run_name)
                new_dict[key] = filename
                try_make_dirs(filename)
            elif isinstance(log_config[key], dict):
                inner_dict = self._handle_dict_config(log_config[key])
                new_dict[key] = inner_dict
            else:
                new_dict[key] = log_config[key]
        return new_dict

def _handle_dict_config ( self , log_config ) : new_dict = dict ( ) for key in log_config . keys ( ) : if key == 'filename' : filename = log_config [ key ] filename = rename_log_file ( filename , env_name = self . env_name , traj_name = self . traj_name , set_name = self . set_name , run_name = self . run_name ) new_dict [ key ] = filename try_make_dirs ( filename ) elif isinstance ( log_config [ key ] , dict ) : inner_dict = self . _handle_dict_config ( log_config [ key ] ) new_dict [ key ] = inner_dict else : new_dict [ key ] = log_config [ key ] return new_dict

Recursively walks and copies the log_config dict and searches for filenames .


def make_logging_handlers_and_tools(self, multiproc=False):
        """Creates logging handlers and redirects stdout."""

        log_stdout = self.log_stdout
        if sys.stdout is self._stdout_to_logger:
            # If we already redirected stdout we don't neet to redo it again
            log_stdout = False

        if self.log_config:
            if multiproc:
                proc_log_config = self._mp_config
            else:
                proc_log_config = self._sp_config

            if proc_log_config:
                if isinstance(proc_log_config, dict):
                    new_dict = self._handle_dict_config(proc_log_config)
                    dictConfig(new_dict)
                else:
                    parser = self._handle_config_parsing(proc_log_config)
                    memory_file = self._parser_to_string_io(parser)
                    fileConfig(memory_file, disable_existing_loggers=False)

        if log_stdout:
            #  Create a logging mock for stdout
            std_name, std_level = self.log_stdout

            stdout = StdoutToLogger(std_name, log_level=std_level)
            stdout.start()
            self._tools.append(stdout)

def make_logging_handlers_and_tools ( self , multiproc = False ) : log_stdout = self . log_stdout if sys . stdout is self . _stdout_to_logger : log_stdout = False if self . log_config : if multiproc : proc_log_config = self . _mp_config else : proc_log_config = self . _sp_config if proc_log_config : if isinstance ( proc_log_config , dict ) : new_dict = self . _handle_dict_config ( proc_log_config ) dictConfig ( new_dict ) else : parser = self . _handle_config_parsing ( proc_log_config ) memory_file = self . _parser_to_string_io ( parser ) fileConfig ( memory_file , disable_existing_loggers = False ) if log_stdout : std_name , std_level = self . log_stdout stdout = StdoutToLogger ( std_name , log_level = std_level ) stdout . start ( ) self . _tools . append ( stdout )

Creates logging handlers and redirects stdout .


def finalize(self, remove_all_handlers=True):
        """Finalizes the manager, closes and removes all handlers if desired."""
        for tool in self._tools:
            tool.finalize()
        self._tools = []
        self._stdout_to_logger = None
        for config in (self._sp_config, self._mp_config):
            if hasattr(config, 'close'):
                config.close()
        self._sp_config = None
        self._mp_config = None
        if remove_all_handlers:
            self.tabula_rasa()

def finalize ( self , remove_all_handlers = True ) : for tool in self . _tools : tool . finalize ( ) self . _tools = [ ] self . _stdout_to_logger = None for config in ( self . _sp_config , self . _mp_config ) : if hasattr ( config , 'close' ) : config . close ( ) self . _sp_config = None self . _mp_config = None if remove_all_handlers : self . tabula_rasa ( )

Finalizes the manager closes and removes all handlers if desired .


def start(self):
        """Starts redirection of `stdout`"""
        if sys.stdout is not self:
            self._original_steam = sys.stdout
            sys.stdout = self
            self._redirection = True
        if self._redirection:
            print('Established redirection of `stdout`.')

def
start
(
self
)
:
if
sys
.
stdout
is
not
self
:
self
.
_original_steam
=
sys
.
stdout
sys
.
stdout
=
self
self
.
_redirection
=
True
if
self
.
_redirection
:
print
(
'Established redirection of `stdout`.'
)


def write(self, buf):
        """Writes data from buffer to logger"""
        if not self._recursion:
            self._recursion = True
            try:
                for line in buf.rstrip().splitlines():
                    self._logger.log(self._log_level, line.rstrip())
            finally:
                self._recursion = False
        else:
            # If stderr is redirected to stdout we can avoid further recursion by
            sys.__stderr__.write('ERROR: Recursion in Stream redirection!')


def results_equal(a, b):
    """Compares two result instances

    Checks full name and all data. Does not consider the comment.

    :return: True or False

    :raises: ValueError if both inputs are no result instances

    """
    if a.v_is_parameter and b.v_is_parameter:
        raise ValueError('Both inputs are not results.')

    if a.v_is_parameter or b.v_is_parameter:
        return False

    if a.v_full_name != b.v_full_name:
        return False

    if hasattr(a, '_data') and not hasattr(b, '_data'):
        return False

    if hasattr(a, '_data'):
        akeyset = set(a._data.keys())
        bkeyset = set(b._data.keys())

        if akeyset != bkeyset:
            return False

        for key in a._data:
            val = a._data[key]
            bval = b._data[key]

            if not nested_equal(val, bval):
                return False

    return True

def
results_equal
(
a
,
b
)
:
if
a
.
v_is_parameter
and
b
.
v_is_parameter
:
raise
ValueError
(
'Both inputs are not results.'
)
if
a
.
v_is_parameter
or
b
.
v_is_parameter
:
return
False
if
a
.
v_full_name
!=
b
.
v_full_name
:
return
False
if
hasattr
(
a
,
'_data'
)
and
not
hasattr
(
b
,
'_data'
)
:
return
False
if
hasattr
(
a
,
'_data'
)
:
akeyset
=
set
(
a
.
_data
.
keys
(
)
)
bkeyset
=
set
(
b
.
_data
.
keys
(
)
)
if
akeyset
!=
bkeyset
:
return
False
for
key
in
a
.
_data
:
val
=
a
.
_data
[
key
]
bval
=
b
.
_data
[
key
]
if
not
nested_equal
(
val
,
bval
)
:
return
False
return
True


def parameters_equal(a, b):
    """Compares two parameter instances

    Checks full name, data, and ranges. Does not consider the comment.

    :return: True or False

    :raises: ValueError if both inputs are no parameter instances

    """
    if (not b.v_is_parameter and
            not a.v_is_parameter):
        raise ValueError('Both inputs are not parameters')

    if (not b.v_is_parameter or
            not a.v_is_parameter):
        return False

    if a.v_full_name != b.v_full_name:
        return False

    if a.f_is_empty() and b.f_is_empty():
        return True

    if a.f_is_empty() != b.f_is_empty():
        return False

    if not a._values_of_same_type(a.f_get(), b.f_get()):
        return False

    if not a._equal_values(a.f_get(), b.f_get()):
        return False

    if a.f_has_range() != b.f_has_range():
        return False

    if a.f_has_range():
        if a.f_get_range_length() != b.f_get_range_length():
            return False

        for myitem, bitem in zip(a.f_get_range(copy=False), b.f_get_range(copy=False)):
            if not a._values_of_same_type(myitem, bitem):
                return False
            if not a._equal_values(myitem, bitem):
                return False

    return True

def
parameters_equal
(
a
,
b
)
:
if
(
not
b
.
v_is_parameter
and
not
a
.
v_is_parameter
)
:
raise
ValueError
(
'Both inputs are not parameters'
)
if
(
not
b
.
v_is_parameter
or
not
a
.
v_is_parameter
)
:
return
False
if
a
.
v_full_name
!=
b
.
v_full_name
:
return
False
if
a
.
f_is_empty
(
)
and
b
.
f_is_empty
(
)
:
return
True
if
a
.
f_is_empty
(
)
!=
b
.
f_is_empty
(
)
:
return
False
if
not
a
.
_values_of_same_type
(
a
.
f_get
(
)
,
b
.
f_get
(
)
)
:
return
False
if
not
a
.
_equal_values
(
a
.
f_get
(
)
,
b
.
f_get
(
)
)
:
return
False
if
a
.
f_has_range
(
)
!=
b
.
f_has_range
(
)
:
return
False
if
a
.
f_has_range
(
)
:
if
a
.
f_get_range_length
(
)
!=
b
.
f_get_range_length
(
)
:
return
False
for
myitem
,
bitem
in
zip
(
a
.
f_get_range
(
copy
=
False
)
,
b
.
f_get_range
(
copy
=
False
)
)
:
if
not
a
.
_values_of_same_type
(
myitem
,
bitem
)
:
return
False
if
not
a
.
_equal_values
(
myitem
,
bitem
)
:
return
False
return
True


def manual_run(turn_into_run=True, store_meta_data=True, clean_up=True):
    """Can be used to decorate a function as a manual run function.

    This can be helpful if you want the run functionality without using an environment.

    :param turn_into_run:

        If the trajectory should become a `single run` with more specialized functionality
        during a single run.

    :param store_meta_data:

        If meta-data like runtime should be automatically stored

    :param clean_up:

        If all data added during the single run should be removed, only works
        if ``turn_into_run=True``.

    """
    def wrapper(func):
        @functools.wraps(func)
        def new_func(traj, *args, **kwargs):
            do_wrap = not traj._run_by_environment
            if do_wrap:
                traj.f_start_run(turn_into_run=turn_into_run)
            result = func(traj, *args, **kwargs)
            if do_wrap:
                traj.f_finalize_run(store_meta_data=store_meta_data,
                                    clean_up=clean_up)
            return result

        return new_func

    return wrapper

def manual_run ( turn_into_run = True , store_meta_data = True , clean_up = True ) : def wrapper ( func ) : @ functools . wraps ( func ) def new_func ( traj , * args , ** kwargs ) : do_wrap = not traj . _run_by_environment if do_wrap : traj . f_start_run ( turn_into_run = turn_into_run ) result = func ( traj , * args , ** kwargs ) if do_wrap : traj . f_finalize_run ( store_meta_data = store_meta_data , clean_up = clean_up ) return result return new_func return wrapper

Can be used to decorate a function as a manual run function .


def deprecated(msg=''):
    """This is a decorator which can be used to mark functions
    as deprecated. It will result in a warning being emitted
    when the function is used.

    :param msg:

        Additional message added to the warning.

    """

    def wrapper(func):
        @functools.wraps(func)
        def new_func(*args, **kwargs):
            warning_string = "Call to deprecated function or property `%s`." % func.__name__
            warning_string = warning_string + ' ' + msg
            warnings.warn(
                warning_string,
                category=DeprecationWarning,
            )
            return func(*args, **kwargs)

        return new_func

    return wrapper

This is a decorator which can be used to mark functions as deprecated . It will result in a warning being emitted when the function is used .


def kwargs_mutual_exclusive(param1_name, param2_name, map2to1=None):
    """ If there exist mutually exclusive parameters checks for them and maps param2 to 1."""
    def wrapper(func):
        @functools.wraps(func)
        def new_func(*args, **kwargs):
            if param2_name in kwargs:
                if param1_name in kwargs:
                    raise ValueError('You cannot specify `%s` and `%s` at the same time, '
                                     'they are mutually exclusive.' % (param1_name, param2_name))
                param2 = kwargs.pop(param2_name)
                if map2to1 is not None:
                    param1 = map2to1(param2)
                else:
                    param1 = param2
                kwargs[param1_name] = param1

            return func(*args, **kwargs)

        return new_func

    return wrapper

If there exist mutually exclusive parameters checks for them and maps param2 to 1 .


def kwargs_api_change(old_name, new_name=None):
    """This is a decorator which can be used if a kwarg has changed
    its name over versions to also support the old argument name.

    Issues a warning if the old keyword argument is detected and
    converts call to new API.

    :param old_name:

        Old name of the keyword argument

    :param new_name:

        New name of keyword argument

    """

    def wrapper(func):
        @functools.wraps(func)
        def new_func(*args, **kwargs):

            if old_name in kwargs:
                if new_name is None:
                    warning_string = 'Using deprecated keyword argument `%s` in function `%s`. ' \
                                 'This keyword is no longer supported, please don`t use it ' \
                                 'anymore.' % (old_name, func.__name__)
                else:
                    warning_string = 'Using deprecated keyword argument `%s` in function `%s`, ' \
                                 'please use keyword `%s` instead.' % \
                                 (old_name, func.__name__, new_name)
                warnings.warn(warning_string, category=DeprecationWarning)
                value = kwargs.pop(old_name)
                if new_name is not None:
                    kwargs[new_name] = value

            return func(*args, **kwargs)

        return new_func

    return wrapper

This is a decorator which can be used if a kwarg has changed its name over versions to also support the old argument name .


def retry(n, errors, wait=0.0, logger_name=None):
    """This is a decorator that retries a function.

    Tries `n` times and catches a given tuple of `errors`.

    If the `n` retries are not enough, the error is reraised.

    If desired `waits` some seconds.

    Optionally takes a 'logger_name' of a given logger to print the caught error.

    """

    def wrapper(func):
        @functools.wraps(func)
        def new_func(*args, **kwargs):
            retries = 0
            while True:
                try:
                    result = func(*args, **kwargs)
                    if retries and logger_name:
                        logger = logging.getLogger(logger_name)
                        logger.debug('Retry of `%s` successful' % func.__name__)
                    return result
                except errors:
                    if retries >= n:
                        if logger_name:
                            logger = logging.getLogger(logger_name)
                            logger.exception('I could not execute `%s` with args %s and kwargs %s, '
                                             'starting next try. ' % (func.__name__,
                                                                      str(args),
                                                                      str(kwargs)))
                        raise
                    elif logger_name:
                        logger = logging.getLogger(logger_name)
                        logger.debug('I could not execute `%s` with args %s and kwargs %s, '
                                         'starting next try. ' % (func.__name__,
                                                                  str(args),
                                                                  str(kwargs)))
                    retries += 1
                    if wait:
                        time.sleep(wait)
        return new_func

    return wrapper

This is a decorator that retries a function .


def prefix_naming(cls):
    """Decorate that adds the prefix naming scheme"""
    if hasattr(cls, '__getattr__'):
        raise TypeError('__getattr__ already defined')
    cls.__getattr__ = _prfx_getattr_
    cls.__setattr__ = _prfx_setattr_
    return cls

def
prefix_naming
(
cls
)
:
if
hasattr
(
cls
,
'__getattr__'
)
:
raise
TypeError
(
'__getattr__ already defined'
)
cls
.
__getattr__
=
_prfx_getattr_
cls
.
__setattr__
=
_prfx_setattr_
return
cls


def add_params(traj):
    """Adds all necessary parameters to `traj`."""

    # We set the BrianParameter to be the standard parameter
    traj.v_standard_parameter=Brian2Parameter
    traj.v_fast_access=True

    # Add parameters we need for our network
    traj.f_add_parameter('Net.C',281*pF)
    traj.f_add_parameter('Net.gL',30*nS)
    traj.f_add_parameter('Net.EL',-70.6*mV)
    traj.f_add_parameter('Net.VT',-50.4*mV)
    traj.f_add_parameter('Net.DeltaT',2*mV)
    traj.f_add_parameter('Net.tauw',40*ms)
    traj.f_add_parameter('Net.a',4*nS)
    traj.f_add_parameter('Net.b',0.08*nA)
    traj.f_add_parameter('Net.I',.8*nA)
    traj.f_add_parameter('Net.Vcut','vm > 0*mV') # practical threshold condition
    traj.f_add_parameter('Net.N',50)

    eqs='''
    dvm/dt=(gL*(EL-vm)+gL*DeltaT*exp((vm-VT)/DeltaT)+I-w)/C : volt
    dw/dt=(a*(vm-EL)-w)/tauw : amp
    Vr:volt
    '''
    traj.f_add_parameter('Net.eqs', eqs)
    traj.f_add_parameter('reset', 'vm=Vr;w+=b')

def
add_params
(
traj
)
:
traj
.
v_standard_parameter
=
Brian2Parameter
traj
.
v_fast_access
=
True
traj
.
f_add_parameter
(
'Net.C'
,
281
*
pF
)
traj
.
f_add_parameter
(
'Net.gL'
,
30
*
nS
)
traj
.
f_add_parameter
(
'Net.EL'
,
70.6
*
mV
)
traj
.
f_add_parameter
(
'Net.VT'
,
50.4
*
mV
)
traj
.
f_add_parameter
(
'Net.DeltaT'
,
2
*
mV
)
traj
.
f_add_parameter
(
'Net.tauw'
,
40
*
ms
)
traj
.
f_add_parameter
(
'Net.a'
,
4
*
nS
)
traj
.
f_add_parameter
(
'Net.b'
,
0.08
*
)
traj
.
f_add_parameter
(
'Net.I'
,
.8
*
)
traj
.
f_add_parameter
(
'Net.Vcut'
,
'vm > 0*mV'
)
traj
.
f_add_parameter
(
'Net.N'
,
50
)
eqs
=
traj
.
f_add_parameter
(
'Net.eqs'
,
eqs
)
traj
.
f_add_parameter
(
'reset'
,
'vm=Vr;w+=b'
)


def run_net(traj):
    """Creates and runs BRIAN network based on the parameters in `traj`."""

    eqs=traj.eqs

    # Create a namespace dictionairy
    namespace = traj.Net.f_to_dict(short_names=True, fast_access=True)
    # Create the Neuron Group
    neuron=NeuronGroup(traj.N, model=eqs, threshold=traj.Vcut, reset=traj.reset,
                       namespace=namespace)
    neuron.vm=traj.EL
    neuron.w=traj.a*(neuron.vm-traj.EL)
    neuron.Vr=linspace(-48.3*mV,-47.7*mV,traj.N) # bifurcation parameter

    # Run the network initially for 100 milliseconds
    print('Initial Run')
    net = Network(neuron)
    net.run(100*ms, report='text') # we discard the first spikes

    # Create a Spike Monitor
    MSpike=SpikeMonitor(neuron)
    net.add(MSpike)
    # Create a State Monitor for the membrane voltage, record from neurons 1-3
    MStateV = StateMonitor(neuron, variables=['vm'],record=[1,2,3])
    net.add(MStateV)

    # Now record for 500 milliseconds
    print('Measurement run')
    net.run(500*ms,report='text')

    # Add the BRAIN monitors
    traj.v_standard_result = Brian2MonitorResult
    traj.f_add_result('SpikeMonitor',MSpike)
    traj.f_add_result('StateMonitorV', MStateV)

def
run_net
(
traj
)
:
eqs
=
traj
.
eqs
namespace
=
traj
.
Net
.
f_to_dict
(
short_names
=
True
,
fast_access
=
True
)
neuron
=
NeuronGroup
(
traj
.
N
,
model
=
eqs
,
threshold
=
traj
.
Vcut
,
reset
=
traj
.
reset
,
namespace
=
namespace
)
neuron
.
vm
=
traj
.
EL
neuron
.
w
=
traj
.
a
*
(
neuron
.
vm
traj
.
EL
)
neuron
.
Vr
=
linspace
(
48.3
*
mV
,
47.7
*
mV
,
traj
.
N
)
print
(
'Initial Run'
)
net
=
Network
(
neuron
)
net
.
run
(
100
*
ms
,
report
=
'text'
)
MSpike
=
SpikeMonitor
(
neuron
)
net
.
add
(
MSpike
)
MStateV
=
StateMonitor
(
neuron
,
variables
=
[
'vm'
]
,
record
=
[
1
,
2
,
3
]
)
net
.
add
(
MStateV
)
print
(
'Measurement run'
)
net
.
run
(
500
*
ms
,
report
=
'text'
)
traj
.
v_standard_result
=
Brian2MonitorResult
traj
.
f_add_result
(
'SpikeMonitor'
,
MSpike
)
traj
.
f_add_result
(
'StateMonitorV'
,
MStateV
)

Creates and runs BRIAN network based on the parameters in traj .


def euler_scheme(traj, diff_func):
    """Simulation function for Euler integration.

    :param traj:

        Container for parameters and results

    :param diff_func:

        The differential equation we want to integrate

    """

    steps = traj.steps
    initial_conditions = traj.initial_conditions
    dimension = len(initial_conditions)

    # This array will collect the results
    result_array = np.zeros((steps,dimension))
    # Get the function parameters stored into `traj` as a dictionary
    # with the (short) names as keys :
    func_params_dict = traj.func_params.f_to_dict(short_names=True, fast_access=True)
    # Take initial conditions as first result
    result_array[0] = initial_conditions

    # Now we compute the Euler Scheme steps-1 times
    for idx in range(1,steps):
        result_array[idx] = diff_func(result_array[idx-1], **func_params_dict) * traj.dt + \
                            result_array[idx-1]
    # Note the **func_params_dict unzips the dictionary, it's the reverse of **kwargs in function
    # definitions!

    #Finally we want to keep the results
    traj.f_add_result('euler_evolution', data=result_array, comment='Our time series data!')

def
euler_scheme
(
traj
,
diff_func
)
:
steps
=
traj
.
steps
initial_conditions
=
traj
.
initial_conditions
dimension
=
len
(
initial_conditions
)
result_array
=
np
.
zeros
(
(
steps
,
dimension
)
)
func_params_dict
=
traj
.
func_params
.
f_to_dict
(
short_names
=
True
,
fast_access
=
True
)
result_array
[
0
]
=
initial_conditions
for
idx
in
range
(
1
,
steps
)
:
result_array
[
idx
]
=
diff_func
(
result_array
[
idx
1
]
,
**
func_params_dict
)
*
traj
.
dt
+
result_array
[
idx
1
]
traj
.
f_add_result
(
'euler_evolution'
,
data
=
result_array
,
comment
=
'Our time series data!'
)

Simulation function for Euler integration .


def add_parameters(traj):
    """Adds all necessary parameters to the `traj` container"""

    traj.f_add_parameter('steps', 10000, comment='Number of time steps to simulate')
    traj.f_add_parameter('dt', 0.01, comment='Step size')

    # Here we want to add the initial conditions as an array parameter. We will simulate
    # a 3-D differential equation, the Lorenz attractor.
    traj.f_add_parameter(ArrayParameter,'initial_conditions', np.array([0.0,0.0,0.0]),
                         comment = 'Our initial conditions, as default we will start from'
                                   ' origin!')

    # We will group all parameters of the Lorenz differential equation into the group 'func_params'
    traj.f_add_parameter('func_params.sigma', 10.0)
    traj.f_add_parameter('func_params.beta', 8.0/3.0)
    traj.f_add_parameter('func_params.rho', 28.0)

    #For the fun of it we will annotate the  group
    traj.func_params.v_annotations.info='This group contains as default the original values chosen ' \
                                   'by Edward Lorenz in 1963. Check it out on wikipedia ' \
                                   '(https://en.wikipedia.org/wiki/Lorenz_attractor)!'

Adds all necessary parameters to the traj container


def diff_lorenz(value_array, sigma, beta, rho):
    """The Lorenz attractor differential equation

    :param value_array: 3d array containing the x,y, and z component values.
    :param sigma: Constant attractor parameter
    :param beta: FConstant attractor parameter
    :param rho: Constant attractor parameter

    :return: 3d array of the Lorenz system evaluated at `value_array`

    """
    diff_array = np.zeros(3)
    diff_array[0] = sigma * (value_array[1]-value_array[0])
    diff_array[1] = value_array[0] * (rho - value_array[2]) - value_array[1]
    diff_array[2] = value_array[0] * value_array[1] - beta * value_array[2]

    return diff_array


def _create_storage(storage_service, trajectory=None, **kwargs):
    """Creates a service from a constructor and checks which kwargs are not used"""
    kwargs_copy = kwargs.copy()
    kwargs_copy['trajectory'] = trajectory
    matching_kwargs = get_matching_kwargs(storage_service, kwargs_copy)
    storage_service = storage_service(**matching_kwargs)
    unused_kwargs = set(kwargs.keys()) - set(matching_kwargs.keys())
    return storage_service, unused_kwargs

def _create_storage ( storage_service , trajectory = None , ** kwargs ) : kwargs_copy = kwargs . copy ( ) kwargs_copy [ 'trajectory' ] = trajectory matching_kwargs = get_matching_kwargs ( storage_service , kwargs_copy ) storage_service = storage_service ( ** matching_kwargs ) unused_kwargs = set ( kwargs . keys ( ) ) - set ( matching_kwargs . keys ( ) ) return storage_service , unused_kwargs


def storage_factory(storage_service, trajectory=None, **kwargs):
    """Creates a storage service, to be extended if new storage services are added

    :param storage_service:

        Storage Service instance of constructor or a string pointing to a file

    :param trajectory:

        A trajectory instance

    :param kwargs:

        Arguments passed to the storage service

    :return:

        A storage service and a set of not used keyword arguments from kwargs

    """

    if 'filename' in kwargs and storage_service is None:
        filename = kwargs['filename']
        _, ext = os.path.splitext(filename)
        if ext in ('.hdf', '.h4', '.hdf4', '.he2', '.h5', '.hdf5', '.he5'):
            storage_service = HDF5StorageService
        else:
            raise ValueError('Extension `%s` of filename `%s` not understood.' %
                             (ext, filename))
    elif isinstance(storage_service, str):
        class_name = storage_service.split('.')[-1]
        storage_service = create_class(class_name, [storage_service, HDF5StorageService])

    if inspect.isclass(storage_service):
        return _create_storage(storage_service, trajectory, **kwargs)
    else:
        return storage_service, set(kwargs.keys())

Creates a storage service to be extended if new storage services are added


def add_parameters(traj):
    """Adds all necessary parameters to the `traj` container.

    You can choose between two parameter sets. One for the Lorenz attractor and
    one for the Roessler attractor.
    The former is chosen for `traj.diff_name=='diff_lorenz'`, the latter for
    `traj.diff_name=='diff_roessler'`.
    You can use parameter presetting to switch between the two cases.

    :raises: A ValueError if `traj.diff_name` is none of the above

    """
    traj.f_add_parameter('steps', 10000, comment='Number of time steps to simulate')
    traj.f_add_parameter('dt', 0.01, comment='Step size')

    # Here we want to add the initial conditions as an array parameter, since we will simulate
    # a 3-D differential equation, that is the Roessler attractor
    # (https://en.wikipedia.org/wiki/R%C3%B6ssler_attractor)
    traj.f_add_parameter(ArrayParameter,'initial_conditions', np.array([0.0,0.0,0.0]),
                         comment = 'Our initial conditions, as default we will start from'
                                   ' origin!')

    # Per default we choose the name `'diff_lorenz'` as in the last example
    traj.f_add_parameter('diff_name','diff_lorenz', comment= 'Name of our differential equation')

    # We want some control flow depending on which name we really choose
    if traj.diff_name == 'diff_lorenz':
        # These parameters are for the Lorenz differential equation
        traj.f_add_parameter('func_params.sigma', 10.0)
        traj.f_add_parameter('func_params.beta', 8.0/3.0)
        traj.f_add_parameter('func_params.rho', 28.0)
    elif traj.diff_name == 'diff_roessler':
        # If we use the Roessler system we need different parameters
        traj.f_add_parameter('func_params.a', 0.1)
        traj.f_add_parameter('func_params.c', 14.0)
    else:
        raise ValueError('I don\'t know what %s is.' % traj.diff_name)

Adds all necessary parameters to the traj container .


def diff_roessler(value_array, a, c):
    """The Roessler attractor differential equation

    :param value_array: 3d array containing the x,y, and z component values.
    :param a: Constant attractor parameter
    :param c: Constant attractor parameter

    :return: 3d array of the Roessler system evaluated at `value_array`

    """
    b=a
    diff_array = np.zeros(3)
    diff_array[0] = -value_array[1] - value_array[2]
    diff_array[1] = value_array[0] + a * value_array[1]
    diff_array[2] = b + value_array[2] * (value_array[0] - c)

    return diff_array

def diff_roessler ( value_array , a , c ) : b = a diff_array = np . zeros ( 3 ) diff_array [ 0 ] = - value_array [ 1 ] - value_array [ 2 ] diff_array [ 1 ] = value_array [ 0 ] + a * value_array [ 1 ] diff_array [ 2 ] = b + value_array [ 2 ] * ( value_array [ 0 ] - c ) return diff_array


def compact_hdf5_file(filename, name=None, index=None, keep_backup=True):
    """Can compress an HDF5 to reduce file size.

    The properties on how to compress the new file are taken from a given
    trajectory in the file.
    Simply calls ``ptrepack`` from the command line.
    (Se also https://pytables.github.io/usersguide/utilities.html#ptrepackdescr)

    Currently only supported under Linux, no guarantee for Windows usage.

    :param filename:

        Name of the file to compact

    :param name:

        The name of the trajectory from which the compression properties are taken

    :param index:

        Instead of a name you could also specify an index, i.e -1 for the last trajectory
        in the file.

    :param keep_backup:

        If a back up version of the original file should be kept.
        The backup file is named as the original but `_backup` is appended to the end.

    :return:

        The return/error code of ptrepack

    """
    if name is None and index is None:
        index = -1

    tmp_traj = load_trajectory(name, index, as_new=False, load_all=pypetconstants.LOAD_NOTHING,
                               force=True, filename=filename)
    service = tmp_traj.v_storage_service
    complevel = service.complevel
    complib = service.complib
    shuffle = service.shuffle
    fletcher32 = service.fletcher32

    name_wo_ext, ext = os.path.splitext(filename)
    tmp_filename = name_wo_ext + '_tmp' + ext

    abs_filename = os.path.abspath(filename)
    abs_tmp_filename = os.path.abspath(tmp_filename)

    command = ['ptrepack', '-v',
               '--complib', complib,
               '--complevel', str(complevel),
               '--shuffle', str(int(shuffle)),
               '--fletcher32', str(int(fletcher32)),
               abs_filename, abs_tmp_filename]
    str_command = ' '.join(command)
    print('Executing command `%s`' % str_command)

    retcode = subprocess.call(command)
    if retcode != 0:
        print('#### ERROR: Compacting `%s` failed with errorcode %s! ####' %
              (filename, str(retcode)))
    else:
        print('#### Compacting successful ####')
        print('Renaming files')
        if keep_backup:
            backup_file_name = name_wo_ext + '_backup' + ext
            os.rename(filename, backup_file_name)
        else:
            os.remove(filename)
        os.rename(tmp_filename, filename)
        print('### Compacting and Renaming finished ####')

    return retcode

Can compress an HDF5 to reduce file size .


def _explored_parameters_in_group(traj, group_node):
    """Checks if one the parameters in `group_node` is explored.

    :param traj: Trajectory container
    :param group_node: Group node
    :return: `True` or `False`

    """
    explored = False
    for param in traj.f_get_explored_parameters():
            if param in group_node:
                explored = True
                break

    return explored

def _explored_parameters_in_group ( traj , group_node ) : explored = False for param in traj . f_get_explored_parameters ( ) : if param in group_node : explored = True break return explored

Checks if one the parameters in group_node is explored .


def _build_model_eqs(traj):
        """Computes model equations for the excitatory and inhibitory population.

        Equation objects are created by fusing `model.eqs` and `model.synaptic.eqs`
        and replacing `PRE` by `i` (for inhibitory) or `e` (for excitatory) depending
        on the type of population.

        :return: Dictionary with 'i' equation object for inhibitory neurons and 'e' for excitatory

        """
        model_eqs = traj.model.eqs
        post_eqs={}
        for name_post in ['i','e']:
            variables_dict ={}
            new_model_eqs=model_eqs.replace('POST', name_post)
            for name_pre in ['i', 'e']:
                conn_eqs = traj.model.synaptic.eqs
                new_conn_eqs = conn_eqs.replace('PRE', name_pre)
                new_model_eqs += new_conn_eqs

                tau1 = traj.model.synaptic['tau1']
                tau2 = traj.model.synaptic['tau2_'+name_pre]

                normalization = (tau1-tau2) / tau2
                invtau1=1.0/tau1
                invtau2 = 1.0/tau2

                variables_dict['invtau1_'+name_pre] = invtau1
                variables_dict['invtau2_'+name_pre] = invtau2
                variables_dict['normalization_'+name_pre] = normalization
                variables_dict['tau1_'+name_pre] = tau1
                variables_dict['tau2_'+name_pre] = tau2

            variables_dict['tau_'+name_post] = traj.model['tau_'+name_post]

            post_eqs[name_post] = Equations(new_model_eqs, **variables_dict)

        return post_eqs

def _build_model_eqs ( traj ) : model_eqs = traj . model . eqs post_eqs = { } for name_post in [ 'i' , 'e' ] : variables_dict = { } new_model_eqs = model_eqs . replace ( 'POST' , name_post ) for name_pre in [ 'i' , 'e' ] : conn_eqs = traj . model . synaptic . eqs new_conn_eqs = conn_eqs . replace ( 'PRE' , name_pre ) new_model_eqs += new_conn_eqs tau1 = traj . model . synaptic [ 'tau1' ] tau2 = traj . model . synaptic [ 'tau2_' + name_pre ] normalization = ( tau1 - tau2 ) / tau2 invtau1 = 1.0 / tau1 invtau2 = 1.0 / tau2 variables_dict [ 'invtau1_' + name_pre ] = invtau1 variables_dict [ 'invtau2_' + name_pre ] = invtau2 variables_dict [ 'normalization_' + name_pre ] = normalization variables_dict [ 'tau1_' + name_pre ] = tau1 variables_dict [ 'tau2_' + name_pre ] = tau2 variables_dict [ 'tau_' + name_post ] = traj . model [ 'tau_' + name_post ] post_eqs [ name_post ] = Equations ( new_model_eqs , ** variables_dict ) return post_eqs

Computes model equations for the excitatory and inhibitory population .


def pre_build(self, traj, brian_list, network_dict):
        """Pre-builds the neuron groups.

        Pre-build is only performed if none of the
        relevant parameters is explored.

        :param traj: Trajectory container

        :param brian_list:

            List of objects passed to BRIAN network constructor.

            Adds:

            Inhibitory neuron group

            Excitatory neuron group

        :param network_dict:

            Dictionary of elements shared among the components

            Adds:

            'neurons_i': Inhibitory neuron group

            'neurons_e': Excitatory neuron group

        """
        self._pre_build = not _explored_parameters_in_group(traj, traj.parameters.model)

        if self._pre_build:
            self._build_model(traj, brian_list, network_dict)

def pre_build ( self , traj , brian_list , network_dict ) : self . _pre_build = not _explored_parameters_in_group ( traj , traj . parameters . model ) if self . _pre_build : self . _build_model ( traj , brian_list , network_dict )


def build(self, traj, brian_list, network_dict):
        """Builds the neuron groups.

        Build is only performed if neuron group was not
        pre-build before.

        :param traj: Trajectory container

        :param brian_list:

            List of objects passed to BRIAN network constructor.

            Adds:

            Inhibitory neuron group

            Excitatory neuron group

        :param network_dict:

            Dictionary of elements shared among the components

            Adds:

            'neurons_i': Inhibitory neuron group

            'neurons_e': Excitatory neuron group

        """
        if not hasattr(self, '_pre_build') or not self._pre_build:
            self._build_model(traj, brian_list, network_dict)

def build ( self , traj , brian_list , network_dict ) : if not hasattr ( self , '_pre_build' ) or not self . _pre_build : self . _build_model ( traj , brian_list , network_dict )


def _build_model(self, traj, brian_list, network_dict):
        """Builds the neuron groups from `traj`.

        Adds the neuron groups to `brian_list` and `network_dict`.

        """

        model = traj.parameters.model

        # Create the equations for both models
        eqs_dict = self._build_model_eqs(traj)

        # Create inhibitory neurons
        eqs_i = eqs_dict['i']
        neurons_i = NeuronGroup(N=model.N_i,
                              model = eqs_i,
                              threshold=model.V_th,
                              reset=model.reset_func,
                              refractory=model.refractory,
                              method='Euler')

        # Create excitatory neurons
        eqs_e = eqs_dict['e']
        neurons_e = NeuronGroup(N=model.N_e,
                              model = eqs_e,
                              threshold=model.V_th,
                              reset=model.reset_func,
                              refractory=model.refractory,
                              method='Euler')

        # Set the bias terms
        neurons_e.mu =rand(model.N_e) * (model.mu_e_max - model.mu_e_min) + model.mu_e_min
        neurons_i.mu =rand(model.N_i) * (model.mu_i_max - model.mu_i_min) + model.mu_i_min

        # Set initial membrane potentials
        neurons_e.V = rand(model.N_e)
        neurons_i.V = rand(model.N_i)

        # Add both groups to the `brian_list` and the `network_dict`
        brian_list.append(neurons_i)
        brian_list.append(neurons_e)
        network_dict['neurons_e']=neurons_e
        network_dict['neurons_i']=neurons_i

def _build_model ( self , traj , brian_list , network_dict ) : model = traj . parameters . model eqs_dict = self . _build_model_eqs ( traj ) eqs_i = eqs_dict [ 'i' ] neurons_i = NeuronGroup ( N = model . N_i , model = eqs_i , threshold = model . V_th , reset = model . reset_func , refractory = model . refractory , method = 'Euler' ) eqs_e = eqs_dict [ 'e' ] neurons_e = NeuronGroup ( N = model . N_e , model = eqs_e , threshold = model . V_th , reset = model . reset_func , refractory = model . refractory , method = 'Euler' ) neurons_e . mu = rand ( model . N_e ) * ( model . mu_e_max - model . mu_e_min ) + model . mu_e_min neurons_i . mu = rand ( model . N_i ) * ( model . mu_i_max - model . mu_i_min ) + model . mu_i_min neurons_e . V = rand ( model . N_e ) neurons_i . V = rand ( model . N_i ) brian_list . append ( neurons_i ) brian_list . append ( neurons_e ) network_dict [ 'neurons_e' ] = neurons_e network_dict [ 'neurons_i' ] = neurons_i


def pre_build(self, traj, brian_list, network_dict):
        """Pre-builds the connections.

        Pre-build is only performed if none of the
        relevant parameters is explored and the relevant neuron groups
        exist.

        :param traj: Trajectory container

        :param brian_list:

            List of objects passed to BRIAN network constructor.

            Adds:

            Connections, amount depends on clustering

        :param network_dict:

            Dictionary of elements shared among the components

            Expects:

            'neurons_i': Inhibitory neuron group

            'neurons_e': Excitatory neuron group

            Adds:

            Connections, amount depends on clustering

        """
        self._pre_build = not _explored_parameters_in_group(traj, traj.parameters.connections)

        self._pre_build = (self._pre_build and 'neurons_i' in network_dict and
                           'neurons_e' in network_dict)

        if self._pre_build:
            self._build_connections(traj, brian_list, network_dict)

def pre_build ( self , traj , brian_list , network_dict ) : self . _pre_build = not _explored_parameters_in_group ( traj , traj . parameters . connections ) self . _pre_build = ( self . _pre_build and 'neurons_i' in network_dict and 'neurons_e' in network_dict ) if self . _pre_build : self . _build_connections ( traj , brian_list , network_dict )


def build(self, traj, brian_list, network_dict):
        """Builds the connections.

        Build is only performed if connections have not
        been pre-build.

        :param traj: Trajectory container

        :param brian_list:

            List of objects passed to BRIAN network constructor.

            Adds:

            Connections, amount depends on clustering

        :param network_dict:

            Dictionary of elements shared among the components

            Expects:

            'neurons_i': Inhibitory neuron group

            'neurons_e': Excitatory neuron group

            Adds:

            Connections, amount depends on clustering

        """
        if not hasattr(self, '_pre_build') or not self._pre_build:
            self._build_connections(traj, brian_list, network_dict)

def build ( self , traj , brian_list , network_dict ) : if not hasattr ( self , '_pre_build' ) or not self . _pre_build : self . _build_connections ( traj , brian_list , network_dict )


def add_parameters(self, traj):
        """Adds all necessary parameters to `traj` container."""
        par= traj.f_add_parameter(Brian2Parameter,'simulation.durations.initial_run', 500*ms,
                             comment='Initialisation run for more realistic '
                                            'measurement conditions.')

        par.v_annotations.order=0
        par=traj.f_add_parameter(Brian2Parameter,'simulation.durations.measurement_run', 1500*ms,
                             comment='Measurement run that is considered for '
                                                'statistical evaluation')
        par.v_annotations.order=1

Adds all necessary parameters to traj container .


def _compute_fano_factor(spike_res, neuron_id, time_window, start_time, end_time):
        """Computes Fano Factor for one neuron.

        :param spike_res:

            Result containing the spiketimes of all neurons

        :param neuron_id:

            Index of neuron for which FF is computed

        :param time_window:

            Length of the consecutive time windows to compute the FF

        :param start_time:

            Start time of measurement to consider

        :param end_time:

            End time of measurement to consider

        :return:

            Fano Factor (float) or
            returns 0 if mean firing activity is 0.

        """
        assert(end_time >= start_time+time_window)

        # Number of time bins
        bins = (end_time-start_time)/time_window
        bins = int(np.floor(bins))

        # Arrays for binning of spike counts
        binned_spikes = np.zeros(bins)

        # DataFrame only containing spikes of the particular neuron
        spike_array_neuron = spike_res.t[spike_res.i==neuron_id]

        for bin in range(bins):
            # We iterate over the bins to calculate the spike counts
            lower_time = start_time+time_window*bin
            upper_time = start_time+time_window*(bin+1)

            # Filter the spikes
            spike_array_interval = spike_array_neuron[spike_array_neuron >= lower_time]
            spike_array_interval = spike_array_interval[spike_array_interval < upper_time]

            # Add count to bins
            spikes = len(spike_array_interval)
            binned_spikes[bin]=spikes

        var = np.var(binned_spikes)
        avg = np.mean(binned_spikes)

        if avg > 0:
            return var/float(avg)
        else:
            return 0

def _compute_fano_factor ( spike_res , neuron_id , time_window , start_time , end_time ) : assert ( end_time >= start_time + time_window ) bins = ( end_time - start_time ) / time_window bins = int ( np . floor ( bins ) ) binned_spikes = np . zeros ( bins ) spike_array_neuron = spike_res . t [ spike_res . i == neuron_id ] for bin in range ( bins ) : lower_time = start_time + time_window * bin upper_time = start_time + time_window * ( bin + 1 ) spike_array_interval = spike_array_neuron [ spike_array_neuron >= lower_time ] spike_array_interval = spike_array_interval [ spike_array_interval < upper_time ] spikes = len ( spike_array_interval ) binned_spikes [ bin ] = spikes var = np . var ( binned_spikes ) avg = np . mean ( binned_spikes ) if avg > 0 : return var / float ( avg ) else : return 0


def _compute_mean_fano_factor( neuron_ids, spike_res, time_window, start_time, end_time):
        """Computes average Fano Factor over many neurons.

        :param neuron_ids:

            List of neuron indices to average over

        :param spike_res:

            Result containing all the spikes

        :param time_window:

            Length of the consecutive time windows to compute the FF

        :param start_time:

            Start time of measurement to consider

        :param end_time:

            End time of measurement to consider

        :return:

            Average fano factor

        """
        ffs = np.zeros(len(neuron_ids))

        for idx, neuron_id in enumerate(neuron_ids):
            ff=CNFanoFactorComputer._compute_fano_factor(
                            spike_res, neuron_id, time_window, start_time, end_time)
            ffs[idx]=ff

        mean_ff = np.mean(ffs)
        return mean_ff

def _compute_mean_fano_factor ( neuron_ids , spike_res , time_window , start_time , end_time ) : ffs = np . zeros ( len ( neuron_ids ) ) for idx , neuron_id in enumerate ( neuron_ids ) : ff = CNFanoFactorComputer . _compute_fano_factor ( spike_res , neuron_id , time_window , start_time , end_time ) ffs [ idx ] = ff mean_ff = np . mean ( ffs ) return mean_ff

Computes average Fano Factor over many neurons .


def analyse(self, traj, network, current_subrun, subrun_list, network_dict):
        """Calculates average Fano Factor of a network.

        :param traj:

            Trajectory container

            Expects:

            `results.monitors.spikes_e`: Data from SpikeMonitor for excitatory neurons

            Adds:

            `results.statistics.mean_fano_factor`: Average Fano Factor

        :param network:

            The BRIAN network

        :param current_subrun:

            BrianParameter

        :param subrun_list:

            Upcoming subruns, analysis is only performed if subruns is empty,
            aka the final subrun has finished.

        :param network_dict:

            Dictionary of items shared among componetns

        """
        #Check if we finished all subruns
        if len(subrun_list)==0:
            spikes_e = traj.results.monitors.spikes_e

            time_window = traj.parameters.analysis.statistics.time_window
            start_time = traj.parameters.simulation.durations.initial_run
            end_time = start_time+traj.parameters.simulation.durations.measurement_run
            neuron_ids = traj.parameters.analysis.statistics.neuron_ids

            mean_ff = self._compute_mean_fano_factor(
                neuron_ids, spikes_e, time_window, start_time, end_time)

            traj.f_add_result('statistics.mean_fano_factor', mean_ff, comment='Average Fano '
                                                                      'Factor over all '
                                                                      'exc neurons')

            print('R_ee: %f, Mean FF: %f' % (traj.R_ee, mean_ff))

def
analyse
(
self
,
traj
,
network
,
current_subrun
,
subrun_list
,
network_dict
)
:
if
len
(
subrun_list
)
==
0
:
spikes_e
=
traj
.
results
.
monitors
.
spikes_e
time_window
=
traj
.
parameters
.
analysis
.
statistics
.
time_window
start_time
=
traj
.
parameters
.
simulation
.
durations
.
initial_run
end_time
=
start_time
+
traj
.
parameters
.
simulation
.
durations
.
measurement_run
neuron_ids
=
traj
.
parameters
.
analysis
.
statistics
.
neuron_ids
mean_ff
=
self
.
_compute_mean_fano_factor
(
neuron_ids
,
spikes_e
,
time_window
,
start_time
,
end_time
)
traj
.
f_add_result
(
'statistics.mean_fano_factor'
,
mean_ff
,
comment
=
'Average Fano '
'Factor over all '
'exc neurons'
)
print
(
'R_ee: %f, Mean FF: %f'
%
(
traj
.
R_ee
,
mean_ff
)
)

Calculates average Fano Factor of a network .


def add_to_network(self, traj, network, current_subrun, subrun_list, network_dict):
        """Adds monitors to the network if the measurement run is carried out.

        :param traj: Trajectory container

        :param network: The BRIAN network

        :param current_subrun: BrianParameter

        :param subrun_list: List of coming subrun_list

        :param network_dict:

            Dictionary of items shared among the components

            Expects:

            'neurons_e': Excitatory neuron group

            Adds:

            'monitors': List of monitors

                0. SpikeMonitor of excitatory neurons

                1. StateMonitor of membrane potential of some excitatory neurons
                (specified in `neuron_records`)

                2. StateMonitor of excitatory synaptic currents of some excitatory neurons

                3. State monitor of inhibitory currents of some excitatory neurons

        """
        if current_subrun.v_annotations.order == 1:
            self._add_monitors(traj, network, network_dict)

def add_to_network ( self , traj , network , current_subrun , subrun_list , network_dict ) : if current_subrun . v_annotations . order == 1 : self . _add_monitors ( traj , network , network_dict )

Adds monitors to the network if the measurement run is carried out .


def _add_monitors(self, traj,  network, network_dict):
        """Adds monitors to the network"""

        neurons_e = network_dict['neurons_e']

        monitor_list = []

        # Spiketimes
        self.spike_monitor = SpikeMonitor(neurons_e)
        monitor_list.append(self.spike_monitor)

        # Membrane Potential
        self.V_monitor = StateMonitor(neurons_e,'V',
                                              record=list(traj.neuron_records))

        monitor_list.append(self.V_monitor)

        # Exc. syn .Current
        self.I_syn_e_monitor = StateMonitor(neurons_e, 'I_syn_e',
                                            record=list(traj.neuron_records))
        monitor_list.append(self.I_syn_e_monitor)

        # Inh. syn. Current
        self.I_syn_i_monitor = StateMonitor(neurons_e, 'I_syn_i',
                                            record=list(traj.neuron_records))
        monitor_list.append(self.I_syn_i_monitor)

        # Add monitors to network and dictionary
        network.add(*monitor_list)
        network_dict['monitors'] = monitor_list

def _add_monitors ( self , traj , network , network_dict ) : neurons_e = network_dict [ 'neurons_e' ] monitor_list = [ ] self . spike_monitor = SpikeMonitor ( neurons_e ) monitor_list . append ( self . spike_monitor ) self . V_monitor = StateMonitor ( neurons_e , 'V' , record = list ( traj . neuron_records ) ) monitor_list . append ( self . V_monitor ) self . I_syn_e_monitor = StateMonitor ( neurons_e , 'I_syn_e' , record = list ( traj . neuron_records ) ) monitor_list . append ( self . I_syn_e_monitor ) self . I_syn_i_monitor = StateMonitor ( neurons_e , 'I_syn_i' , record = list ( traj . neuron_records ) ) monitor_list . append ( self . I_syn_i_monitor ) network . add ( * monitor_list ) network_dict [ 'monitors' ] = monitor_list


def _make_folder(self, traj):
        """Makes a subfolder for plots.

        :return: Path name to print folder

        """
        print_folder = os.path.join(traj.analysis.plot_folder,
                                    traj.v_name, traj.v_crun)
        print_folder = os.path.abspath(print_folder)
        if not os.path.isdir(print_folder):
            os.makedirs(print_folder)

        return print_folder

def _make_folder ( self , traj ) : print_folder = os . path . join ( traj . analysis . plot_folder , traj . v_name , traj . v_crun ) print_folder = os . path . abspath ( print_folder ) if not os . path . isdir ( print_folder ) : os . makedirs ( print_folder ) return print_folder


def _plot_result(self, traj, result_name):
        """Plots a state variable graph for several neurons into one figure"""
        result = traj.f_get(result_name)
        varname = result.record_variables[0]
        values = result[varname]
        times = result.t

        record = result.record

        for idx, celia_neuron in enumerate(record):
            plt.subplot(len(record), 1, idx+1)
            plt.plot(times, values[idx,:])
            if idx==0:
                plt.title('%s' % varname)
            if idx==1:
                plt.ylabel('%s' % ( varname))
            if idx == len(record)-1:
                plt.xlabel('t')

def _plot_result ( self , traj , result_name ) : result = traj . f_get ( result_name ) varname = result . record_variables [ 0 ] values = result [ varname ] times = result . t record = result . record for idx , celia_neuron in enumerate ( record ) : plt . subplot ( len ( record ) , 1 , idx + 1 ) plt . plot ( times , values [ idx , : ] ) if idx == 0 : plt . title ( '%s' % varname ) if idx == 1 : plt . ylabel ( '%s' % ( varname ) ) if idx == len ( record ) - 1 : plt . xlabel ( 't' )


def _print_graphs(self, traj):
        """Makes some plots and stores them into subfolders"""
        print_folder = self._make_folder(traj)

        # If we use BRIAN's own raster_plot functionality we
        # need to sue the SpikeMonitor directly
        plt.figure()
        plt.scatter(self.spike_monitor.t, self.spike_monitor.i, s=1)
        plt.xlabel('t')
        plt.ylabel('Exc. Neurons')
        plt.title('Spike Raster Plot')

        filename=os.path.join(print_folder,'spike.png')

        print('Current plot: %s ' % filename)
        plt.savefig(filename)
        plt.close()

        fig=plt.figure()
        self._plot_result(traj, 'monitors.V')
        filename=os.path.join(print_folder,'V.png')
        print('Current plot: %s ' % filename)
        fig.savefig(filename)
        plt.close()

        plt.figure()
        self._plot_result(traj, 'monitors.I_syn_e')
        filename=os.path.join(print_folder,'I_syn_e.png')
        print('Current plot: %s ' % filename)
        plt.savefig(filename)
        plt.close()

        plt.figure()
        self._plot_result(traj, 'monitors.I_syn_i')
        filename=os.path.join(print_folder,'I_syn_i.png')
        print('Current plot: %s ' % filename)
        plt.savefig(filename)
        plt.close()

        if not traj.analysis.show_plots:
            plt.close('all')
        else:
            plt.show()

def
_print_graphs
(
self
,
traj
)
:
print_folder
=
self
.
_make_folder
(
traj
)
plt
.
figure
(
)
plt
.
scatter
(
self
.
spike_monitor
.
t
,
self
.
spike_monitor
.
i
,
s
=
1
)
plt
.
xlabel
(
't'
)
plt
.
ylabel
(
'Exc. Neurons'
)
plt
.
title
(
'Spike Raster Plot'
)
filename
=
os
.
path
.
join
(
print_folder
,
'spike.png'
)
print
(
'Current plot: %s '
%
filename
)
plt
.
savefig
(
filename
)
plt
.
close
(
)
fig
=
plt
.
figure
(
)
self
.
_plot_result
(
traj
,
'monitors.V'
)
filename
=
os
.
path
.
join
(
print_folder
,
'V.png'
)
print
(
'Current plot: %s '
%
filename
)
fig
.
savefig
(
filename
)
plt
.
close
(
)
plt
.
figure
(
)
self
.
_plot_result
(
traj
,
'monitors.I_syn_e'
)
filename
=
os
.
path
.
join
(
print_folder
,
'I_syn_e.png'
)
print
(
'Current plot: %s '
%
filename
)
plt
.
savefig
(
filename
)
plt
.
close
(
)
plt
.
figure
(
)
self
.
_plot_result
(
traj
,
'monitors.I_syn_i'
)
filename
=
os
.
path
.
join
(
print_folder
,
'I_syn_i.png'
)
print
(
'Current plot: %s '
%
filename
)
plt
.
savefig
(
filename
)
plt
.
close
(
)
if
not
traj
.
analysis
.
show_plots
:
plt
.
close
(
'all'
)
else
:
plt
.
show
(
)


def analyse(self, traj, network, current_subrun, subrun_list, network_dict):
        """Extracts monitor data and plots.

        Data extraction is done if all subruns have been completed,
        i.e. `len(subrun_list)==0`

        First, extracts results from the monitors and stores them into `traj`.

        Next, uses the extracted data for plots.

        :param traj:

            Trajectory container

            Adds:

            Data from monitors

        :param network: The BRIAN network

        :param current_subrun: BrianParameter

        :param subrun_list: List of coming subruns

        :param network_dict: Dictionary of items shared among all components

        """
        if len(subrun_list)==0:

            traj.f_add_result(Brian2MonitorResult, 'monitors.spikes_e', self.spike_monitor,
                              comment = 'The spiketimes of the excitatory population')

            traj.f_add_result(Brian2MonitorResult, 'monitors.V', self.V_monitor,
                              comment = 'Membrane voltage of four neurons from 2 clusters')

            traj.f_add_result(Brian2MonitorResult, 'monitors.I_syn_e', self.I_syn_e_monitor,
                              comment = 'I_syn_e of four neurons from 2 clusters')

            traj.f_add_result(Brian2MonitorResult, 'monitors.I_syn_i', self.I_syn_i_monitor,
                              comment = 'I_syn_i of four neurons from 2 clusters')

            print('Plotting')

            if traj.parameters.analysis.make_plots:
                self._print_graphs(traj)


def get_batch():
    """Function that parses the batch id from the command line arguments"""
    optlist, args = getopt.getopt(sys.argv[1:], '', longopts='batch=')
    batch = 0
    for o, a in optlist:
        if o == '--batch':
            batch = int(a)
            print('Found batch %d' % batch)

    return batch

def
get_batch
(
)
:
optlist
,
args
=
getopt
.
getopt
(
sys
.
argv
[
1
:
]
,
''
,
longopts
=
'batch='
)
batch
=
0
for
o
,
a
in
optlist
:
if
o
==
'--batch'
:
batch
=
int
(
a
)
print
(
'Found batch %d'
%
batch
)
return
batch


def explore_batch(traj, batch):
    """Chooses exploration according to `batch`"""
    explore_dict = {}
    explore_dict['sigma'] = np.arange(10.0 * batch, 10.0*(batch+1), 1.0).tolist()
    # for batch = 0 explores sigma in [0.0, 1.0, 2.0, ..., 9.0],
    # for batch = 1 explores sigma in [10.0, 11.0, 12.0, ..., 19.0]
    # and so on
    traj.f_explore(explore_dict)

def explore_batch ( traj , batch ) : explore_dict = { } explore_dict [ 'sigma' ] = np . arange ( 10.0 * batch , 10.0 * ( batch + 1 ) , 1.0 ) . tolist ( ) traj . f_explore ( explore_dict )


def vars(self):
        """Alternative naming, you can use `node.vars.name` instead of `node.v_name`"""
        if self._vars is None:
            self._vars = NNTreeNodeVars(self)
        return self._vars

def vars ( self ) : if self . _vars is None : self . _vars = NNTreeNodeVars ( self ) return self . _vars

Alternative naming you can use node . vars . name instead of node . v_name


def func(self):
        """Alternative naming, you can use `node.func.name` instead of `node.f_func`"""
        if self._func is None:
            self._func = NNTreeNodeFunc(self)
        return self._func

def func ( self ) : if self . _func is None : self . _func = NNTreeNodeFunc ( self ) return self . _func

Alternative naming you can use node . func . name instead of node . f_func


def _rename(self, full_name):
        """Renames the tree node"""
        self._full_name = full_name
        if full_name:
            self._name = full_name.rsplit('.', 1)[-1]

def _rename ( self , full_name ) : self . _full_name = full_name if full_name : self . _name = full_name . rsplit ( '.' , 1 ) [ - 1 ]


def _set_details(self, depth, branch, run_branch):
        """Sets some details for internal handling."""
        self._depth = depth
        self._branch = branch
        self._run_branch = run_branch

def _set_details ( self , depth , branch , run_branch ) : self . _depth = depth self . _branch = branch self . _run_branch = run_branch

Sets some details for internal handling .


def _node_to_msg(store_load, node):
        """Maps a given node and a store_load constant to the message that is understood by
        the storage service.

        """
        if node.v_is_leaf:
            if store_load == STORE:
                return pypetconstants.LEAF
            elif store_load == LOAD:
                return pypetconstants.LEAF
            elif store_load == REMOVE:
                return pypetconstants.DELETE
        else:
            if store_load == STORE:
                return pypetconstants.GROUP
            elif store_load == LOAD:
                return pypetconstants.GROUP
            elif store_load == REMOVE:
                return pypetconstants.DELETE

def _node_to_msg ( store_load , node ) : if node . v_is_leaf : if store_load == STORE : return pypetconstants . LEAF elif store_load == LOAD : return pypetconstants . LEAF elif store_load == REMOVE : return pypetconstants . DELETE else : if store_load == STORE : return pypetconstants . GROUP elif store_load == LOAD : return pypetconstants . GROUP elif store_load == REMOVE : return pypetconstants . DELETE

Maps a given node and a store_load constant to the message that is understood by the storage service .


def _remove_subtree(self, start_node, name, predicate=None):
        """Removes a subtree from the trajectory tree.

        Does not delete stuff from disk only from RAM.

        :param start_node: The parent node from where to start
        :param name: Name of child which will be deleted and recursively all nodes below the child
        :param predicate:

            Predicate that can be used to compute for individual nodes if they should be removed
            ``True`` or kept ``False``.

        """
        def _delete_from_children(node, child_name):
            del node._children[child_name]
            if child_name in node._groups:
                del node._groups[child_name]
            elif child_name in node._leaves:
                del node._leaves[child_name]
            else:
                raise RuntimeError('You shall not pass!')

        def _remove_subtree_inner(node, predicate):

            if not predicate(node):
                return False
            elif node.v_is_group:
                for name_ in itools.chain(list(node._leaves.keys()),
                                          list(node._groups.keys())):
                    child_ = node._children[name_]
                    child_deleted = _remove_subtree_inner(child_, predicate)
                    if child_deleted:
                        _delete_from_children(node, name_)
                        del child_

                for link_ in list(node._links.keys()):
                    node.f_remove_link(link_)

                if len(node._children) == 0:
                    self._delete_node(node)
                    return True
                else:
                    return False
            else:
                self._delete_node(node)
                return True

        if name in start_node._links:
            start_node.f_remove_link(name)
        else:
            child = start_node._children[name]
            if predicate is None:
                predicate = lambda x: True

            if _remove_subtree_inner(child, predicate):
                _delete_from_children(start_node, name)
                del child
                return True
            else:
                return False

def
_remove_subtree
(
self
,
start_node
,
name
,
predicate
=
)
:
def
_delete_from_children
(
node
,
child_name
)
:
del
node
.
_children
[
child_name
]
if
child_name
in
node
.
_groups
:
del
node
.
_groups
[
child_name
]
elif
child_name
in
node
.
_leaves
:
del
node
.
_leaves
[
child_name
]
else
:
raise
RuntimeError
(
'You shall not pass!'
)
def
_remove_subtree_inner
(
node
,
predicate
)
:
if
not
predicate
(
node
)
:
return
False
elif
node
.
v_is_group
:
for
name_
in
itools
.
chain
(
list
(
node
.
_leaves
.
keys
(
)
)
,
list
(
node
.
_groups
.
keys
(
)
)
)
:
child_
=
node
.
_children
[
name_
]
child_deleted
=
_remove_subtree_inner
(
child_
,
predicate
)
if
child_deleted
:
_delete_from_children
(
node
,
name_
)
del
child_
for
link_
in
list
(
node
.
_links
.
keys
(
)
)
:
node
.
f_remove_link
(
link_
)
if
len
(
node
.
_children
)
==
0
:
self
.
_delete_node
(
node
)
return
True
else
:
return
False
else
:
self
.
_delete_node
(
node
)
return
True
if
name
in
start_node
.
_links
:
start_node
.
f_remove_link
(
name
)
else
:
child
=
start_node
.
_children
[
name
]
if
predicate
is
:
predicate
=
lambda
x
:
True
if
_remove_subtree_inner
(
child
,
predicate
)
:
_delete_from_children
(
start_node
,
name
)
del
child
return
True
else
:
return
False

Removes a subtree from the trajectory tree .


def _delete_node(self, node):
        """Deletes a single node from the tree.

        Removes all references to the node.

        Note that the 'parameters', 'results', 'derived_parameters', and 'config' groups
        hanging directly below root cannot be deleted. Also the root node itself cannot be
        deleted. (This would cause a tremendous wave of uncontrollable self destruction, which
        would finally lead to the Apocalypse!)

        """
        full_name = node.v_full_name
        root = self._root_instance

        if full_name == '':
            # You cannot delete root
            return

        if node.v_is_leaf:
            if full_name in root._parameters:
                del root._parameters[full_name]

            elif full_name in root._config:
                del root._config[full_name]

            elif full_name in root._derived_parameters:
                del root._derived_parameters[full_name]

            elif full_name in root._results:
                del root._results[full_name]

            elif full_name in root._other_leaves:
                del root._other_leaves[full_name]

            if full_name in root._explored_parameters:

                if root._stored:
                    # We always keep the explored parameters in case the trajectory was stored
                    root._explored_parameters[full_name] = None
                else:
                    del root._explored_parameters[full_name]
                if len(root._explored_parameters) == 0:
                    root.f_shrink()

            del self._flat_leaf_storage_dict[full_name]
        else:
            del root._all_groups[full_name]

            if full_name in root._run_parent_groups:
                del root._run_parent_groups[full_name]

        # Delete all links to the node
        if full_name in root._linked_by:
            linking = root._linked_by[full_name]
            for linking_name in list(linking.keys()):
                linking_group, link_set = linking[linking_name]
                for link in list(link_set):
                    linking_group.f_remove_link(link)

        if (node.v_location, node.v_name) in self._root_instance._new_nodes:
            del self._root_instance._new_nodes[(node.v_location, node.v_name)]

        # Finally remove all references in the dictionaries for fast search
        self._remove_from_nodes_and_leaves(node)

        # Remove circular references
        node._vars = None
        node._func = None

def _delete_node ( self , node ) : full_name = node . v_full_name root = self . _root_instance if full_name == '' : return if node . v_is_leaf : if full_name in root . _parameters : del root . _parameters [ full_name ] elif full_name in root . _config : del root . _config [ full_name ] elif full_name in root . _derived_parameters : del root . _derived_parameters [ full_name ] elif full_name in root . _results : del root . _results [ full_name ] elif full_name in root . _other_leaves : del root . _other_leaves [ full_name ] if full_name in root . _explored_parameters : if root . _stored : root . _explored_parameters [ full_name ] = None else : del root . _explored_parameters [ full_name ] if len ( root . _explored_parameters ) == 0 : root . f_shrink ( ) del self . _flat_leaf_storage_dict [ full_name ] else : del root . _all_groups [ full_name ] if full_name in root . _run_parent_groups : del root . _run_parent_groups [ full_name ] if full_name in root . _linked_by : linking = root . _linked_by [ full_name ] for linking_name in list ( linking . keys ( ) ) : linking_group , link_set = linking [ linking_name ] for link in list ( link_set ) : linking_group . f_remove_link ( link ) if ( node . v_location , node . v_name ) in self . _root_instance . _new_nodes : del self . _root_instance . _new_nodes [ ( node . v_location , node . v_name ) ] self . _remove_from_nodes_and_leaves ( node ) node . _vars = None node . _func = None


def _remove_node_or_leaf(self, instance, recursive=False):
        """Removes a single node from the tree.

        Only from RAM not from hdf5 file!

        :param instance: The node to be deleted

        :param recursive: If group nodes with children should be deleted

        """
        full_name = instance.v_full_name
        split_name = deque(full_name.split('.'))
        self._remove_along_branch(self._root_instance, split_name, recursive)

def _remove_node_or_leaf ( self , instance , recursive = False ) : full_name = instance . v_full_name split_name = deque ( full_name . split ( '.' ) ) self . _remove_along_branch ( self . _root_instance , split_name , recursive )


def _remove_along_branch(self, actual_node, split_name, recursive=False):
        """Removes a given node from the tree.

        Starts from a given node and walks recursively down the tree to the location of the node
        we want to remove.

        We need to walk from a start node in case we want to check on the way back whether we got
        empty group nodes due to deletion.

        :param actual_node: Current node

        :param split_name: DEQUE of names to get the next nodes.

        :param recursive:

            To also delete all children of a group node

        :return: True if node was deleted, otherwise False

        """

        # If the names list is empty, we have reached the node we want to delete.

        if len(split_name) == 0:
            if actual_node.v_is_group and actual_node.f_has_children():
                if recursive:
                    for child in list(actual_node._children.keys()):
                        actual_node.f_remove_child(child, recursive=True)
                else:
                    raise TypeError('Cannot remove group `%s` it contains children. Please '
                                    'remove with `recursive=True`.' % actual_node.v_full_name)
            self._delete_node(actual_node)
            return True

        # Otherwise get the next node by using the first name in the list
        name = split_name.popleft()

        if name in actual_node._links:
            if len(split_name)>0:
                raise RuntimeError('You cannot remove nodes while hopping over links!')
            actual_node.f_remove_link(name)
        else:
            child = actual_node._children[name]

            if self._remove_along_branch(child, split_name, recursive=recursive):

                del actual_node._children[name]
                if name in actual_node._groups:
                    del actual_node._groups[name]
                elif name in actual_node._leaves:
                    del actual_node._leaves[name]
                else:
                    raise RuntimeError('You shall not pass!')
                del child
                return False


def _translate_shortcut(self, name):
        """Maps a given shortcut to corresponding name

        * 'run_X' or 'r_X' to 'run_XXXXXXXXX'

        * 'crun' to the current run name in case of a
          single run instance if trajectory is used via `v_crun`

        * 'par' 'parameters'

        * 'dpar' to 'derived_parameters'

        * 'res' to 'results'

        * 'conf' to 'config'

        :return: True or False and the mapped name.

        """

        if isinstance(name, int):
            return True, self._root_instance.f_wildcard('$', name)

        if name.startswith('run_') or name.startswith('r_'):
            split_name = name.split('_')
            if len(split_name) == 2:
                index = split_name[1]
                if index.isdigit():
                    return True, self._root_instance.f_wildcard('$', int(index))
                elif index == 'A':
                    return True, self._root_instance.f_wildcard('$', -1)

        if name.startswith('runtoset_') or name.startswith('rts_'):
            split_name = name.split('_')
            if len(split_name) == 2:
                index = split_name[1]
                if index.isdigit():
                    return True, self._root_instance.f_wildcard('$set', int(index))
                elif index == 'A':
                    return True, self._root_instance.f_wildcard('$set', -1)

        if name in SHORTCUT_SET:
            if name == 'par':
                return True, 'parameters'
            elif name == 'dpar':
                return True, 'derived_parameters'
            elif name == 'res':
                return True, 'results'
            elif name == 'conf':
                return True, 'config'
            else:
                raise RuntimeError('You shall not pass!')

        return False, name

def
_translate_shortcut
(
self
,
name
)
:
if
isinstance
(
name
,
int
)
:
return
True
,
self
.
_root_instance
.
f_wildcard
(
'$'
,
name
)
if
name
.
startswith
(
'run_'
)
or
name
.
startswith
(
'r_'
)
:
split_name
=
name
.
split
(
'_'
)
if
len
(
split_name
)
==
2
:
index
=
split_name
[
1
]
if
index
.
isdigit
(
)
:
return
True
,
self
.
_root_instance
.
f_wildcard
(
'$'
,
int
(
index
)
)
elif
index
==
'A'
:
return
True
,
self
.
_root_instance
.
f_wildcard
(
'$'
,
1
)
if
name
.
startswith
(
'runtoset_'
)
or
name
.
startswith
(
'rts_'
)
:
split_name
=
name
.
split
(
'_'
)
if
len
(
split_name
)
==
2
:
index
=
split_name
[
1
]
if
index
.
isdigit
(
)
:
return
True
,
self
.
_root_instance
.
f_wildcard
(
'$set'
,
int
(
index
)
)
elif
index
==
'A'
:
return
True
,
self
.
_root_instance
.
f_wildcard
(
'$set'
,
1
)
if
name
in
SHORTCUT_SET
:
if
name
==
'par'
:
return
True
,
'parameters'
elif
name
==
'dpar'
:
return
True
,
'derived_parameters'
elif
name
==
'res'
:
return
True
,
'results'
elif
name
==
'conf'
:
return
True
,
'config'
else
:
raise
RuntimeError
(
'You shall not pass!'
)
return
False
,
name


def _add_prefix(self, split_names, start_node, group_type_name):
        """Adds the correct sub branch prefix to a given name.

        Usually the prefix is the full name of the parent node. In case items are added
        directly to the trajectory the prefixes are chosen according to the matching subbranch.

        For example, this could be 'parameters' for parameters or 'results.run_00000004' for
        results added to the fifth single run.

        :param split_names:

            List of names of the new node (e.g. ``['mynewgroupA', 'mynewgroupB', 'myresult']``).

        :param start_node:

            Parent node under which the new node should be added.

        :param group_type_name:

            Type name of subbranch the item belongs to
            (e.g. 'PARAMETER_GROUP', 'RESULT_GROUP' etc).

        :return: The name with the added prefix.

        """
        root = self._root_instance

        # If the start node of our insertion is root or one below root
        # we might need to add prefixes.
        # In case of derived parameters and results we also need to add prefixes containing the
        # subbranch and the current run in case of a single run.
        # For instance, a prefix could be 'results.runs.run_00000007'.
        prepend = []
        if start_node.v_depth < 3 and not group_type_name == GROUP:
            if start_node.v_depth == 0:

                if group_type_name == DERIVED_PARAMETER_GROUP:
                    if split_names[0] == 'derived_parameters':
                        return split_names
                    else:
                        prepend += ['derived_parameters']

                elif group_type_name == RESULT_GROUP:
                    if split_names[0] == 'results':
                        return split_names
                    else:
                        prepend += ['results']

                elif group_type_name == CONFIG_GROUP:
                    if split_names[0] == 'config':
                        return split_names
                    else:
                        prepend += ['config']

                elif group_type_name == PARAMETER_GROUP:
                    if split_names[0] == 'parameters':
                        return split_names[0]
                    else:
                        prepend += ['parameters']
                else:
                    raise RuntimeError('Why are you here?')

            # Check if we have to add a prefix containing the current run
            if root._is_run and root._auto_run_prepend:
                dummy = root.f_wildcard('$', -1)
                crun = root.f_wildcard('$')
                if any(name in root._run_information for name in split_names):
                    pass
                elif any(name == dummy for name in split_names):
                    pass
                elif (group_type_name == RESULT_GROUP or
                        group_type_name == DERIVED_PARAMETER_GROUP):

                    if start_node.v_depth == 0:
                        prepend += ['runs', crun]

                    elif start_node.v_depth == 1:

                        if len(split_names) == 1 and split_names[0] == 'runs':
                            return split_names
                        else:
                            prepend += ['runs', crun]

                    elif start_node.v_depth == 2 and start_node.v_name == 'runs':
                        prepend += [crun]

        if prepend:
            split_names = prepend + split_names

        return split_names

def
_add_prefix
(
self
,
split_names
,
start_node
,
group_type_name
)
:
root
=
self
.
_root_instance
prepend
=
[
]
if
start_node
.
v_depth
<
3
and
not
group_type_name
==
GROUP
:
if
start_node
.
v_depth
==
0
:
if
group_type_name
==
DERIVED_PARAMETER_GROUP
:
if
split_names
[
0
]
==
'derived_parameters'
:
return
split_names
else
:
prepend
+=
[
'derived_parameters'
]
elif
group_type_name
==
RESULT_GROUP
:
if
split_names
[
0
]
==
'results'
:
return
split_names
else
:
prepend
+=
[
'results'
]
elif
group_type_name
==
CONFIG_GROUP
:
if
split_names
[
0
]
==
'config'
:
return
split_names
else
:
prepend
+=
[
'config'
]
elif
group_type_name
==
PARAMETER_GROUP
:
if
split_names
[
0
]
==
'parameters'
:
return
split_names
[
0
]
else
:
prepend
+=
[
'parameters'
]
else
:
raise
RuntimeError
(
'Why are you here?'
)
if
root
.
_is_run
and
root
.
_auto_run_prepend
:
dummy
=
root
.
f_wildcard
(
'$'
,
1
)
crun
=
root
.
f_wildcard
(
'$'
)
if
any
(
name
in
root
.
_run_information
for
name
in
split_names
)
:
pass
elif
any
(
name
==
dummy
for
name
in
split_names
)
:
pass
elif
(
group_type_name
==
RESULT_GROUP
or
group_type_name
==
DERIVED_PARAMETER_GROUP
)
:
if
start_node
.
v_depth
==
0
:
prepend
+=
[
'runs'
,
crun
]
elif
start_node
.
v_depth
==
1
:
if
len
(
split_names
)
==
1
and
split_names
[
0
]
==
'runs'
:
return
split_names
else
:
prepend
+=
[
'runs'
,
crun
]
elif
start_node
.
v_depth
==
2
and
start_node
.
v_name
==
'runs'
:
prepend
+=
[
crun
]
if
prepend
:
split_names
=
prepend
+
split_names
return
split_names

Adds the correct sub branch prefix to a given name .


def _determine_types(start_node, first_name, add_leaf, add_link):
        """Determines types for generic additions"""
        if start_node.v_is_root:
            where = first_name
        else:
            where = start_node._branch

        if where in SUBTREE_MAPPING:
            type_tuple = SUBTREE_MAPPING[where]
        else:
            type_tuple = (GROUP, LEAF)

        if add_link:
            return type_tuple[0], LINK
        if add_leaf:
            return type_tuple
        else:
            return type_tuple[0], type_tuple[0]

def _determine_types ( start_node , first_name , add_leaf , add_link ) : if start_node . v_is_root : where = first_name else : where = start_node . _branch if where in SUBTREE_MAPPING : type_tuple = SUBTREE_MAPPING [ where ] else : type_tuple = ( GROUP , LEAF ) if add_link : return type_tuple [ 0 ] , LINK if add_leaf : return type_tuple else : return type_tuple [ 0 ] , type_tuple [ 0 ]


def _add_generic(self, start_node, type_name, group_type_name, args, kwargs,
                     add_prefix=True, check_naming=True):
        """Adds a given item to the tree irrespective of the subtree.

        Infers the subtree from the arguments.

        :param start_node: The parental node the adding was initiated from

        :param type_name:

            The type of the new instance. Whether it is a parameter, parameter group, config,
            config group, etc. See the name of the corresponding constants at the top of this
            python module.

        :param group_type_name:

            Type of the subbranch. i.e. whether the item is added to the 'parameters',
            'results' etc. These subbranch types are named as the group names
            (e.g. 'PARAMETER_GROUP') in order to have less constants.
            For all constants used see beginning of this python module.

        :param args:

            Arguments specifying how the item is added.

            If len(args)==1 and the argument is the a given instance of a result or parameter,
            this one is added to the tree.

            Otherwise it is checked if the first argument is a class specifying how to
            construct a new item and the second argument is the name of the new class.

            If the first argument is not a class but a string, the string is assumed to be
            the name of the new instance.

            Additional args are later on used for the construction of the instance.

        :param kwargs:

            Additional keyword arguments that might be handed over to the instance constructor.

        :param add_prefix:

            If a prefix group, i.e. `results`, `config`, etc. should be added

        :param check_naming:

            If it should be checked for correct namings, can be set to ``False`` if data is loaded
            and we know that all names are correct.

        :return: The new added instance

        """
        args = list(args)
        create_new = True
        name = ''
        instance = None
        constructor = None

        add_link = type_name == LINK

        # First check if the item is already a given instance or we want to add a link
        if add_link:
            name = args[0]
            instance = args[1]
            create_new = False
        elif len(args) == 1 and len(kwargs) == 0:
            item = args[0]
            try:
                name = item.v_full_name
                instance = item

                create_new = False
            except AttributeError:
                pass

        # If the item is not an instance yet, check if args[0] is a class and args[1] is
        # a string describing the new name of the instance.
        # If args[0] is not a class it is assumed to be the name of the new instance.
        if create_new:
            if len(args) > 0 and inspect.isclass(args[0]):
                constructor = args.pop(0)
            if len(args) > 0 and isinstance(args[0], str):
                name = args.pop(0)
            elif 'name' in kwargs:
                name = kwargs.pop('name')
            elif 'full_name' in kwargs:
                name = kwargs.pop('full_name')
            else:
                raise ValueError('Could not determine a name of the new item you want to add. '
                                 'Either pass the name as positional argument or as a keyword '
                                 'argument `name`.')

        split_names = name.split('.')
        if check_naming:

            for idx, name in enumerate(split_names):
                translated_shortcut, name = self._translate_shortcut(name)
                replaced, name = self._replace_wildcards(name)
                if translated_shortcut or replaced:
                    split_names[idx] = name

            # First check if the naming of the new item is appropriate
            faulty_names = self._check_names(split_names, start_node)

            if faulty_names:
                full_name = '.'.join(split_names)
                raise ValueError(
                    'Your Parameter/Result/Node `%s` contains the following not admissible names: '
                    '%s please choose other names.' % (full_name, faulty_names))

            if add_link:
                if instance is None:
                    raise ValueError('You must provide an instance to link to!')
                if instance.v_is_root:
                    raise ValueError('You cannot create a link to the root node')
                if start_node.v_is_root and name in SUBTREE_MAPPING:
                    raise ValueError('`%s` is a reserved name for a group under root.' % name)
                if not self._root_instance.f_contains(instance, with_links=False, shortcuts=False):
                    raise ValueError('You can only link to items within the trajectory tree!')

        # Check if the name fulfils the prefix conditions, if not change the name accordingly.
        if add_prefix:
            split_names = self._add_prefix(split_names, start_node, group_type_name)

        if group_type_name == GROUP:
            add_leaf = type_name != group_type_name and not add_link
            # If this is equal we add a group node
            group_type_name, type_name = self._determine_types(start_node, split_names[0],
                                                               add_leaf, add_link)

        # Check if we are allowed to add the data
        if self._root_instance._is_run and type_name in SENSITIVE_TYPES:
            raise TypeError('You are not allowed to add config or parameter data or groups '
                            'during a single run.')

        return self._add_to_tree(start_node, split_names, type_name, group_type_name, instance,
                                 constructor, args, kwargs)

Adds a given item to the tree irrespective of the subtree .


def _add_to_tree(self, start_node, split_names, type_name, group_type_name,
                     instance, constructor, args, kwargs):
        """Adds a new item to the tree.

        The item can be an already given instance or it is created new.

        :param start_node:

            Parental node the adding of the item was initiated from.

        :param split_names:

            List of names of the new item

        :param type_name:

            Type of item 'RESULT', 'RESULT_GROUP', 'PARAMETER', etc. See name of constants
            at beginning of the python module.

        :param group_type_name:

            Name of the subbranch the item is added to 'RESULT_GROUP', 'PARAMETER_GROUP' etc.
            See name of constants at beginning of this python module.

        :param instance:

            Here an already given instance can be passed. If instance should be created new
            pass None.

        :param constructor:

            If instance should be created new pass a constructor class. If None is passed
            the standard constructor for the instance is chosen.

        :param args:

            Additional arguments passed to instance construction

        :param kwargs:

            Additional keyword arguments passed to instance construction

        :return: The new added instance

        :raises: ValueError if naming of the new item is invalid

        """

        # Then walk iteratively from the start node as specified by the new name and create
        # new empty groups on the fly
        try:
            act_node = start_node
            last_idx = len(split_names) - 1
            add_link = type_name == LINK
            link_added = False
            # last_name = start_node.v_crun
            for idx, name in enumerate(split_names):
                if name not in act_node._children:
                    if idx == last_idx:
                        if add_link:
                            new_node = self._create_link(act_node, name, instance)
                            link_added = True
                        elif group_type_name != type_name:
                            # We are at the end of the chain and we add a leaf node

                            new_node = self._create_any_param_or_result(act_node,
                                                                        name,
                                                                        type_name,
                                                                        instance,
                                                                        constructor,
                                                                        args, kwargs)

                            self._flat_leaf_storage_dict[new_node.v_full_name] = new_node
                        else:
                            # We add a group as desired
                            new_node = self._create_any_group(act_node, name,
                                                              group_type_name,
                                                              instance,
                                                              constructor,
                                                              args, kwargs)
                    else:
                        # We add a group on the fly
                        new_node = self._create_any_group(act_node, name,
                                                          group_type_name)

                    if name in self._root_instance._run_information:
                        self._root_instance._run_parent_groups[act_node.v_full_name] = act_node
                    if self._root_instance._is_run:
                        if link_added:
                            self._root_instance._new_links[(act_node.v_full_name, name)] = \
                                (act_node, new_node)
                        else:
                            self._root_instance._new_nodes[(act_node.v_full_name, name)] = \
                                (act_node, new_node)
                else:
                    if name in act_node._links:
                        raise AttributeError('You cannot hop over links when adding '
                                             'data to the tree. '
                                             'There is a link called `%s` under `%s`.' %
                                             (name, act_node.v_full_name))
                    if idx == last_idx:
                        if self._root_instance._no_clobber:
                            self._logger.warning('You already have a group/instance/link `%s` '
                                                 'under `%s`. '
                                                 'However, you set `v_no_clobber=True`, '
                                                 'so I will ignore your addition of '
                                                 'data.' % (name, act_node.v_full_name))
                        else:
                            raise AttributeError('You already have a group/instance/link `%s` '
                                                 'under `%s`' % (name, act_node.v_full_name))
                act_node = act_node._children[name]
            return act_node
        except:
            self._logger.error('Failed adding `%s` under `%s`.' %
                               (name, start_node.v_full_name))
            raise