Skip to content

Commit

Permalink
Change to DemoTestUnit
Browse files Browse the repository at this point in the history
  • Loading branch information
appukuttan-shailesh committed May 5, 2021
1 parent edd9329 commit bd0430f
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 23 deletions.
File renamed without changes.
42 changes: 42 additions & 0 deletions DemoTestUnit/capabilities/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import sciunit

# ===============================================================================

class SomaProducesMembranePotential(sciunit.Capability):
"""Enables recording membrane potential from soma """

def get_soma_membrane_potential(self, tstop):
"""
Run simulation for time 'tstop', specified in ms, while
recording the somatic membrane potential.
Must return a dict of the form:
{'T': list1, 'V': list2 } where,
list1 = time series (in ms)
list2 = membrane potential series (in mV)
"""
raise NotImplementedError()

# this will be used by our second test (test for input resistance)
def get_soma_membrane_potential_eFEL_format(self, tstop, start, stop):
traces = self.get_soma_membrane_potential(tstop)
efel_trace = {'T' : traces['T'],
'V' : traces['V'],
'stim_start' : [start],
'stim_end' : [stop]}
return efel_trace

# ===============================================================================

class SomaReceivesStepCurrent(sciunit.Capability):
""" Enables step current stimulus into soma """

def inject_soma_square_current(self, current):
"""
Input current is specified in the form of a dict with keys:
'delay' : (value in ms),
'duration' : (value in ms),
'amplitude' : (value in nA)
"""
raise NotImplementedError()

# ===============================================================================
File renamed without changes.
File renamed without changes.
157 changes: 157 additions & 0 deletions DemoTestUnit/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import sciunit
import efel
import numpy

import os
import json
import matplotlib
# To avoid figures being plotted on screen (we wish to save to file directly)
matplotlib.use('Agg')
import matplotlib.pyplot as plt

import DemoTestUnit.capabilities as cap

# ===============================================================================

class RestingPotential(sciunit.Test):
"""Test the cell's resting membrane potential"""
score_type = sciunit.scores.ZScore
description = ("Test the cell's resting membrane potential")

def __init__(self,
observation={'mean':None, 'std':None},
name="Resting Membrane Potential Test"):
self.required_capabilities += (cap.SomaProducesMembranePotential,)
sciunit.Test.__init__(self, observation, name)

def validate_observation(self, observation):
try:
assert len(observation.keys()) == 2
for key, val in observation.items():
assert key in ["mean", "std"]
assert (isinstance(val, int) or isinstance(val, float))
except Exception:
raise sciunit.errors.ObservationError(
("Observation must return a dictionary of the form:"
"{'mean': NUM1, 'std': NUM2}"))

def generate_prediction(self, model):
self.trace = model.get_soma_membrane_potential(tstop=50.0)
prediction = numpy.mean(self.trace['V'])
return prediction

def compute_score(self, observation, prediction):
score = sciunit.scores.ZScore.compute(observation, prediction)
return score

def bind_score(self, score, model, observation, prediction):
self.figures = []
self.target_dir = os.path.join("./validation_results", self.name, model.name)
if not os.path.exists(self.target_dir):
os.makedirs(self.target_dir)

# create relevant output files
# 1. JSON data: observation, prediction, score, run_times
validation_data = {
"observation": observation,
"prediction": prediction,
"score": score.score,
}
with open(os.path.join(self.target_dir, 'basic_data.json'), 'w') as f:
json.dump(validation_data, f, indent=4)
self.figures.append(os.path.join(self.target_dir, 'basic_data.json'))

# 2. JSON data: save Vm vs t traces
with open(os.path.join(self.target_dir, 'trace_data.json'), 'w') as f:
json.dump(self.trace, f, indent=4)
self.figures.append(os.path.join(self.target_dir, 'trace_data.json'))

# 3. Vm traces as PDF
fig = plt.figure()
plt.plot(self.trace["T"], self.trace["V"])
plt.title("Somatic Vm vs t")
plt.xlabel("Time (ms)")
plt.ylabel("Membrane potential (mV)")
plt.show()
fig.savefig(os.path.join(self.target_dir, "trace_plot.pdf"))
self.figures.append(os.path.join(self.target_dir, "trace_plot.pdf"))

score.related_data["figures"] = self.figures
return score

# ===============================================================================

class InputResistance(sciunit.Test):
"""Test the cell's input resistance"""
score_type = sciunit.scores.ZScore
description = ("Test the cell's input resistance")

def __init__(self,
observation={'mean':None, 'std':None},
name="Input Resistance Test"):
self.required_capabilities += (cap.SomaReceivesStepCurrent, cap.SomaProducesMembranePotential,)
sciunit.Test.__init__(self, observation, name)

def validate_observation(self, observation):
try:
assert len(observation.keys()) == 2
for key, val in observation.items():
assert key in ["mean", "std"]
assert (isinstance(val, int) or isinstance(val, float))
except Exception:
raise sciunit.errors.ObservationError(
("Observation must return a dictionary of the form:"
"{'mean': NUM1, 'std': NUM2}"))

def generate_prediction(self, model):
efel.reset()
model.inject_soma_square_current(current={'delay':20.0,
'duration':50.0,
'amplitude':-5.0})
self.trace = model.get_soma_membrane_potential_eFEL_format(tstop=100.0,
start=20.0,
stop =70.0)
efel.setDoubleSetting('stimulus_current', -5.0)
prediction = efel.getFeatureValues([self.trace], ['ohmic_input_resistance_vb_ssse'])[0]["ohmic_input_resistance_vb_ssse"][0]
return prediction

def compute_score(self, observation, prediction):
score = sciunit.scores.ZScore.compute(observation, prediction)
return score

def bind_score(self, score, model, observation, prediction):
self.figures = []
self.target_dir = os.path.join("./validation_results", self.name, model.name)
if not os.path.exists(self.target_dir):
os.makedirs(self.target_dir)

# create relevant output files
# 1. JSON data: observation, prediction, score, run_times
validation_data = {
"observation": observation,
"prediction": prediction,
"score": score.score,
}
with open(os.path.join(self.target_dir, 'basic_data.json'), 'w') as f:
json.dump(validation_data, f, indent=4)
self.figures.append(os.path.join(self.target_dir, 'basic_data.json'))

# 2. JSON data: save Vm vs t traces
with open(os.path.join(self.target_dir, 'trace_data.json'), 'w') as f:
json.dump(self.trace, f, indent=4)
self.figures.append(os.path.join(self.target_dir, 'trace_data.json'))

# 3. Vm traces as PDF
fig = plt.figure()
plt.plot(self.trace["T"], self.trace["V"])
plt.title("Somatic Vm vs t")
plt.xlabel("Time (ms)")
plt.ylabel("Membrane potential (mV)")
plt.show()
fig.savefig(os.path.join(self.target_dir, "trace_plot.pdf"))
self.figures.append(os.path.join(self.target_dir, "trace_plot.pdf"))

score.related_data["figures"] = self.figures
return score

# ===============================================================================
7 changes: 0 additions & 7 deletions PackageName/capabilities/__init__.py

This file was deleted.

7 changes: 0 additions & 7 deletions PackageName/tests/__init__.py

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# PackageName
# DemoTestUnit

A simple SciUnit library for demonstrating data-driven testing of electrophysiological features extracted from computational models.
16 changes: 8 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
from distutils.core import setup

setup(
name='PackageName',
version='0.1',
name='DemoTestUnit',
version='1.2.0',
author='Shailesh Appukuttan, Andrew Davison',
author_email='[email protected]',
packages=['PackageName',
'PackageName.tests',
'PackageName.capabilities',
'PackageName.scores',
'PackageName.plots',],
url='https://github.com/appukuttan-shailesh/PackageName',
packages=['DemoTestUnit',
'DemoTestUnit.tests',
'DemoTestUnit.capabilities',
'DemoTestUnit.scores',
'DemoTestUnit.plots',],
url='https://github.com/appukuttan-shailesh/DemoTestUnit',
keywords=['electrophysiology', 'electrical',
'testing', 'validation framework'],
license='MIT',
Expand Down

0 comments on commit bd0430f

Please sign in to comment.