#!/usr/bin/python
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------
# Copyright (c) 2012 Michael Hull.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------
from morphforge.core import LocMgr, SettingsMgr
from morphforge.core.misc import SeqUtils
import itertools
[docs]class Simulation(object):
# Syntactic Sugar:
# ------------------
[docs] def create_cell(self, **kwargs):
cell = self.environment.Cell(simulation=self, **kwargs)
self.add_cell(cell)
return cell
[docs] def create_currentclamp(self, **kwargs):
current_clamp = self.environment.CurrentClamp(simulation=self, **kwargs)
self.add_currentclamp(current_clamp)
return current_clamp
[docs] def create_voltageclamp(self, **kwargs):
voltage_clamp = self.environment.VoltageClamp(simulation=self, **kwargs)
self.add_voltageclamp(voltage_clamp)
return voltage_clamp
[docs] def create_synapse(self, trigger, postsynaptic_mech,**kwargs):
syn = self.environment.Synapse(simulation=self,
trigger=trigger,
postsynaptic_mech=postsynaptic_mech,
**kwargs)
self.add_synapse(syn)
return syn
[docs] def create_gapjunction(self, **kwargs):
gap_junction = self.environment.GapJunction(simulation=self, **kwargs)
self.add_gapjunction(gap_junction)
return gap_junction
# New API
[docs] def add_currentclamp(self, cc):
assert not cc.name in self.objectnames, 'Duplicate name found: %s'%cc.name
self._current_clamps.append(cc)
self.add_currentclamp_backend_specific(cc)
[docs] def add_voltageclamp(self, vc):
assert not vc.name in self.objectnames, 'Duplicate name found: %s'%vc.name
self._voltage_clamps.append(vc)
self.add_voltageclamp_backend_specific(vc)
[docs] def add_cell(self, cell):
assert not cell.name in self.objectnames, 'Duplicate name found: %s'%cell.name
self._cells.append(cell)
self.add_cell_backend_specific(cell)
[docs] def add_synapse(self, syn):
assert not syn.name in self.objectnames, 'Duplicate name found: %s'%syn.name
self._synapses.append(syn)
self.add_synapse_backend_specific(syn)
[docs] def add_gapjunction(self, gj):
assert not gj.name in self.objectnames, 'Duplicate name found: %s'%gj.name
self._gapjunctions.append(gj)
self.add_gapjunction_backend_specific(gj)
[docs] def add_recordable(self, recordable):
assert not recordable.name in self.objectnames, 'Duplicate name found: %s'%recordable.name
self._recordables.append(recordable)
self.add_recordable_backend_specific(recordable)
[docs] def add_recordable_backend_specific(self, recordable):
raise NotImplementedError()
[docs] def add_cell_backend_specific(self, cell):
raise NotImplementedError()
[docs] def add_currentclamp_backend_specific(self, vc):
raise NotImplementedError()
[docs] def add_voltageclamp_backend_specific(self, vc):
raise NotImplementedError()
[docs] def add_synapse_backend_specific(self, syn):
raise NotImplementedError()
[docs] def add_gapjunction_backend_specific(self, syn):
raise NotImplementedError()
@property
def neuron_populations(self):
return set([cell.population for cell in self._cells
if cell.population])
@property
def synapse_populations(self):
return set([syn.population for syn in self._synapses
if syn.population])
@property
def are_all_cells_in_pops(self):
for cell in self._cells:
if not cell.population:
return False
return True
@property
def postsynaptic_templates(self):
from morphforge.stdimports import PostSynapticMechInstantiation
mechs = [syn.get_postsynaptic_mechanism() for syn in self.synapses ]
synaptic_templates = set()
for m in mechs:
print isinstance(m,PostSynapticMechInstantiation)
if isinstance( m,PostSynapticMechInstantiation):
synaptic_templates.add(m.src_tmpl)
return synaptic_templates
@property
def cells(self):
return self._cells
@property
def synapses(self):
return self._synapses
@property
def gapjunctions(self):
return self._gapjunctions
@property
def voltage_clamps(self):
return self._voltage_clamps
@property
def current_clamps(self):
return self._current_clamps
@property
def recordables(self):
return self._recordables
@property
def objects(self):
return itertools.chain(
self.cells,
self.synapses,
self.gapjunctions,
self.voltage_clamps,
self.current_clamps,
self.recordables)
@property
def objectnames(self):
return [obj.name for obj in self.objects]
[docs] def __init__(self, name, environment, **kwargs):
name = (name if name else 'Unnamed Simulation')
self.name = name
self.environment = environment
self.simsettings = self.environment.SimulationSettings(**kwargs)
self.result = None
# For checksumming: we store links to additional classes:
self.config_classes = [SettingsMgr, LocMgr]
# These should only be used by this
# class, subclasses should take care of the
# management of cells, VC's and CC's themselves.
self._cells = []
self._voltage_clamps = []
self._current_clamps = []
self._gapjunctions = []
self._synapses = []
self._recordables = []
# Postprosessing
self._postprocessors = []
# Over-ridden in child classes:
[docs] def run(self, **kwargs):
raise NotImplementedError()
#def add_recordable(self, recordable):
# raise NotImplementedError()
# Syntactic Sugar for making more readable scripts:
[docs] def record(self, recordable_src=None, **kwargs):
# Allow 'recordable_src' to be missing. In this case; we expect
# to be recording from the cell, and that there will be
# a kwarg['cell_location']:
if recordable_src is None:
recordable_src = kwargs['cell_location'].cell
recordable = recordable_src.get_recordable(simulation=self,
**kwargs)
self.add_recordable(recordable)
return recordable
[docs] def recordall(self, membrane_mech, **kwargs):
for recordable_value in membrane_mech.Recordables.all:
self.record(membrane_mech, what=recordable_value,
description='[%s-%s]' % (membrane_mech.name,
recordable_value), **kwargs)
[docs] def get_cell(self, cellname=None):
""" Either return a cell by name if there is more than one cell, otherwise the single cell """
if cellname:
return SeqUtils.filter_expect_single(self.cells,
lambda s: s.name == cellname)
else:
return SeqUtils.expect_single(self.cells)
[docs] def get_all_channels(self):
return list(set(itertools.chain(*[cell.biophysics.get_all_channels_applied_to_cell() for cell in self.cells])) )
[docs] def do_result_post_processing(self,):
for pp in self._postprocessors:
pp(result=self.result)
# Post processing: