From 0e6dbcdbbe0b729806b37a3b48c049dc2a836240 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 20 Oct 2023 13:06:36 +0200 Subject: [PATCH 01/85] throw runtime_error, rm exit(1) in featuretype&calcfeatures --- efel/cppcore/cfeature.cpp | 22 ++++++--------------- efel/cppcore/cppcore.cpp | 40 +++++++++++++++++++++++++-------------- tests/test_basic.py | 2 +- tests/test_cppcore.py | 2 +- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 5c449861..12cc528e 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -374,12 +374,7 @@ int cFeature::calc_features(const string& name) { map >::const_iterator lookup_it( fptrlookup.find(name)); if (lookup_it == fptrlookup.end()) { - fprintf(stderr, - "\nFeature [ %s ] dependency file entry or pointer table entry is " - "missing. Exiting\n", - name.c_str()); - fflush(stderr); - exit(1); + throw std::runtime_error("Feature dependency file entry or pointer table entry is missing."); } bool last_failed = false; @@ -581,17 +576,12 @@ double cFeature::getDistance(string strName, double mean, double std, } } - // check datatype of feature featureType = featuretype(strName); - if (featureType.empty()) { - printf("Error : Feature [%s] not found. Exiting..\n", strName.c_str()); - exit(1); - } if (featureType == "int") { retVal = getFeature(strName, feature_veci); intFlag = 1; - } else { + } else { // double retVal = getFeature(strName, feature_vec); intFlag = 0; } @@ -634,12 +624,12 @@ double cFeature::getDistance(string strName, double mean, double std, string cFeature::featuretype(string featurename) { int npos = featurename.find(";"); - if (npos >= 0) { + if (npos != string::npos) { featurename = featurename.substr(0, npos); } - string type(featuretypes[featurename]); - if (type.empty()) { - GErrorStr += featurename + "missing in featuretypes map.\n"; + string type = featuretypes[featurename]; + if (type != "int" && type != "double") { + throw std::runtime_error("Unknown feature name: " + featurename); } return type; } diff --git a/efel/cppcore/cppcore.cpp b/efel/cppcore/cppcore.cpp index d1f70e74..03afa3e8 100644 --- a/efel/cppcore/cppcore.cpp +++ b/efel/cppcore/cppcore.cpp @@ -117,27 +117,39 @@ _getfeature(PyObject* self, PyObject* args, const string &type) { return NULL; } - string feature_type = pFeature->featuretype(string(feature_name)); + string feature_type; + try + { + feature_type = pFeature->featuretype(string(feature_name)); + } + catch(const std::runtime_error& e) + { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return NULL; + } - if (!type.empty() && feature_type != type){ + if (!type.empty() && feature_type != type){ // when types do not match PyErr_SetString(PyExc_TypeError, "Feature type does not match"); return NULL; } - if (feature_type == "int") { - vector values; - return_value = pFeature->getFeature(string(feature_name), values); - PyList_from_vectorint(values, py_values); - } else if (feature_type == "double") { - vector values; - return_value = pFeature->getFeature(string(feature_name), values); - PyList_from_vectordouble(values, py_values); - } else { - PyErr_SetString(PyExc_TypeError, "Unknown feature name"); + try { + if (feature_type == "int") { + vector values; + return_value = pFeature->getFeature(string(feature_name), values); + PyList_from_vectorint(values, py_values); + return Py_BuildValue("i", return_value); + } else { // double + vector values; + return_value = pFeature->getFeature(string(feature_name), values); + PyList_from_vectordouble(values, py_values); + return Py_BuildValue("i", return_value); + } + } + catch(const std::runtime_error& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); return NULL; } - - return Py_BuildValue("i", return_value); } diff --git a/tests/test_basic.py b/tests/test_basic.py index 9751ec68..6c7e303c 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -183,7 +183,7 @@ def test_nonexisting_feature(): trace['stim_end'] = [75] pytest.raises( - TypeError, + RuntimeError, efel.getFeatureValues, [trace], ['nonexisting_feature']) diff --git a/tests/test_cppcore.py b/tests/test_cppcore.py index ef5131e6..fac793d2 100644 --- a/tests/test_cppcore.py +++ b/tests/test_cppcore.py @@ -160,7 +160,7 @@ def test_getFeature_failure(self): # pylint: disable=R0201 return_value = efel.cppcore.getFeature("AP_amplitude", feature_values) assert return_value == -1 - @pytest.mark.xfail(raises=TypeError) + @pytest.mark.xfail(raises=RuntimeError) def test_getFeature_non_existant(self): # pylint: disable=R0201 """cppcore: Testing failure exit code in getFeature""" import efel From 5cc3c5ecdacf9c03e020b903663c8d6ee175b8cb Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 20 Oct 2023 13:16:34 +0200 Subject: [PATCH 02/85] rename type->input_type --- efel/cppcore/cppcore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/efel/cppcore/cppcore.cpp b/efel/cppcore/cppcore.cpp index 03afa3e8..e9a6471a 100644 --- a/efel/cppcore/cppcore.cpp +++ b/efel/cppcore/cppcore.cpp @@ -108,7 +108,7 @@ static void PyList_from_vectorstring(vector input, PyObject* output) { } static PyObject* -_getfeature(PyObject* self, PyObject* args, const string &type) { +_getfeature(PyObject* self, PyObject* args, const string &input_type) { char* feature_name; PyObject* py_values; @@ -128,7 +128,7 @@ _getfeature(PyObject* self, PyObject* args, const string &type) { return NULL; } - if (!type.empty() && feature_type != type){ // when types do not match + if (!input_type.empty() && feature_type != input_type){ // when types do not match PyErr_SetString(PyExc_TypeError, "Feature type does not match"); return NULL; } From 2a84582cfe842df1369b2e5a5a04d98c8a1afdde Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 20 Oct 2023 15:13:09 +0200 Subject: [PATCH 03/85] throw EfelAssertionError to avoid exit(-1) --- efel/cppcore/CMakeLists.txt | 2 +- efel/cppcore/EfelExceptions.h | 12 ++++++++++++ efel/cppcore/Utils.h | 6 ++++-- efel/cppcore/cppcore.cpp | 11 +++++++++-- 4 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 efel/cppcore/EfelExceptions.h diff --git a/efel/cppcore/CMakeLists.txt b/efel/cppcore/CMakeLists.txt index 053cb3bc..bbd8e61c 100644 --- a/efel/cppcore/CMakeLists.txt +++ b/efel/cppcore/CMakeLists.txt @@ -40,6 +40,6 @@ add_library(efel SHARED ${FEATURESRCS}) install(TARGETS efel LIBRARY DESTINATION lib) install(FILES efel.h cfeature.h FillFptrTable.h LibV1.h LibV2.h LibV3.h - LibV5.h mapoperations.h Utils.h DependencyTree.h eFELLogger.h + LibV5.h mapoperations.h Utils.h DependencyTree.h eFELLogger.h EfelExceptions.h types.h DESTINATION include) diff --git a/efel/cppcore/EfelExceptions.h b/efel/cppcore/EfelExceptions.h new file mode 100644 index 00000000..ac7c85c2 --- /dev/null +++ b/efel/cppcore/EfelExceptions.h @@ -0,0 +1,12 @@ +#ifndef EFEL_EXCEPTIONS_H +#define EFEL_EXCEPTIONS_H + +#include + +// Define the custom exception class +class EfelAssertionError : public std::runtime_error { +public: + explicit EfelAssertionError(const std::string& message) : std::runtime_error(message) {} +}; + +#endif // EFEL_EXCEPTIONS_H diff --git a/efel/cppcore/Utils.h b/efel/cppcore/Utils.h index 5e59ba6a..c064cb6a 100644 --- a/efel/cppcore/Utils.h +++ b/efel/cppcore/Utils.h @@ -26,6 +26,7 @@ #include #include #include +#include "EfelExceptions.h" using std::vector; @@ -85,8 +86,9 @@ inline void efel_assert(bool assertion, const char *message, const char *file, const int line) { if(!assertion){ - printf("Assertion fired(%s:%d): %s\n", file, line, message); - exit(-1); + using std::string, std::to_string; + string errorMsg = "Assertion fired(" + string(file) + ":" + to_string(line) + "): " + string(message); + throw EfelAssertionError(errorMsg); } } diff --git a/efel/cppcore/cppcore.cpp b/efel/cppcore/cppcore.cpp index e9a6471a..196057d4 100644 --- a/efel/cppcore/cppcore.cpp +++ b/efel/cppcore/cppcore.cpp @@ -118,8 +118,7 @@ _getfeature(PyObject* self, PyObject* args, const string &input_type) { } string feature_type; - try - { + try { feature_type = pFeature->featuretype(string(feature_name)); } catch(const std::runtime_error& e) @@ -146,10 +145,18 @@ _getfeature(PyObject* self, PyObject* args, const string &input_type) { return Py_BuildValue("i", return_value); } } + catch(EfelAssertionError& e) { // more specialised exception + PyErr_SetString(PyExc_AssertionError, e.what()); + return NULL; + } catch(const std::runtime_error& e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return NULL; } + catch(...) { + PyErr_SetString(PyExc_RuntimeError, "Unknown error"); + return NULL; + } } From 84626df57148ff8a304ca9a82303c35a9983bbfc Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 20 Oct 2023 15:54:31 +0200 Subject: [PATCH 04/85] add test to trigger C++->Python AssertionError --- efel/cppcore/cfeature.cpp | 5 +++-- efel/cppcore/cppcore.cpp | 19 ++++++------------- tests/test_cppcore.py | 12 ++++++++++++ 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 12cc528e..1ec75bfb 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -627,10 +627,11 @@ string cFeature::featuretype(string featurename) { if (npos != string::npos) { featurename = featurename.substr(0, npos); } + if (featurename == "__test_efel_assertion__") // for testing only + throw EfelAssertionError("Test efel assertion is successfully triggered."); string type = featuretypes[featurename]; - if (type != "int" && type != "double") { + if (type != "int" && type != "double") throw std::runtime_error("Unknown feature name: " + featurename); - } return type; } diff --git a/efel/cppcore/cppcore.cpp b/efel/cppcore/cppcore.cpp index 196057d4..938a0646 100644 --- a/efel/cppcore/cppcore.cpp +++ b/efel/cppcore/cppcore.cpp @@ -114,25 +114,18 @@ _getfeature(PyObject* self, PyObject* args, const string &input_type) { int return_value; if (!PyArg_ParseTuple(args, "sO!", &feature_name, &PyList_Type, &py_values)) { + PyErr_SetString(PyExc_TypeError, "Unexpected argument type provided."); return NULL; } - string feature_type; try { - feature_type = pFeature->featuretype(string(feature_name)); - } - catch(const std::runtime_error& e) - { - PyErr_SetString(PyExc_RuntimeError, e.what()); - return NULL; - } + string feature_type = pFeature->featuretype(string(feature_name)); - if (!input_type.empty() && feature_type != input_type){ // when types do not match - PyErr_SetString(PyExc_TypeError, "Feature type does not match"); - return NULL; - } + if (!input_type.empty() && feature_type != input_type){ // when types do not match + PyErr_SetString(PyExc_TypeError, "Feature type does not match"); + return NULL; + } - try { if (feature_type == "int") { vector values; return_value = pFeature->getFeature(string(feature_name), values); diff --git a/tests/test_cppcore.py b/tests/test_cppcore.py index fac793d2..19ad2a49 100644 --- a/tests/test_cppcore.py +++ b/tests/test_cppcore.py @@ -209,3 +209,15 @@ def test_caching(self, feature_name): assert contents.count(f"Calculated feature {feature_name}") == 1 # make sure Reusing computed value of text occurs twice assert contents.count(f"Reusing computed value of {feature_name}") == 2 + + +def test_efel_assertion_error(): + """Testing if c++ assertion error is propagated to python acorrectly.""" + import efel + efel.reset() + trace = { + "stim_start": [25], + "stim_end": [75], + } + with pytest.raises(AssertionError): + efel.getFeatureValues([trace], ["__test_efel_assertion__"]) From 954613abb3f5232950e011d70675d81542ced37c Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 20 Oct 2023 15:56:25 +0200 Subject: [PATCH 05/85] remove featurename.find(";") check --- efel/cppcore/cfeature.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 1ec75bfb..f1edcc68 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -623,10 +623,6 @@ double cFeature::getDistance(string strName, double mean, double std, } string cFeature::featuretype(string featurename) { - int npos = featurename.find(";"); - if (npos != string::npos) { - featurename = featurename.substr(0, npos); - } if (featurename == "__test_efel_assertion__") // for testing only throw EfelAssertionError("Test efel assertion is successfully triggered."); string type = featuretypes[featurename]; From e9cbcc8d58523c57cd478d0725979a230115c5ad Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 20 Oct 2023 15:58:18 +0200 Subject: [PATCH 06/85] typo in docstring --- tests/test_cppcore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_cppcore.py b/tests/test_cppcore.py index 19ad2a49..1682cee4 100644 --- a/tests/test_cppcore.py +++ b/tests/test_cppcore.py @@ -212,7 +212,7 @@ def test_caching(self, feature_name): def test_efel_assertion_error(): - """Testing if c++ assertion error is propagated to python acorrectly.""" + """Testing if C++ assertion error is propagated to Python correctly.""" import efel efel.reset() trace = { From 443e083cffc2fe876bdaca0c6b0a402b9ef828d9 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 20 Oct 2023 16:46:45 +0200 Subject: [PATCH 07/85] add feature's name to the error message --- efel/cppcore/cfeature.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index f1edcc68..6fe7e0ae 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -374,9 +374,9 @@ int cFeature::calc_features(const string& name) { map >::const_iterator lookup_it( fptrlookup.find(name)); if (lookup_it == fptrlookup.end()) { - throw std::runtime_error("Feature dependency file entry or pointer table entry is missing."); + throw std::runtime_error("Feature dependency file entry or pointer table " + "entry for '" + name + "' is missing."); } - bool last_failed = false; for (vector::const_iterator pfptrstring = From f11e36d74e5fc4bbad21e1b5a50a410283f2425c Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 20 Oct 2023 17:05:25 +0200 Subject: [PATCH 08/85] Revert "remove featurename.find(";") check" This reverts commit 954613abb3f5232950e011d70675d81542ced37c. --- efel/cppcore/cfeature.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 6fe7e0ae..4eaaae10 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -623,6 +623,10 @@ double cFeature::getDistance(string strName, double mean, double std, } string cFeature::featuretype(string featurename) { + int npos = featurename.find(";"); + if (npos != string::npos) { + featurename = featurename.substr(0, npos); + } if (featurename == "__test_efel_assertion__") // for testing only throw EfelAssertionError("Test efel assertion is successfully triggered."); string type = featuretypes[featurename]; From 108ca8511c6a91fbd8fe2bb42e39778d45095cfb Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 20 Oct 2023 17:37:12 +0200 Subject: [PATCH 09/85] remove setversion function --- efel/cppcore/cfeature.cpp | 17 ----------------- efel/cppcore/cfeature.h | 1 - efel/cppcore/efel.cpp | 4 ---- efel/cppcore/efel.h | 1 - 4 files changed, 23 deletions(-) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 4eaaae10..b07e0083 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -74,23 +74,6 @@ const vector cFeature::getmapDoubleData(string strName) { return getMapData(strName, mapDoubleData); } -int cFeature::setVersion(string strDepFile) { - FptrTable.clear(); - /* - map > >::iterator mapVecItr; - vector< pair< fptr, string > > *vecFptr; - for(mapVecItr = pFeature->fptrlookup.begin(); mapVecItr != - pFeature->fptrlookup.end(); mapVecItr++){ - vecFptr = &(mapVecItr->second); - vecFptr->clear(); - } - */ - fptrlookup.clear(); - cTree DepTree(strDepFile.c_str()); - DepTree.setFeaturePointers(mapFptrLib, &FptrTable, &fptrlookup); - return 1; -} - void cFeature::fillfeaturetypes() { // initialize feature type information featuretypes["peak_indices"] = "int"; diff --git a/efel/cppcore/cfeature.h b/efel/cppcore/cfeature.h index 3fece8c3..2d3eb6d4 100644 --- a/efel/cppcore/cfeature.h +++ b/efel/cppcore/cfeature.h @@ -66,7 +66,6 @@ class cFeature { string featuretype(string featurename); string getGError(); void get_feature_names(vector& feature_names); - int setVersion(string strDepFile); double getDistance(string strName, double mean, double std, bool trace_check=true, double error_dist=250); diff --git a/efel/cppcore/efel.cpp b/efel/cppcore/efel.cpp index f885f8b0..b9e813c0 100644 --- a/efel/cppcore/efel.cpp +++ b/efel/cppcore/efel.cpp @@ -35,10 +35,6 @@ int Initialize(const char *strDepFile, const char *outdir) { } } -int setVersion(const char *strDepFile) { - return pFeature->setVersion(string(strDepFile)); -} - int FeaturePrint(const char *strFile) { pFeature->printFeature(strFile); return 1; diff --git a/efel/cppcore/efel.h b/efel/cppcore/efel.h index 95fecf58..e2801d70 100644 --- a/efel/cppcore/efel.h +++ b/efel/cppcore/efel.h @@ -21,7 +21,6 @@ #define FEATURELIB_API extern "C" { FEATURELIB_API int Initialize(const char *strDepFile, const char *outdir); -FEATURELIB_API int setVersion(const char *strDepFile); FEATURELIB_API int setFeatureInt(const char *strName, int *A, unsigned nValue); FEATURELIB_API int setFeatureDouble(const char *strName, double *A, unsigned nValue); FEATURELIB_API int getTotalIntData(); From 71f687d71c35f8f7d9ed455ce1d37e4d80a7628a Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 20 Oct 2023 18:47:10 +0200 Subject: [PATCH 10/85] draft: removing alternative wildcard syntax --- efel/cppcore/cfeature.cpp | 31 -------- tests/test_allfeatures.py | 158 +++++++++++++++++--------------------- tests/test_cppcore.py | 1 + 3 files changed, 70 insertions(+), 120 deletions(-) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index b07e0083..a57e8e1c 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -461,33 +461,6 @@ int cFeature::getFeatureString(const string& key, string& value) { return -1; } } -/* - * not needed -int cFeature::ifExist(string strName, map > &mapIntData){ - map >::iterator mapItrInt; - int n = mapIntData.size(); - string str; - for(mapItrInt = mapIntData.begin(); mapItrInt != mapIntData.end(); -mapItrInt++){ - str = mapItrInt->first; - if( str == strName) return 1; - } - return 0; -} - -int cFeature::ifExist(string strName, map > -&mapDoubleData){ - map >::iterator mapItrDouble; - int n = mapDoubleData.size(); - string str; - for(mapItrDouble = mapDoubleData.begin(); mapItrDouble != -mapDoubleData.end(); mapItrDouble++){ - str = mapItrDouble->first; - if( str == strName) return 1; - } - return 0; -} -*/ int cFeature::setFeatureDouble(string strName, vector& v) { if (mapDoubleData.find(strName) != mapDoubleData.end()) { @@ -606,10 +579,6 @@ double cFeature::getDistance(string strName, double mean, double std, } string cFeature::featuretype(string featurename) { - int npos = featurename.find(";"); - if (npos != string::npos) { - featurename = featurename.substr(0, npos); - } if (featurename == "__test_efel_assertion__") // for testing only throw EfelAssertionError("Test efel assertion is successfully triggered."); string type = featuretypes[featurename]; diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index fee7c7ba..900e12f3 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -29,6 +29,7 @@ """ import os +import warnings # pylint: disable=R0914 @@ -41,123 +42,102 @@ def get_allfeature_values(): """Get back all the feature names and value""" import efel - efel.reset() import numpy + efel.reset() all_featurenames = efel.getFeatureNames() - soma_data = numpy.loadtxt(os.path.join(testdata_dir, 'testdata.txt')) - soma_time = soma_data[:, 0] - soma_voltage = soma_data[:, 1] - - db_data = numpy.loadtxt(os.path.join(testdata_dir, 'testdbdata.txt')) - db_time = db_data[:, 0] - db_voltage = db_data[:, 1] - - bac_data = numpy.loadtxt(os.path.join(testdata_dir, 'testbacdata.txt')) - bac_time = bac_data[:, 0] - bac_voltage = bac_data[:, 1] - - bap1_data = numpy.loadtxt(os.path.join(testdata_dir, 'testbap1data.txt')) - bap1_time = bap1_data[:, 0] - bap1_voltage = bap1_data[:, 1] - - bap2_data = numpy.loadtxt(os.path.join(testdata_dir, 'testbap2data.txt')) - bap2_time = bap2_data[:, 0] - bap2_voltage = bap2_data[:, 1] - - trace = {} - trace_db = {} - - trace['T'] = soma_time - trace['V'] = soma_voltage - trace['stim_start'] = [700] - trace['stim_end'] = [2700] - trace['T;location_AIS'] = soma_time - trace['V;location_AIS'] = soma_voltage - trace['stim_start;location_AIS'] = [700] - trace['stim_end;location_AIS'] = [2700] - trace['T;location_epsp'] = bac_time - trace['V;location_epsp'] = bac_voltage - trace['stim_start;location_epsp'] = [295] - trace['stim_end;location_epsp'] = [600] - trace['T;location_dend1'] = bap1_time - trace['V;location_dend1'] = bap1_voltage - trace['stim_start;location_dend1'] = [295] - trace['stim_end;location_dend1'] = [500] - trace['T;location_dend2'] = bap2_time - trace['V;location_dend2'] = bap2_voltage - trace['stim_start;location_dend2'] = [295] - trace['stim_end;location_dend2'] = [500] - - trace_db['T'] = db_time - trace_db['V'] = db_voltage - trace_db['stim_start'] = [419.995] - trace_db['stim_end'] = [1419.995] + def load_data(filename): + data = numpy.loadtxt(os.path.join(testdata_dir, filename)) + return data[:, 0], data[:, 1] + + soma_time, soma_voltage = load_data('testdata.txt') + db_time, db_voltage = load_data('testdbdata.txt') + bac_time, bac_voltage = load_data('testbacdata.txt') + bap1_time, bap1_voltage = load_data('testbap1data.txt') + bap2_time, bap2_voltage = load_data('testbap2data.txt') + + traces = [ + { + 'T': soma_time, + 'V': soma_voltage, + 'stim_start': [700], + 'stim_end': [2700] + }, + { + 'T': soma_time, + 'V': soma_voltage, + 'stim_start': [700], + 'stim_end': [2700], + }, + { + 'T': bac_time, + 'V': bac_voltage, + 'stim_start': [295], + 'stim_end': [600] + }, + { + 'T': bap1_time, + 'V': bap1_voltage, + 'stim_start': [295], + 'stim_end': [500] + }, + { + 'T': bap2_time, + 'V': bap2_voltage, + 'stim_start': [295], + 'stim_end': [500] + } + ] + + trace_db = { + 'T': db_time, + 'V': db_voltage, + 'stim_start': [419.995], + 'stim_end': [1419.995] + } bpap_featurenames = [ 'BPAPHeightLoc1', 'BPAPHeightLoc2', 'BPAPAmplitudeLoc1', - 'BPAPAmplitudeLoc2'] - - bac_featurenames = [ - 'BAC_width'] - - db_featurenames = [ - 'depol_block', - 'depol_block_bool' + 'BPAPAmplitudeLoc2' ] - soma_featurenames = all_featurenames[:] - - for feature_name in bpap_featurenames: - soma_featurenames.remove(feature_name) - - for feature_name in bac_featurenames: - soma_featurenames.remove(feature_name) - - for feature_name in db_featurenames: - soma_featurenames.remove(feature_name) - - soma_featurenames = [x for x in soma_featurenames - if x not in ['current', 'current_base', 'impedance']] + bac_featurenames = ['BAC_width'] + db_featurenames = ['depol_block', 'depol_block_bool'] + + soma_featurenames = [ + x + for x in all_featurenames + if x + not in bpap_featurenames + + bac_featurenames + + db_featurenames + + ["current", "current_base", "impedance"] + ] - import warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") - feature_values = efel.getFeatureValues([trace], soma_featurenames)[0] + feature_values = efel.getFeatureValues(traces, soma_featurenames)[0] with warnings.catch_warnings(): warnings.simplefilter("ignore") - feature_values = dict( - list(feature_values.items()) + - list(efel.getFeatureValues( - [trace_db], - db_featurenames)[0].items())) + feature_values.update(efel.getFeatureValues([trace_db], db_featurenames)[0]) with warnings.catch_warnings(): warnings.simplefilter("ignore") efel.setThreshold(-30) - feature_values = dict( - list(feature_values.items()) + - list(efel.getFeatureValues( - [trace], - bpap_featurenames)[0].items())) + feature_values.update(efel.getFeatureValues(traces, bpap_featurenames)[0]) with warnings.catch_warnings(): warnings.simplefilter("ignore") efel.setThreshold(-55) - feature_values = dict( - list(feature_values.items()) + - list(efel.getFeatureValues( - [trace], - bac_featurenames)[0].items())) + feature_values.update(efel.getFeatureValues(traces, bac_featurenames)[0]) for feature_name in feature_values: if feature_values[feature_name] is not None: - feature_values[feature_name] = list( - feature_values[feature_name]) + feature_values[feature_name] = list(feature_values[feature_name]) return feature_values diff --git a/tests/test_cppcore.py b/tests/test_cppcore.py index 1682cee4..50199d04 100644 --- a/tests/test_cppcore.py +++ b/tests/test_cppcore.py @@ -200,6 +200,7 @@ def test_caching(self, feature_name): efel.cppcore.getFeature(feature_name, feature_values) with (Path(tempdir) / 'fllog.txt').open() as fd: contents = fd.read() + # breakpoint() # re-call efel's Initialize with current dir to remove pointer to tempdir. # this pointer was preventing the deletion of tempdir on windows. efel.cppcore.Initialize(efel.getDependencyFileLocation(), '.') From 37486289705c9a7c724c9002c5233bc66aa9d28c Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Wed, 25 Oct 2023 23:23:45 +0200 Subject: [PATCH 11/85] remove variable features in LibV5 --- docs/source/eFeatures.rst | 109 -------- efel/DependencyV5.txt | 8 - efel/cppcore/FillFptrTable.cpp | 10 - efel/cppcore/LibV5.cpp | 235 ------------------ efel/cppcore/LibV5.h | 16 -- efel/cppcore/cfeature.cpp | 8 - efel/units/units.json | 8 - tests/DependencyV5_LibV5peakindices.txt | 8 - tests/featurenames.json | 8 - tests/test_allfeatures.py | 22 +- tests/test_basic.py | 4 +- tests/test_units.py | 1 - .../testdata/allfeatures/expectedresults.json | 22 -- 13 files changed, 3 insertions(+), 456 deletions(-) diff --git a/docs/source/eFeatures.rst b/docs/source/eFeatures.rst index f4a7e004..7954b385 100644 --- a/docs/source/eFeatures.rst +++ b/docs/source/eFeatures.rst @@ -343,23 +343,6 @@ The adaptation index is zero for a constant firing rate and bigger than zero for ISI_sub = ISI_values[1:] - ISI_values[:-1] adaptation_index = numpy.mean(ISI_sum / ISI_sub) - -`LibV5`_ : check_AISInitiation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Check initiation of AP in AIS - -- **Required features**: t, V, stim_start, stim_end, AP_begin_time, AP_begin_time;location_AIS -- **Units**: constant -- **Pseudocode**: :: - - if len(AP_begin_time) != len(AP_begin_time;location_AIS): - return None - for soma_time, ais_time in zip(AP_begin_time, AP_begin_time;location_AIS): - if soma_time < ais_time: - return None - return [1] - `LibV1`_ : burst_mean_freq ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1287,98 +1270,6 @@ Slope of the V, dVdt phasespace plot at the beginning of every spike range_min_idxs = AP_begin_indices - AP_phseslope_range AP_phaseslope = (dvdt[range_max_idxs] - dvdt[range_min_idxs]) / (v[range_max_idxs] - v[range_min_idxs]) -`LibV5`_ : AP_phaseslope_AIS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Same as AP_phaseslope, but for AIS location - -Please, notice that you have to provide t, v, stim_start and stim_end for location. - -- **Required features**: T;location_AIS, V;location_AIS, stim_start;location_AIS, stim_end;location_AIS, LibV5:AP_begin_indices;location_AIS -- **Parameters**: AP_phaseslope_range -- **Units**: 1/(ms) -- **Pseudocode**: :: - - range_max_idxs = AP_begin_indices + AP_phseslope_range - range_min_idxs = AP_begin_indices - AP_phseslope_range - AP_phaseslope_AIS = (dvdt[range_max_idxs] - dvdt[range_min_idxs]) / (v[range_max_idxs] - v[range_min_idxs]) - -`LibV5`_ : BPAPHeightLoc1 -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Voltage height (difference betwen peaks and voltage base) at dendrite location - -Please, notice that you have to provide t, v, stim_start and stim_end for location. - -- **Required features**: T;location_dend1, V;location_dend1, stim_start;location_dend1, stim_end;location_dend1, peak_voltage;location_dend1, voltage_base;location_dend1 -- **Units**: mV -- **Pseudocode**: :: - - BPAPHeightLoc1 = peak_voltage - voltage_base - -`LibV5`_ : BPAPHeightLoc2 -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Same as BPAPHeightLoc1, but for dend2 location - -- **Required features**: T;location_dend2, V;location_dend2, stim_start;location_dend2, stim_end;location_dend2, peak_voltage;location_dend2, voltage_base;location_dend2 -- **Units**: mV -- **Pseudocode**: :: - - BPAPHeightLoc2 = peak_voltage - voltage_base - -`LibV5`_ : BPAPAmplitudeLoc1 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Amplitude at dendrite location - -Please, notice that you have to provide t, v, stim_start and stim_end for location. - -- **Required features**: T;location_dend1, V;location_dend1, stim_start;location_dend1, stim_end;location_dend1, peak_voltage;location_dend1, AP_begin_voltage;location_dend1 -- **Units**: mV -- **Pseudocode**: :: - - BPAPAmplitudeLoc1 = peak_voltage - AP_begin_voltage - -`LibV5`_ : BPAPAmplitudeLoc2 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Same as BPAPAmplitudeLoc1, but for dend2 location - -- **Required features**: T;location_dend2, V;location_dend2, stim_start;location_dend2, stim_end;location_dend2, peak_voltage;location_dend2, AP_begin_voltage;location_dend2 -- **Units**: mV -- **Pseudocode**: :: - - BPAPAmplitudeLoc2 = peak_voltage - AP_begin_voltage - -`LibV5`_ : BAC_width -~~~~~~~~~~~~~~~~~~~~ - -AP width at epsp location - -Please, notice that you have to provide t, v, stim_start and stim_end for location. - -- **Required features**: T;location_epsp, V;location_epsp, stim_start;location_epsp, stim_end;location_epsp, AP_width;location_epsp -- **Units**: ms -- **Pseudocode**: :: - - BAC_width = AP_width - -`LibV5`_ : BAC_maximum_voltage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Maximuum voltage at epsp location - -Please, notice that you have to provide t, v, stim_start and stim_end for location. - -- **Required features**: T;location_epsp, V;location_epsp, stim_start;location_epsp, stim_end;location_epsp, maximum_voltage;location_epsp -- **Units**: mV -- **Pseudocode**: :: - - BAC_maximum_voltage = maximum_voltage - - - Voltage features ---------------- diff --git a/efel/DependencyV5.txt b/efel/DependencyV5.txt index 607c391e..0039d4a7 100644 --- a/efel/DependencyV5.txt +++ b/efel/DependencyV5.txt @@ -133,15 +133,7 @@ LibV5:is_not_stuck #LibV1:peak_time #LibV1:interpolate LibV5:mean_AP_amplitude #LibV1:AP_amplitude #LibV1:interpolate LibV5:voltage_after_stim #LibV1:interpolate LibV5:AP2_AP1_begin_width_diff #LibV5:AP_begin_width #LibV1:interpolate -LibV5:BPAPHeightLoc1 #LibV1:peak_voltage;location_dend1 #LibV5:voltage_base;location_dend1 #LibV1:interpolate -LibV5:BPAPHeightLoc2 #LibV1:peak_voltage;location_dend2 #LibV5:voltage_base;location_dend2 #LibV1:interpolate -LibV5:BPAPAmplitudeLoc1 #LibV1:peak_voltage;location_dend1 #LibV5:AP_begin_voltage;location_dend1 #LibV1:interpolate -LibV5:BPAPAmplitudeLoc2 #LibV1:peak_voltage;location_dend2 #LibV5:AP_begin_voltage;location_dend2 #LibV1:interpolate -LibV5:check_AISInitiation #LibV5:AP_begin_time #LibV5:AP_begin_time;location_AIS #LibV1:interpolate LibV5:AP_phaseslope #LibV5:AP_begin_indices #LibV1:interpolate -LibV5:AP_phaseslope_AIS #LibV5:AP_phaseslope;location_AIS #LibV1:interpolate -LibV5:BAC_width #LibV1:AP_width;location_epsp #LibV1:interpolate -LibV5:BAC_maximum_voltage #LibV1:maximum_voltage;location_epsp #LibV1:interpolate LibV5:all_ISI_values #LibV1:peak_time #LibV1:interpolate LibV5:AP_amplitude_from_voltagebase #LibV5:voltage_base #LibV1:peak_voltage #LibV1:interpolate LibV5:min_voltage_between_spikes #LibV5:peak_indices #LibV1:interpolate diff --git a/efel/cppcore/FillFptrTable.cpp b/efel/cppcore/FillFptrTable.cpp index 284d16ab..7c56eaa3 100644 --- a/efel/cppcore/FillFptrTable.cpp +++ b/efel/cppcore/FillFptrTable.cpp @@ -181,17 +181,7 @@ int FillFptrTable() { FptrTableV5["AP2_AP1_begin_width_diff"] = &LibV5::AP2_AP1_begin_width_diff; - FptrTableV5["BPAPHeightLoc1"] = &LibV5::BPAPHeightLoc1; - FptrTableV5["BPAPAmplitudeLoc1"] = &LibV5::BPAPAmplitudeLoc1; - FptrTableV5["BPAPAmplitudeLoc2"] = &LibV5::BPAPAmplitudeLoc2; - FptrTableV5["BPAPHeightLoc2"] = &LibV5::BPAPHeightLoc2; - - FptrTableV5["check_AISInitiation"] = &LibV5::check_AISInitiation; FptrTableV5["AP_phaseslope"] = &LibV5::AP_phaseslope; - FptrTableV5["AP_phaseslope_AIS"] = &LibV5::AP_phaseslope_AIS; - - FptrTableV5["BAC_width"] = &LibV5::BAC_width; - FptrTableV5["BAC_maximum_voltage"] = &LibV5::BAC_maximum_voltage; FptrTableV5["all_ISI_values"] = &LibV5::all_ISI_values; diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index fdb0b44d..96687d5d 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -1587,191 +1587,6 @@ int LibV5::mean_AP_amplitude(mapStr2intVec& IntFeatureData, return mean_AP_amplitude.size(); } -// *** BPAPHeightLoc1 *** -int LibV5::BPAPHeightLoc1(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retval; - vector peakvoltage; - retval = getDoubleParam(DoubleFeatureData, "peak_voltage;location_dend1", - peakvoltage); - // one spike required - if (retval <= 0) return -1; - - // voltage base - vector vb_dend; - retval = - getDoubleParam(DoubleFeatureData, "voltage_base;location_dend1", vb_dend); - if (retval <= 0) return -1; - - vector v_dend; - retval = getDoubleParam(DoubleFeatureData, "V;location_dend1", v_dend); - if (retval <= 0) return -1; - vector bpapheight; - - // bpapheight.push_back(*max_element(v_dend.begin(), v_dend.end()) - - // vb_dend[0]); - for (size_t i = 0; i < peakvoltage.size(); i++) { - bpapheight.push_back(peakvoltage[i] - vb_dend[0]); - // printf("peak voltage: %f, voltage base: %f, height: %f", peakvoltage[i], - // vb_dend[0], peakvoltage[0] - vb_dend[0]); - } - - setVec(DoubleFeatureData, StringData, "BPAPHeightLoc1", bpapheight); - return bpapheight.size(); -} -// end of BPAPHeightLoc1 - -// *** BPAPAmplitudeLoc1 *** -int LibV5::BPAPAmplitudeLoc1(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retval; - vector peakvoltage; - retval = getDoubleParam(DoubleFeatureData, "peak_voltage;location_dend1", - peakvoltage); - // one spike required - if (retval <= 0) return -1; - - // voltage base - vector ap_begin_voltage_dend; - retval = getDoubleParam(DoubleFeatureData, "AP_begin_voltage;location_dend1", - ap_begin_voltage_dend); - if (retval <= 0) return -1; - - if (peakvoltage.size() > ap_begin_voltage_dend.size()) { - GErrorStr += "More peakvoltage entries than AP begin voltages"; - return -1; - } - - vector bpapamplitude; - - for (size_t i = 0; i < peakvoltage.size(); i++) { - bpapamplitude.push_back(peakvoltage[i] - ap_begin_voltage_dend[i]); - } - - setVec(DoubleFeatureData, StringData, "BPAPAmplitudeLoc1", - bpapamplitude); - return bpapamplitude.size(); -} -// end of BPAPAmplitudeLoc1 - -// *** BPAPAmplitudeLoc2 *** -int LibV5::BPAPAmplitudeLoc2(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retval; - vector peakvoltage; - retval = getDoubleParam(DoubleFeatureData, "peak_voltage;location_dend2", - peakvoltage); - // one spike required - if (retval <= 0) return -1; - - // voltage base - vector ap_begin_voltage_dend; - retval = getDoubleParam(DoubleFeatureData, "AP_begin_voltage;location_dend2", - ap_begin_voltage_dend); - if (retval <= 0) return -1; - - if (peakvoltage.size() > ap_begin_voltage_dend.size()) { - GErrorStr += "More peakvoltage entries than AP begin voltages"; - return -1; - } - - vector bpapamplitude; - - for (size_t i = 0; i < peakvoltage.size(); i++) { - bpapamplitude.push_back(peakvoltage[i] - ap_begin_voltage_dend[i]); - } - - setVec(DoubleFeatureData, StringData, "BPAPAmplitudeLoc2", - bpapamplitude); - return bpapamplitude.size(); -} -// end of BPAPAmplitudeLoc2 - -// *** BPAPHeightLoc2 *** -int LibV5::BPAPHeightLoc2(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retval; - vector peakvoltage; - retval = getDoubleParam(DoubleFeatureData, "peak_voltage;location_dend2", - peakvoltage); - // one spike required - if (retval <= 0) return -1; - - // voltage base - vector vb_dend; - retval = - getDoubleParam(DoubleFeatureData, "voltage_base;location_dend2", vb_dend); - if (retval <= 0) return -1; - - vector v_dend; - retval = getDoubleParam(DoubleFeatureData, "V;location_dend2", v_dend); - if (retval <= 0) return -1; - vector bpapheight; - - // bpapheight.push_back(*max_element(v_dend.begin(), v_dend.end()) - - // vb_dend[0]); - for (size_t i = 0; i < peakvoltage.size(); i++) { - bpapheight.push_back(peakvoltage[i] - vb_dend[0]); - // printf("peak voltage: %f, voltage base: %f, height: %f", peakvoltage[i], - // vb_dend[0], peakvoltage[0] - vb_dend[0]); - } - setVec(DoubleFeatureData, StringData, "BPAPHeightLoc2", bpapheight); - return bpapheight.size(); -} -// end of BPAPHeightLoc2 - -// *** check_AISInitiation *** -int LibV5::check_AISInitiation(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retval; - vector apBeginSoma; - retval = getDoubleParam(DoubleFeatureData, "AP_begin_time", apBeginSoma); - if (retval <= 0) { - printf("Error calculating AP_begin_time\n"); - return -1; - } - - vector apBeginAIS; - retval = getDoubleParam(DoubleFeatureData, "AP_begin_time;location_AIS", - apBeginAIS); - if (retval <= 0) { - printf("Error calculating AP_begin_time\n"); - return -1; - } - - // printf("Calculated AP_begin_time\n"); - - // printf("%d, %d\n", apBeginSoma.size(), apBeginAIS.size()); fflush(stdout); - - // Not the same amount of spike in soma and AIS - if (apBeginSoma.size() != apBeginAIS.size()) { - GErrorStr += "\nNot the same amount of spikes in soma and AIS\n"; - return -1; - } - - // Testing if no spike in the soma start earlier than in the dendrites - for (size_t i = 0; i < apBeginSoma.size(); i++) { - /// printf("%f, %f\n", apBeginSoma[i], apBeginAIS[i]); fflush(stdout); - if (apBeginSoma[i] < apBeginAIS[i]) { - GErrorStr = - GErrorStr + - "\nThere is a spike that initiates in the soma before the axon.\n"; - return -1; - } - } - vector returnvalues; - returnvalues.push_back(1); - setVec(DoubleFeatureData, StringData, "check_AISInitiation", - returnvalues); - return returnvalues.size(); -} -// end of check_AISInitation -// static int __AP_phaseslope(const vector& v, const vector& t, double stimStart, double stimEnd, @@ -1847,56 +1662,6 @@ int LibV5::AP_phaseslope(mapStr2intVec& IntFeatureData, return retVal; } -/// Calculate the slope of the V, dVdt plot at the beginning of every spike -/// (at the point where the derivative crosses the DerivativeThreshold) -int LibV5::AP_phaseslope_AIS(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - vector ap_phaseslopes; - retVal = getVec(DoubleFeatureData, StringData, - "AP_phaseslope;location_AIS", ap_phaseslopes); - if (retVal < 0) return -1; - setVec(DoubleFeatureData, StringData, "AP_phaseslope_AIS", - ap_phaseslopes); - return retVal; -} - -int LibV5::BAC_width(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - vector ap_width; - retVal = getVec(DoubleFeatureData, StringData, "AP_width;location_epsp", - ap_width); - if (retVal < 0) { - GErrorStr += "\n AP_width calculation failed in BAC_width.\n"; - return -1; - } - if (retVal > 1) { - GErrorStr += - "\n More than one spike found a location_epsp for BAC_width.\n"; - return -1; - } - setVec(DoubleFeatureData, StringData, "BAC_width", ap_width); - - return retVal; -} - -int LibV5::BAC_maximum_voltage(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - vector ap_phaseslopes; - retVal = getVec(DoubleFeatureData, StringData, - "maximum_voltage;location_epsp", ap_phaseslopes); - if (retVal != 1) return -1; - - setVec(DoubleFeatureData, StringData, "BAC_maximum_voltage", - ap_phaseslopes); - return retVal; -} - int LibV5::all_ISI_values(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { diff --git a/efel/cppcore/LibV5.h b/efel/cppcore/LibV5.h index 8a025a5f..3f7efaea 100644 --- a/efel/cppcore/LibV5.h +++ b/efel/cppcore/LibV5.h @@ -170,24 +170,8 @@ int AP2_AP1_begin_width_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int BPAPHeightLoc1(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int BPAPAmplitudeLoc1(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int BPAPAmplitudeLoc2(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int BPAPHeightLoc2(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); - -int check_AISInitiation(mapStr2intVec&, mapStr2doubleVec&, mapStr2Str&); - int AP_phaseslope(mapStr2intVec&, mapStr2doubleVec&, mapStr2Str&); -int AP_phaseslope_AIS(mapStr2intVec&, mapStr2doubleVec&, mapStr2Str&); - -int BAC_width(mapStr2intVec&, mapStr2doubleVec&, mapStr2Str&); -int BAC_maximum_voltage(mapStr2intVec&, mapStr2doubleVec&, mapStr2Str&); - int all_ISI_values(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index a57e8e1c..43dad475 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -221,15 +221,7 @@ void cFeature::fillfeaturetypes() { featuretypes["voltage_after_stim"] = "double"; featuretypes["AP2_AP1_begin_width_diff"] = "double"; - featuretypes["BPAPHeightLoc1"] = "double"; - featuretypes["BPAPAmplitudeLoc1"] = "double"; - featuretypes["BPAPAmplitudeLoc2"] = "double"; - featuretypes["BPAPHeightLoc2"] = "double"; - featuretypes["check_AISInitiation"] = "double"; featuretypes["AP_phaseslope"] = "double"; - featuretypes["AP_phaseslope_AIS"] = "double"; - featuretypes["BAC_width"] = "double"; - featuretypes["BAC_maximum_voltage"] = "double"; featuretypes["all_ISI_values"] = "double"; featuretypes["AP_amplitude_from_voltagebase"] = "double"; featuretypes["min_voltage_between_spikes"] = "double"; diff --git a/efel/units/units.json b/efel/units/units.json index bbc8accc..22b6dde5 100644 --- a/efel/units/units.json +++ b/efel/units/units.json @@ -43,7 +43,6 @@ "AP_peak_downstroke": "V/s", "AP_peak_upstroke": "V/s", "AP_phaseslope": "1/(ms)", - "AP_phaseslope_AIS": "1/(ms)", "AP_rise_rate": "V/s", "AP_rise_rate_change": "constant", "AP_rise_time": "ms", @@ -51,12 +50,6 @@ "AP_width_between_threshold": "ms", "APlast_amp": "mV", "APlast_width": "ms", - "BAC_maximum_voltage": "mV", - "BAC_width": "ms", - "BPAPAmplitudeLoc1": "mV", - "BPAPAmplitudeLoc2": "mV", - "BPAPHeightLoc1": "mV", - "BPAPHeightLoc2": "mV", "ISI_CV": "constant", "ISI_log_slope": "ms", "ISI_log_slope_skip": "ms", @@ -72,7 +65,6 @@ "amp_drop_second_last": "mV", "burst_mean_freq": "Hz", "burst_number": "constant", - "check_AISInitiation": "constant", "current_base": "nA", "decay_time_constant_after_stim": "ms", "depolarized_base": "mV", diff --git a/tests/DependencyV5_LibV5peakindices.txt b/tests/DependencyV5_LibV5peakindices.txt index 7933ea70..60e43aad 100644 --- a/tests/DependencyV5_LibV5peakindices.txt +++ b/tests/DependencyV5_LibV5peakindices.txt @@ -127,15 +127,7 @@ LibV5:is_not_stuck #LibV1:peak_time LibV5:mean_AP_amplitude #LibV1:AP_amplitude LibV5:voltage_after_stim LibV5:AP2_AP1_begin_width_diff #LibV5:AP_begin_width -LibV5:BPAPHeightLoc1 #LibV1:peak_voltage;location_dend1 #LibV5:voltage_base;location_dend1 -LibV5:BPAPHeightLoc2 #LibV1:peak_voltage;location_dend2 #LibV5:voltage_base;location_dend2 -LibV5:BPAPAmplitudeLoc1 #LibV1:peak_voltage;location_dend1 #LibV5:AP_begin_voltage;location_dend1 -LibV5:BPAPAmplitudeLoc2 #LibV1:peak_voltage;location_dend2 #LibV5:AP_begin_voltage;location_dend2 -LibV5:check_AISInitiation #LibV5:AP_begin_time #LibV5:AP_begin_time;location_AIS LibV5:AP_phaseslope #LibV5:AP_begin_indices -LibV5:AP_phaseslope_AIS #LibV5:AP_phaseslope;location_AIS -LibV5:BAC_width #LibV1:AP_width;location_epsp -LibV5:BAC_maximum_voltage #LibV1:maximum_voltage;location_epsp LibV5:all_ISI_values #LibV1:peak_time LibV5:AP_amplitude_from_voltagebase #LibV5:voltage_base #LibV1:peak_voltage LibV5:min_voltage_between_spikes #LibV5:peak_indices diff --git a/tests/featurenames.json b/tests/featurenames.json index da1e79d1..9f1112d9 100644 --- a/tests/featurenames.json +++ b/tests/featurenames.json @@ -42,7 +42,6 @@ "AP_peak_downstroke", "AP_peak_upstroke", "AP_phaseslope", - "AP_phaseslope_AIS", "AP_rise_indices", "AP_rise_rate", "AP_rise_rate_change", @@ -50,12 +49,6 @@ "AP_width", "APlast_amp", "APlast_width", - "BAC_maximum_voltage", - "BAC_width", - "BPAPAmplitudeLoc1", - "BPAPAmplitudeLoc2", - "BPAPHeightLoc1", - "BPAPHeightLoc2", "BPAPatt2", "BPAPatt3", "E10", @@ -104,7 +97,6 @@ "burst_ISI_indices", "burst_mean_freq", "burst_number", - "check_AISInitiation", "current", "current_base", "decay_time_constant_after_stim", diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index 900e12f3..6c006fd2 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -97,23 +97,13 @@ def load_data(filename): 'stim_end': [1419.995] } - bpap_featurenames = [ - 'BPAPHeightLoc1', - 'BPAPHeightLoc2', - 'BPAPAmplitudeLoc1', - 'BPAPAmplitudeLoc2' - ] - - bac_featurenames = ['BAC_width'] db_featurenames = ['depol_block', 'depol_block_bool'] soma_featurenames = [ x for x in all_featurenames if x - not in bpap_featurenames - + bac_featurenames - + db_featurenames + not in db_featurenames + ["current", "current_base", "impedance"] ] @@ -125,16 +115,6 @@ def load_data(filename): warnings.simplefilter("ignore") feature_values.update(efel.getFeatureValues([trace_db], db_featurenames)[0]) - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - efel.setThreshold(-30) - feature_values.update(efel.getFeatureValues(traces, bpap_featurenames)[0]) - - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - efel.setThreshold(-55) - feature_values.update(efel.getFeatureValues(traces, bac_featurenames)[0]) - for feature_name in feature_values: if feature_values[feature_name] is not None: feature_values[feature_name] = list(feature_values[feature_name]) diff --git a/tests/test_basic.py b/tests/test_basic.py index 6c7e303c..5ea54062 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -2072,11 +2072,11 @@ def test_getmeanfeaturevalues(): feature_values = \ efel.getFeatureValues( [trace], - ['AP_amplitude', 'BPAPHeightLoc1'], raise_warnings=False) + ['AP_amplitude'], raise_warnings=False) mean_feature_values = efel.getMeanFeatureValues( [trace], [ - 'AP_amplitude', 'BPAPHeightLoc1'], raise_warnings=False) + 'AP_amplitude'], raise_warnings=False) assert (numpy.mean(feature_values[0]['AP_amplitude']) == mean_feature_values[0]['AP_amplitude']) diff --git a/tests/test_units.py b/tests/test_units.py index 7f31d962..e8d6fd35 100644 --- a/tests/test_units.py +++ b/tests/test_units.py @@ -8,7 +8,6 @@ def test_get_unit(): """Unit test for the get_unit function.""" assert get_unit("time_to_last_spike") == "ms" assert get_unit("inv_second_ISI") == "Hz" - assert get_unit("check_AISInitiation") == "constant" assert get_unit("AP1_amp") != "wrong unit" assert get_unit("AP1_amp") == "mV" assert get_unit("ohmic_input_resistance") == "MΩ" diff --git a/tests/testdata/allfeatures/expectedresults.json b/tests/testdata/allfeatures/expectedresults.json index 966c9a76..7420220b 100644 --- a/tests/testdata/allfeatures/expectedresults.json +++ b/tests/testdata/allfeatures/expectedresults.json @@ -251,7 +251,6 @@ 40.98143755958056 ], "AP_phaseslope": null, - "AP_phaseslope_AIS": null, "AP_rise_indices": [ 7074, 9104, @@ -297,9 +296,6 @@ "APlast_width": [ 3.1545523959582193 ], - "BAC_maximum_voltage": [ - -50.69687269736847 - ], "BPAPatt2": null, "BPAPatt3": null, "E10": null, @@ -387,9 +383,6 @@ "burst_number": [ 2 ], - "check_AISInitiation": [ - 1.0 - ], "decay_time_constant_after_stim": [ 13.45188514197874 ], @@ -60602,21 +60595,6 @@ "depol_block_bool": [ 1 ], - "BPAPHeightLoc1": [ - 44.759481866542046 - ], - "BPAPHeightLoc2": [ - 36.96503266314145 - ], - "BPAPAmplitudeLoc1": [ - 33.683406087334944 - ], - "BPAPAmplitudeLoc2": [ - 25.779005513879177 - ], - "BAC_width": [ - 5.9000000000013415 - ], "min_between_peaks_indices": [ 7115, 9833, From 9fa5fa4be6226d2bb431bd4a4985e3a9953ce3b8 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 3 Nov 2023 13:26:19 +0100 Subject: [PATCH 12/85] remove variable (alias) features in LibV2 --- efel/DependencyV5.txt | 31 - efel/cppcore/FillFptrTable.cpp | 32 -- efel/cppcore/LibV2.cpp | 528 ------------------ efel/cppcore/LibV2.h | 64 --- efel/cppcore/cfeature.cpp | 31 - tests/DependencyV5_LibV5peakindices.txt | 31 - tests/featurenames.json | 31 - .../testdata/allfeatures/expectedresults.json | 31 - 8 files changed, 779 deletions(-) diff --git a/efel/DependencyV5.txt b/efel/DependencyV5.txt index 0039d4a7..91ac3977 100644 --- a/efel/DependencyV5.txt +++ b/efel/DependencyV5.txt @@ -49,38 +49,7 @@ LibV2:AP_rise_rate_change #LibV2:AP_rise_rate #LibV1:interpolate LibV2:AP_fall_rate_change #LibV2:AP_fall_rate #LibV1:interpolate LibV2:fast_AHP_change #LibV2:fast_AHP #LibV1:interpolate LibV2:AP_duration_half_width_change #LibV2:AP_duration_half_width #LibV1:interpolate -LibV2:E6 #LibV1:AP_amplitude;APWaveForm #LibV1:interpolate -LibV2:E7 #LibV2:AP_duration;APWaveForm #LibV1:interpolate LibV1:single_burst_ratio #LibV1:ISI_values #LibV1:interpolate -LibV2:BPAPatt2 #LibV1:peak_voltage;location_soma #LibV5:voltage_base;location #LibV1:interpolate -LibV2:BPAPatt3 #LibV1:peak_voltage;location_soma #LibV5:voltage_base;location #LibV1:interpolate -LibV2:E39 #LibV1:mean_frequency;IDthreshold #LibV1:interpolate -LibV2:E39_cod #LibV2:E39 #LibV1:interpolate -LibV2:E2 #LibV2:amp_drop_first_second;APDrop #LibV1:interpolate -LibV2:E3 #LibV2:amp_drop_first_last;APDrop #LibV1:interpolate -LibV2:E4 #LibV2:amp_drop_second_last;APDrop #LibV1:interpolate -LibV2:E5 #LibV2:max_amp_difference;APDrop #LibV1:interpolate -LibV2:E8 #LibV2:AP_duration_half_width;APWaveForm #LibV1:interpolate -LibV2:E9 #LibV2:AP_rise_time;APWaveForm #LibV1:interpolate -LibV2:E10 #LibV2:AP_fall_time;APWaveForm #LibV1:interpolate -LibV2:E11 #LibV2:AP_rise_rate;APWaveForm #LibV1:interpolate -LibV2:E12 #LibV2:AP_fall_rate;APWaveForm #LibV1:interpolate -LibV2:E13 #LibV2:fast_AHP;APWaveForm #LibV1:interpolate -LibV2:E14 #LibV1:peak_voltage;APWaveForm #LibV1:interpolate -LibV2:E15 #LibV2:AP_duration;APWaveForm #LibV1:interpolate -LibV2:E16 #LibV2:AP_duration_half_width;APWaveForm #LibV1:interpolate -LibV2:E17 #LibV2:AP_rise_time;APWaveForm #LibV1:interpolate -LibV2:E18 #LibV2:AP_fall_time;APWaveForm #LibV1:interpolate -LibV2:E19 #LibV2:AP_rise_rate;APWaveForm #LibV1:interpolate -LibV2:E20 #LibV2:AP_fall_rate;APWaveForm #LibV1:interpolate -LibV2:E21 #LibV2:fast_AHP;APWaveForm #LibV1:interpolate -LibV2:E22 #LibV2:AP_amplitude_change;APWaveForm #LibV1:interpolate -LibV2:E23 #LibV2:AP_duration_change;APWaveForm #LibV1:interpolate -LibV2:E24 #LibV2:AP_duration_half_width_change;APWaveForm #LibV1:interpolate -LibV2:E25 #LibV2:AP_rise_rate_change;APWaveForm #LibV1:interpolate -LibV2:E26 #LibV2:AP_fall_rate_change;APWaveForm #LibV1:interpolate -LibV2:E27 #LibV2:fast_AHP_change;APWaveForm #LibV1:interpolate -LibV2:E40 #LibV1:time_to_first_spike;IDrest #LibV1:interpolate LibV2:steady_state_hyper #LibV1:interpolate LibV2:amp_drop_first_second #LibV1:peak_voltage #LibV1:interpolate LibV2:amp_drop_first_last #LibV1:peak_voltage #LibV1:interpolate diff --git a/efel/cppcore/FillFptrTable.cpp b/efel/cppcore/FillFptrTable.cpp index 7c56eaa3..7005f89b 100644 --- a/efel/cppcore/FillFptrTable.cpp +++ b/efel/cppcore/FillFptrTable.cpp @@ -82,38 +82,6 @@ int FillFptrTable() { FptrTableV2["AP_duration_half_width"] = &LibV2::AP_duration_half_width; FptrTableV2["AP_duration_half_width_change"] = &LibV2::AP_duration_half_width_change; - FptrTableV2["E6"] = &LibV2::E6; - FptrTableV2["E7"] = &LibV2::E7; - - FptrTableV2["BPAPatt2"] = &LibV2::BPAPatt2; - FptrTableV2["BPAPatt3"] = &LibV2::BPAPatt3; - FptrTableV2["E39"] = &LibV2::E39; - FptrTableV2["E39_cod"] = &LibV2::E39_cod; - FptrTableV2["E2"] = &LibV2::E2; - FptrTableV2["E3"] = &LibV2::E3; - FptrTableV2["E4"] = &LibV2::E4; - FptrTableV2["E5"] = &LibV2::E5; - FptrTableV2["E8"] = &LibV2::E8; - FptrTableV2["E9"] = &LibV2::E9; - FptrTableV2["E10"] = &LibV2::E10; - FptrTableV2["E11"] = &LibV2::E11; - FptrTableV2["E12"] = &LibV2::E12; - FptrTableV2["E13"] = &LibV2::E13; - FptrTableV2["E14"] = &LibV2::E14; - FptrTableV2["E15"] = &LibV2::E15; - FptrTableV2["E16"] = &LibV2::E16; - FptrTableV2["E17"] = &LibV2::E17; - FptrTableV2["E18"] = &LibV2::E18; - FptrTableV2["E19"] = &LibV2::E19; - FptrTableV2["E20"] = &LibV2::E20; - FptrTableV2["E21"] = &LibV2::E21; - FptrTableV2["E22"] = &LibV2::E22; - FptrTableV2["E23"] = &LibV2::E23; - FptrTableV2["E24"] = &LibV2::E24; - FptrTableV2["E25"] = &LibV2::E25; - FptrTableV2["E26"] = &LibV2::E26; - FptrTableV2["E27"] = &LibV2::E27; - FptrTableV2["E40"] = &LibV2::E40; FptrTableV2["steady_state_hyper"] = &LibV2::steady_state_hyper; FptrTableV2[string("amp_drop_first_second")] = &LibV2::amp_drop_first_second; FptrTableV2[string("amp_drop_first_last")] = &LibV2::amp_drop_first_last; diff --git a/efel/cppcore/LibV2.cpp b/efel/cppcore/LibV2.cpp index a1895584..a3ede731 100644 --- a/efel/cppcore/LibV2.cpp +++ b/efel/cppcore/LibV2.cpp @@ -615,159 +615,6 @@ int LibV2::fast_AHP_change(mapStr2intVec& IntFeatureData, } // end of fast_AHP_change -// *** E6 *** -int LibV2::E6(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e6; - retval = mean_traces_double(DoubleFeatureData, "AP_amplitude", "APWaveForm", - 0, e6); - if (retval >= 0) { - e6.resize(1); - setVec(DoubleFeatureData, StringData, "E6", e6); - } - return retval; -} -// end of E6 - -// *** E7 *** -int LibV2::E7(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e7; - retval = - mean_traces_double(DoubleFeatureData, "AP_duration", "APWaveForm", 0, e7); - if (retval >= 0) { - e7.resize(1); - setVec(DoubleFeatureData, StringData, "E7", e7); - } - return retval; -} -// end of E7 - -// *** BPAPatt2 *** -int LibV2::BPAPatt2(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retval; - vector peakvoltage; - retval = getDoubleParam(DoubleFeatureData, "peak_voltage;location_soma", - peakvoltage); - // one spike required - if (retval <= 0) return -1; - // voltage base - vector vb_dend; - retval = getDoubleParam(DoubleFeatureData, "voltage_base;location_dend620", - vb_dend); - if (retval <= 0) return -1; - vector v_dend; - retval = getDoubleParam(DoubleFeatureData, "V;location_dend620", v_dend); - if (retval <= 0) return -1; - vector vb_soma; - retval = - getDoubleParam(DoubleFeatureData, "voltage_base;location_soma", vb_soma); - if (retval <= 0) return -1; - vector bpapatt; - // this is according to Etay's definition of the backpropagating action - // potential: - // the ratio of the height of somatic and dendritic spike - // bpapatt.push_back((peakvoltage[0] - vb_soma[0]) / - // (*max_element(v_dend.begin(), v_dend.end()) - vb_dend[0])); - // - // this is according to the definition of the error of the backpropagating - // action potential: - // the height of the dendritic spike - bpapatt.push_back(*max_element(v_dend.begin(), v_dend.end()) - vb_dend[0]); - setVec(DoubleFeatureData, StringData, "BPAPatt2", bpapatt); - return retval; -} -// end of BPAPatt2 - -// *** BPAPatt3 *** -int LibV2::BPAPatt3(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retval; - vector peakvoltage; - retval = getDoubleParam(DoubleFeatureData, "peak_voltage;location_soma", - peakvoltage); - // one spike required - if (retval <= 0) return -1; - // voltage base - vector vb_dend; - retval = getDoubleParam(DoubleFeatureData, "voltage_base;location_dend800", - vb_dend); - if (retval <= 0) return -1; - vector v_dend; - retval = getDoubleParam(DoubleFeatureData, "V;location_dend800", v_dend); - if (retval <= 0) return -1; - vector vb_soma; - retval = - getDoubleParam(DoubleFeatureData, "voltage_base;location_soma", vb_soma); - if (retval <= 0) return -1; - vector bpapatt; - // this is according to Etay's definition of the backpropagating action - // potential: - // the ratio of the height of somatic and dendritic spike - // bpapatt.push_back((peakvoltage[0] - vb_soma[0]) / - // (*max_element(v_dend.begin(), v_dend.end()) - vb_dend[0])); - // - // this is according to the definition of the error of the backpropagating - // action potential: - // the height of the dendritic spike - bpapatt.push_back(*max_element(v_dend.begin(), v_dend.end()) - vb_dend[0]); - setVec(DoubleFeatureData, StringData, "BPAPatt3", bpapatt); - return retval; -} -// end of BPAPatt3 - -// *** E39 *** -// unit: Hz / nA -int LibV2::E39(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - vector stim_params; - // retrieve the complete suffixes of all traces where the suffix matches - // "IDthreshold": - getTraces(DoubleFeatureData, "IDthreshold", stim_params); - if (stim_params.size() > 1) { - vector current(stim_params.size()); - vector frequency(stim_params.size()); - // iterate over these traces: - for (size_t i = 0; i < stim_params.size(); i++) { - vector stimulus_current; - // retrieve the trace data - // note that we call getDoubleParam with suffix appended, - // this is the direct access to the global map - getDoubleParam(DoubleFeatureData, "stimulus_current" + stim_params[i], - stimulus_current); - current[i] = stimulus_current[0]; - vector freq; - getDoubleParam(DoubleFeatureData, "mean_frequency" + stim_params[i], - freq); - frequency[i] = freq[0]; - } - linear_fit_result fit; - fit = slope_straight_line_fit(current, frequency); - vector e39(1, fit.slope); - vector e39_cod(1, fit.r_square); - setVec(DoubleFeatureData, StringData, "E39", e39); - setVec(DoubleFeatureData, StringData, "E39_cod", e39_cod); - return e39.size(); - } - GErrorStr += "\nMore than 1 trace required for calculation of E39"; - return -1; -} -// end of E39 - -// *** E39_cod *** -// coefficient of determination for the slope of the IF curve -int LibV2::E39_cod(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - return 1; -} -// end of E39_cod - // *** amp_drop_first_second *** static int __amp_drop_first_second(const vector& peakvoltage, vector& ampdropfirstsecond) { @@ -796,21 +643,6 @@ int LibV2::amp_drop_first_second(mapStr2intVec& IntFeatureData, } // end of amp_drop_first_second -// *** E2 *** -int LibV2::E2(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e2; - retval = mean_traces_double(DoubleFeatureData, "amp_drop_first_second", - "APDrop", 0, e2); - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "E2", e2); - return 1; - } - return retval; -} -// end of E2 - // *** amp_drop_first_last *** static int __amp_drop_first_last(const vector& peakvoltage, vector& ampdropfirstlast) { @@ -839,21 +671,6 @@ int LibV2::amp_drop_first_last(mapStr2intVec& IntFeatureData, } // end of amp_drop_first_last -// *** E3 *** -int LibV2::E3(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e3; - retval = mean_traces_double(DoubleFeatureData, "amp_drop_first_last", - "APDrop", 0, e3); - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "E3", e3); - return 1; - } - return retval; -} -// end of E3 - // *** amp_drop_second_last *** static int __amp_drop_second_last(const vector& peakvoltage, vector& ampdropsecondlast) { @@ -882,21 +699,6 @@ int LibV2::amp_drop_second_last(mapStr2intVec& IntFeatureData, } // end of amp_drop_second_last -// *** E4 *** -int LibV2::E4(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e4; - retval = mean_traces_double(DoubleFeatureData, "amp_drop_second_last", - "APDrop", 0, e4); - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "E4", e4); - return 1; - } - return retval; -} -// end of E4 - // *** max_amp_difference *** static int __max_amp_difference(const vector& peakvoltage, vector& maxampdifference) { @@ -935,323 +737,6 @@ int LibV2::max_amp_difference(mapStr2intVec& IntFeatureData, } // end of max_amp_difference -// *** E5 *** -int LibV2::E5(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e5; - retval = mean_traces_double(DoubleFeatureData, "max_amp_difference", "APDrop", - 0, e5); - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "E5", e5); - return 1; - } - return retval; -} -// end of E5 - -// *** E8 *** -int LibV2::E8(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e8; - retval = mean_traces_double(DoubleFeatureData, "AP_duration_half_width", - "APWaveForm", 0, e8); - if (retval >= 0) { - e8.resize(1); - setVec(DoubleFeatureData, StringData, "E8", e8); - } - return retval; -} -// end of E8 - -// *** E9 *** -int LibV2::E9(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e9; - retval = mean_traces_double(DoubleFeatureData, "AP_rise_time", "APWaveForm", - 0, e9); - if (retval >= 0) { - e9.resize(1); - setVec(DoubleFeatureData, StringData, "E9", e9); - } - return retval; -} -// end of E9 - -// *** E10 *** -int LibV2::E10(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e10; - retval = mean_traces_double(DoubleFeatureData, "AP_fall_time", "APWaveForm", - 0, e10); - if (retval >= 0) { - e10.resize(1); - setVec(DoubleFeatureData, StringData, "E10", e10); - } - return retval; -} -// end of E10 - -// *** E11 *** -int LibV2::E11(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e11; - retval = mean_traces_double(DoubleFeatureData, "AP_rise_rate", "APWaveForm", - 0, e11); - if (retval >= 0) { - e11.resize(1); - setVec(DoubleFeatureData, StringData, "E11", e11); - } - return retval; -} -// end of E11 - -// *** E12 *** -int LibV2::E12(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e12; - retval = mean_traces_double(DoubleFeatureData, "AP_fall_rate", "APWaveForm", - 0, e12); - if (retval >= 0) { - e12.resize(1); - setVec(DoubleFeatureData, StringData, "E12", e12); - } - return retval; -} -// end of E12 - -// *** E13 *** -int LibV2::E13(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e13; - retval = - mean_traces_double(DoubleFeatureData, "fast_AHP", "APWaveForm", 0, e13); - if (retval >= 0) { - e13.resize(1); - setVec(DoubleFeatureData, StringData, "E13", e13); - } - return retval; -} -// end of E13 - -// *** E14 *** -int LibV2::E14(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e14; - retval = mean_traces_double(DoubleFeatureData, "peak_voltage", "APWaveForm", - 0, e14); - if (retval >= 0) { - e14[0] = e14[1]; - e14.resize(1); - setVec(DoubleFeatureData, StringData, "E14", e14); - } - return retval; -} -// end of E14 - -// *** E15 *** -int LibV2::E15(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e15; - retval = mean_traces_double(DoubleFeatureData, "AP_duration", "APWaveForm", 0, - e15); - if (retval >= 0) { - e15[0] = e15[1]; - e15.resize(1); - setVec(DoubleFeatureData, StringData, "E15", e15); - } - return retval; -} -// end of E15 - -// *** E16 *** -int LibV2::E16(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e16; - retval = mean_traces_double(DoubleFeatureData, "AP_duration_half_width", - "APWaveForm", 0, e16); - if (retval >= 0) { - e16[0] = e16[1]; - e16.resize(1); - setVec(DoubleFeatureData, StringData, "E16", e16); - } - return retval; -} -// end of E16 - -// *** E17 *** -int LibV2::E17(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e17; - retval = mean_traces_double(DoubleFeatureData, "AP_rise_time", "APWaveForm", - 0, e17); - if (retval >= 0) { - e17[0] = e17[1]; - e17.resize(1); - setVec(DoubleFeatureData, StringData, "E17", e17); - } - return retval; -} -// end of E17 - -// *** E18 *** -int LibV2::E18(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e18; - retval = mean_traces_double(DoubleFeatureData, "AP_fall_time", "APWaveForm", - 0, e18); - if (retval >= 0) { - e18[0] = e18[1]; - e18.resize(1); - setVec(DoubleFeatureData, StringData, "E18", e18); - } - return retval; -} -// end of E18 - -// *** E19 *** -int LibV2::E19(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e19; - retval = mean_traces_double(DoubleFeatureData, "AP_rise_rate", "APWaveForm", - 0, e19); - if (retval >= 0) { - e19[0] = e19[1]; - e19.resize(1); - setVec(DoubleFeatureData, StringData, "E19", e19); - } - return retval; -} -// end of E19 - -// *** E20 *** -int LibV2::E20(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e20; - retval = mean_traces_double(DoubleFeatureData, "AP_fall_rate", "APWaveForm", - 0, e20); - if (retval >= 0) { - e20[0] = e20[1]; - e20.resize(1); - setVec(DoubleFeatureData, StringData, "E20", e20); - } - return retval; -} -// end of E20 - -// *** E21 *** -int LibV2::E21(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e21; - retval = - mean_traces_double(DoubleFeatureData, "fast_AHP", "APWaveForm", 0, e21); - if (retval >= 0) { - e21[0] = e21[1]; - e21.resize(1); - setVec(DoubleFeatureData, StringData, "E21", e21); - } - return retval; -} -// end of E21 - -// *** E22 *** -int LibV2::E22(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e22; - retval = mean_traces_double(DoubleFeatureData, "AP_amplitude_change", - "APWaveForm", 0, e22); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "E22", e22); - } - return retval; -} -// end of E22 - -// *** E23 *** -int LibV2::E23(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e23; - retval = mean_traces_double(DoubleFeatureData, "AP_duration_change", - "APWaveForm", 0, e23); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "E23", e23); - } - return retval; -} -// end of E23 - -// *** E24 *** -int LibV2::E24(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e24; - retval = mean_traces_double( - DoubleFeatureData, "AP_duration_half_width_change", "APWaveForm", 0, e24); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "E24", e24); - } - return retval; -} -// end of E24 - -// *** E25 *** -int LibV2::E25(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e25; - retval = mean_traces_double(DoubleFeatureData, "AP_rise_rate_change", - "APWaveForm", 0, e25); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "E25", e25); - } - return retval; -} -// end of E25 - -// *** E26 *** -int LibV2::E26(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e26; - retval = mean_traces_double(DoubleFeatureData, "AP_fall_rate_change", - "APWaveForm", 0, e26); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "E26", e26); - } - return retval; -} -// end of E26 - -// *** E27 *** -int LibV2::E27(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e27; - retval = mean_traces_double(DoubleFeatureData, "fast_AHP_change", - "APWaveForm", 0, e27); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "E27", e27); - } - return retval; -} -// end of E27 - // steady state of the voltage response during hyperpolarizing stimulus, // elementary feature for E29 // *** steady_state_hyper @@ -1306,19 +791,6 @@ int LibV2::steady_state_hyper(mapStr2intVec& IntFeatureData, return retval; } -// *** E40 *** -int LibV2::E40(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector e40; - retval = mean_traces_double(DoubleFeatureData, "time_to_first_spike", - "IDrest", 0, e40); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "E40", e40); - } - return retval; -} -// end of E40 // // end of feature definition diff --git a/efel/cppcore/LibV2.h b/efel/cppcore/LibV2.h index 75fb85d3..efdc9bbd 100644 --- a/efel/cppcore/LibV2.h +++ b/efel/cppcore/LibV2.h @@ -72,73 +72,9 @@ int AP_duration_half_width(mapStr2intVec& IntFeatureData, int AP_duration_half_width_change(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); - -int E6(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E7(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); - -int BPAPatt2(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int BPAPatt3(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E39(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E39_cod(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E2(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E3(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E4(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E5(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E8(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E9(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E10(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E11(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E12(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E13(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E14(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E15(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E16(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E17(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E18(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E19(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E20(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E21(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E22(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E23(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E24(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E25(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E26(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); -int E27(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); int steady_state_hyper(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int E40(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); int amp_drop_first_second(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 43dad475..b4639403 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -120,40 +120,9 @@ void cFeature::fillfeaturetypes() { featuretypes["AP_fall_rate_change"] = "double"; featuretypes["fast_AHP_change"] = "double"; featuretypes["AP_duration_half_width_change"] = "double"; - featuretypes["E6"] = "double"; - featuretypes["E7"] = "double"; featuretypes["AP_height"] = "double"; featuretypes["AP_amplitude"] = "double"; featuretypes["single_burst_ratio"] = "double"; - featuretypes["BPAPatt2"] = "double"; - featuretypes["BPAPatt3"] = "double"; - featuretypes["E39"] = "double"; - featuretypes["E39_cod"] = "double"; - featuretypes["E2"] = "double"; - featuretypes["E3"] = "double"; - featuretypes["E4"] = "double"; - featuretypes["E5"] = "double"; - featuretypes["E8"] = "double"; - featuretypes["E9"] = "double"; - featuretypes["E10"] = "double"; - featuretypes["E11"] = "double"; - featuretypes["E12"] = "double"; - featuretypes["E13"] = "double"; - featuretypes["E14"] = "double"; - featuretypes["E15"] = "double"; - featuretypes["E16"] = "double"; - featuretypes["E17"] = "double"; - featuretypes["E18"] = "double"; - featuretypes["E19"] = "double"; - featuretypes["E20"] = "double"; - featuretypes["E21"] = "double"; - featuretypes["E22"] = "double"; - featuretypes["E23"] = "double"; - featuretypes["E24"] = "double"; - featuretypes["E25"] = "double"; - featuretypes["E26"] = "double"; - featuretypes["E27"] = "double"; - featuretypes["E40"] = "double"; featuretypes["steady_state_hyper"] = "double"; featuretypes["AP_width"] = "double"; featuretypes["doublet_ISI"] = "double"; diff --git a/tests/DependencyV5_LibV5peakindices.txt b/tests/DependencyV5_LibV5peakindices.txt index 60e43aad..7b173dce 100644 --- a/tests/DependencyV5_LibV5peakindices.txt +++ b/tests/DependencyV5_LibV5peakindices.txt @@ -45,38 +45,7 @@ LibV2:AP_rise_rate_change #LibV2:AP_rise_rate LibV2:AP_fall_rate_change #LibV2:AP_fall_rate LibV2:fast_AHP_change #LibV2:fast_AHP LibV2:AP_duration_half_width_change #LibV2:AP_duration_half_width -LibV2:E6 #LibV1:AP_amplitude;APWaveForm -LibV2:E7 #LibV2:AP_duration;APWaveForm LibV1:single_burst_ratio #LibV1:ISI_values -LibV2:BPAPatt2 #LibV1:peak_voltage;location_soma #LibV5:voltage_base;location -LibV2:BPAPatt3 #LibV1:peak_voltage;location_soma #LibV5:voltage_base;location -LibV2:E39 #LibV1:mean_frequency;IDthreshold -LibV2:E39_cod #LibV2:E39 -LibV2:E2 #LibV2:amp_drop_first_second;APDrop -LibV2:E3 #LibV2:amp_drop_first_last;APDrop -LibV2:E4 #LibV2:amp_drop_second_last;APDrop -LibV2:E5 #LibV2:max_amp_difference;APDrop -LibV2:E8 #LibV2:AP_duration_half_width;APWaveForm -LibV2:E9 #LibV2:AP_rise_time;APWaveForm -LibV2:E10 #LibV2:AP_fall_time;APWaveForm -LibV2:E11 #LibV2:AP_rise_rate;APWaveForm -LibV2:E12 #LibV2:AP_fall_rate;APWaveForm -LibV2:E13 #LibV2:fast_AHP;APWaveForm -LibV2:E14 #LibV1:peak_voltage;APWaveForm -LibV2:E15 #LibV2:AP_duration;APWaveForm -LibV2:E16 #LibV2:AP_duration_half_width;APWaveForm -LibV2:E17 #LibV2:AP_rise_time;APWaveForm -LibV2:E18 #LibV2:AP_fall_time;APWaveForm -LibV2:E19 #LibV2:AP_rise_rate;APWaveForm -LibV2:E20 #LibV2:AP_fall_rate;APWaveForm -LibV2:E21 #LibV2:fast_AHP;APWaveForm -LibV2:E22 #LibV2:AP_amplitude_change;APWaveForm -LibV2:E23 #LibV2:AP_duration_change;APWaveForm -LibV2:E24 #LibV2:AP_duration_half_width_change;APWaveForm -LibV2:E25 #LibV2:AP_rise_rate_change;APWaveForm -LibV2:E26 #LibV2:AP_fall_rate_change;APWaveForm -LibV2:E27 #LibV2:fast_AHP_change;APWaveForm -LibV2:E40 #LibV1:time_to_first_spike;IDrest LibV2:steady_state_hyper LibV2:amp_drop_first_second #LibV1:peak_voltage LibV2:amp_drop_first_last #LibV1:peak_voltage diff --git a/tests/featurenames.json b/tests/featurenames.json index 9f1112d9..74d3b486 100644 --- a/tests/featurenames.json +++ b/tests/featurenames.json @@ -49,37 +49,6 @@ "AP_width", "APlast_amp", "APlast_width", - "BPAPatt2", - "BPAPatt3", - "E10", - "E11", - "E12", - "E13", - "E14", - "E15", - "E16", - "E17", - "E18", - "E19", - "E2", - "E20", - "E21", - "E22", - "E23", - "E24", - "E25", - "E26", - "E27", - "E3", - "E39", - "E39_cod", - "E4", - "E40", - "E5", - "E6", - "E7", - "E8", - "E9", "ISI_CV", "ISI_log_slope", "ISI_log_slope_skip", diff --git a/tests/testdata/allfeatures/expectedresults.json b/tests/testdata/allfeatures/expectedresults.json index 7420220b..491cdf23 100644 --- a/tests/testdata/allfeatures/expectedresults.json +++ b/tests/testdata/allfeatures/expectedresults.json @@ -296,37 +296,6 @@ "APlast_width": [ 3.1545523959582193 ], - "BPAPatt2": null, - "BPAPatt3": null, - "E10": null, - "E11": null, - "E12": null, - "E13": null, - "E14": null, - "E15": null, - "E16": null, - "E17": null, - "E18": null, - "E19": null, - "E2": null, - "E20": null, - "E21": null, - "E22": null, - "E23": null, - "E24": null, - "E25": null, - "E26": null, - "E27": null, - "E3": null, - "E39": null, - "E39_cod": null, - "E4": null, - "E40": null, - "E5": null, - "E6": null, - "E7": null, - "E8": null, - "E9": null, "ISI_CV": [ 0.44788080327644053 ], From f07895b5a348ec388eaad879b02ed7bb860c7dba Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 3 Nov 2023 14:46:05 +0100 Subject: [PATCH 13/85] simplify feature pointers representation in cppcore, remove wildcards --- efel/cppcore/DependencyTree.cpp | 69 +++++------------ efel/cppcore/DependencyTree.h | 10 +-- efel/cppcore/Global.h | 1 - efel/cppcore/cfeature.cpp | 128 ++++++-------------------------- efel/cppcore/cfeature.h | 3 +- efel/cppcore/mapoperations.cpp | 103 ------------------------- efel/cppcore/mapoperations.h | 10 --- efel/cppcore/types.h | 2 - 8 files changed, 45 insertions(+), 281 deletions(-) diff --git a/efel/cppcore/DependencyTree.cpp b/efel/cppcore/DependencyTree.cpp index 3416125a..804d7fc5 100644 --- a/efel/cppcore/DependencyTree.cpp +++ b/efel/cppcore/DependencyTree.cpp @@ -61,12 +61,12 @@ int cTree::getDependencyList(string) { * FptrTable : * FptrLookup | vector of pairs: * first | string: feature name - * second | vector of featureStringPair + * second | vector of feature_function to represent list of dependent features * */ int cTree::setFeaturePointers(map &mapFptrLib, feature2function *FptrTable, - map > *FptrLookup) + map > *FptrLookup) { list::iterator lstItr; map::iterator mapLibItr; @@ -74,9 +74,8 @@ int cTree::setFeaturePointers(map &mapFptrLib, feature2function::iterator mapFeatureItr; string strLibFeature, strLib, strFeature; - string wildcards; - vector vecfptr; + vector vecfptr; if (vecFeature.size() == 0) return -1; @@ -87,7 +86,7 @@ int cTree::setFeaturePointers(map &mapFptrLib, FinalList.clear(); strLibFeature = vecFeature[i]; // fill FinalList with all the dependencies of feature vecFeature[i] - getDependency(strLibFeature, ""); + getDependency(strLibFeature); vecfptr.clear(); for (lstItr = FinalList.begin(); lstItr != FinalList.end(); lstItr++) { // Here strLibFeature is the feature name of the dependent feature @@ -102,14 +101,7 @@ int cTree::setFeaturePointers(map &mapFptrLib, strLib = strLibFeature.substr(0, nPos); // Put feature name in strFeature - size_t wcpos = strLibFeature.find(";"); - if (wcpos == string::npos) { - strFeature = strLibFeature.substr(nPos + 1); - wildcards = ""; - } else { - strFeature = strLibFeature.substr(nPos + 1, wcpos - nPos - 1); - wildcards = strLibFeature.substr(wcpos); - } + strFeature = strLibFeature.substr(nPos + 1); // Find the feature function pointer map for the library mapLibItr = mapFptrLib.find(strLib); @@ -127,15 +119,13 @@ int cTree::setFeaturePointers(map &mapFptrLib, return -1; } - // Add the feature function pointer and wildcards to the list of dependent - // features - vecfptr.push_back(featureStringPair(mapFeatureItr->second, wildcards)); + vecfptr.push_back(mapFeatureItr->second); FptrTable->insert(std::pair( strFeature, mapFeatureItr->second)); } // Add the vecfptr from above to a map with as key the base featurei FptrLookup->insert( - std::pair >(strFeature, vecfptr)); + std::pair >(strFeature, vecfptr)); } return 1; @@ -180,43 +170,22 @@ int cTree::getChilds(string str, list &childs) { return 1; } -/* - * - * Fill FinalList with a list of all the feature matching the wildcards - * - */ -int cTree::getDependency(string strLine, string wildcards) { - list tmpChild; - - // parse wildcards out of "LibVx:feature_name;wildcards_name" - size_t wcpos = strLine.find(";"); - if (wcpos != string::npos) { - wildcards = strLine.substr(wcpos); - strLine = strLine.substr(0, wcpos); - } - unsigned childCount = 0; +int cTree::getDependency(const std::string& strLine) { + std::list tmpChild; + getChilds(strLine, tmpChild); - if (tmpChild.size() != 0) { - childCount = tmpChild.size(); - for (unsigned i = 0; i < childCount; i++) { - string str = tmpChild.front(); - tmpChild.pop_front(); - getDependency(str, wildcards); - } + for (const auto& childFeature : tmpChild) { + getDependency(childFeature); // Recursively get dependencies of the child feature. } - AddUniqueItem(strLine + wildcards, FinalList); + AddUniqueItem(strLine); // Add the feature itself to the FinalList. return 0; } -int cTree::AddUniqueItem(string strFeature, list &lstFinal) { - list::iterator lstItr; - bool FoundFlag = false; - for (lstItr = lstFinal.begin(); lstItr != lstFinal.end(); lstItr++) { - if (strFeature == *lstItr) { - FoundFlag = true; - break; - } +bool cTree::AddUniqueItem(const std::string& strFeature) { + auto it = std::find(FinalList.begin(), FinalList.end(), strFeature); + if (it == FinalList.end()) { + FinalList.push_back(strFeature); + return true; // Item was added } - if (!FoundFlag) lstFinal.push_back(strFeature); - return 1; + return false; // Item was not added (already present) } diff --git a/efel/cppcore/DependencyTree.h b/efel/cppcore/DependencyTree.h index 880cbd4d..0644e209 100644 --- a/efel/cppcore/DependencyTree.h +++ b/efel/cppcore/DependencyTree.h @@ -45,14 +45,10 @@ class cTree { int getDependencyList(string str); int setFeaturePointers(map &mapFptrLib, feature2function *FptrTable, - map > *FptrLookup); - - int setFeaturePointers(map &mapFptrLib, - feature2function *FptrTable, - map > *FptrLookup); + map > *FptrLookup); int getChilds(string strLine, list &childs); - int getDependency(string strLine, string parent_stim); - int AddUniqueItem(string strFeature, list &lstFinal); + int getDependency(const std::string& strLine); + bool AddUniqueItem(const std::string& strFeature); int getAllParents(vector &vecFeature); }; diff --git a/efel/cppcore/Global.h b/efel/cppcore/Global.h index 241d5645..a2d0e05e 100644 --- a/efel/cppcore/Global.h +++ b/efel/cppcore/Global.h @@ -26,7 +26,6 @@ feature2function FptrTableV1; feature2function FptrTableV2; feature2function FptrTableV3; -feature2function FptrTableV4; feature2function FptrTableV5; feature2function FptrTable; diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index b4639403..e0dc8517 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -241,17 +241,6 @@ void cFeature::get_feature_names(vector& feature_names) { } } -/* -int cFeature::getmapfptrVec(string strName, vector &vFptr){ - map >::iterator mapFptrItr; - mapFptrItr= FptrLookup.find(strName); - if(mapFptrItr == FptrLookup.end()) {GErrorStr = GErrorStr + string("Feature -[") + strName + "] dependency is missing\n"; return -1;} - vFptr = mapFptrItr->second; - return 1; -} -*/ - int cFeature::printMapMember(FILE* fp) { map >::iterator mapstr2IntItr; fprintf(fin, "\n\n\n IntData....."); @@ -273,107 +262,34 @@ int cFeature::setFeatureInt(string strName, vector& v) { return 1; } -/* - * Take a wildcard string as an argument: - * wildcards seperated by ';' e.g. "APWaveForm;soma" - * Find traces containing every required wildcard in the name - * e.g. "V;APWaveForm200;soma", "V;APWaveForm240;soma" - * Finally return a vector of all parameter strings - * e.g. (";APWaveForm200;soma", ";APWaveForm240;soma", ...) - */ -void cFeature::getTraces(const string& wildcards, vector& params) { - map >::const_iterator map_it; - string featurename; - params.clear(); - for (map_it = mapDoubleData.begin(); map_it != mapDoubleData.end(); - ++map_it) { - featurename = map_it->first; - // find traces - if (featurename.find("V;") != string::npos) { - bool match = true; - int nextpos; - int oldpos = 1; - do { - string param; - nextpos = wildcards.find(";", oldpos + 1); - if (nextpos == -1) { - nextpos = wildcards.size(); - } - param = wildcards.substr(oldpos, nextpos - oldpos - 1); - if (featurename.find(param) == string::npos) { - match = false; - break; - } - oldpos = nextpos; - } while (nextpos != (int)wildcards.size()); - if (match) { - params.push_back(featurename.substr(1)); - } +int cFeature::calc_features(const std::string& name) { + // stimulus extension + auto lookup_it = fptrlookup.find(name); + // print lookup_it + std::cout<<"lookup_it first: "<first< >::const_iterator lookup_it( - fptrlookup.find(name)); - if (lookup_it == fptrlookup.end()) { - throw std::runtime_error("Feature dependency file entry or pointer table " - "entry for '" + name + "' is missing."); - } - bool last_failed = false; - - for (vector::const_iterator pfptrstring = - lookup_it->second.begin(); - pfptrstring != lookup_it->second.end(); ++pfptrstring) { - // set parameters, for now only the wildcard 'stimulusname' - // - feature_function function = pfptrstring->first; - string wildcard = pfptrstring->second; - if (wildcard.empty()) { - // make sure that - // - the feature is called only once - // - the feature operates on "V" and "T" if it operates on traces at all - setFeatureString("params", ""); - if (function(mapIntData, mapDoubleData, mapStrData) < 0) { - // GErrorStr += "\nFeature [" + name + "] called twice, or doesn't - // operate on V and T."; - // return -1;i - last_failed = true; - } else { - last_failed = false; - } - } else { - // make sure that - // -the feature is called once for every trace according to the wildcard - // -the feature operates on each trace - vector params; - // TODO - // read stimulus configuration file and parse additional parameters - // such as number of required traces - getTraces(wildcard, params); - if (params.empty()) { - GErrorStr += "\nMissing trace with wildcards " + wildcard; - return -1; - } - for (unsigned i = 0; i < params.size(); i++) { - // setting the "params" entry here makes sure that the required features - // require specific traces also - setFeatureString("params", params[i]); + bool last_failed = false; + + int i = 0; + for (const auto& pfptrstring : lookup_it->second) { + std::cout< diff --git a/efel/cppcore/cfeature.h b/efel/cppcore/cfeature.h index 2d3eb6d4..62713622 100644 --- a/efel/cppcore/cfeature.h +++ b/efel/cppcore/cfeature.h @@ -43,7 +43,7 @@ class cFeature { void fillfeaturetypes(); public: - std::map > fptrlookup; + std::map > fptrlookup; eFELLogger logger; cFeature(const string& depFile, const string& outdir); @@ -59,7 +59,6 @@ class cFeature { int setFeatureDouble(string strName, vector& DoubleVec); int setFeatureString(const string& key, const string& value); int getFeatureString(const string& key, string& value); - void getTraces(const string& wildcard, vector& traces); int printFeature(const char* strFileName); int printMapMember(FILE* fp); diff --git a/efel/cppcore/mapoperations.cpp b/efel/cppcore/mapoperations.cpp index 78899dd6..19b46da8 100644 --- a/efel/cppcore/mapoperations.cpp +++ b/efel/cppcore/mapoperations.cpp @@ -100,109 +100,6 @@ int getVec(std::map >& FeatureData, mapStr2Str& Stri return (v.size()); } -/* - * Take a wildcard string as an argument: - * wildcards seperated by ';' e.g. "APWaveForm;soma" - * Find traces containing every required wildcard in the name - * e.g. "V;APWaveForm200;soma", "V;APWaveForm240;soma" - * Finally return a vector of all parameter strings - * e.g. (";APWaveForm200;soma", ";APWaveForm240;soma", ...) - */ -void getTraces(mapStr2doubleVec& mapDoubleData, const string& wildcards, - vector& params) { - mapStr2doubleVec::const_iterator map_it; - string featurename; - params.clear(); - for (map_it = mapDoubleData.begin(); map_it != mapDoubleData.end(); - ++map_it) { - featurename = map_it->first; - // find traces - if (featurename.find("V;") != string::npos) { - bool match = true; - int nextpos; - int oldpos = 1; - do { - string param; - nextpos = wildcards.find(";", oldpos + 1); - if (nextpos == -1) { - nextpos = wildcards.size(); - } - param = wildcards.substr(oldpos, nextpos - oldpos - 1); - if (featurename.find(param) == string::npos) { - match = false; - break; - } - oldpos = nextpos; - } while (nextpos != (int)wildcards.size()); - if (match) { - params.push_back(featurename.substr(1)); - } - } - } -} - -// mean over all traces obtained with the same stimulus -int mean_traces_double(mapStr2doubleVec& DoubleFeatureData, - const string& feature, const string& stimulus_name, - int i_elem, vector& mean) { - double sum = 0.; - vector stim_params; - getTraces(DoubleFeatureData, stimulus_name, stim_params); - if (stim_params.size() > 0) { - for (unsigned i = 0; i < stim_params.size(); i++) { - vector elem_feature; - getDoubleParam(DoubleFeatureData, feature + stim_params[i], elem_feature); - if (i_elem > (int)elem_feature.size() - 1 || elem_feature.size() == 0) { - GErrorStr += - "mean_traces_double: feature vector of the elementary feature does " - "not contain that many elements.\n"; - } - if (i_elem == -1) { - sum += elem_feature.back(); - } else { - sum += elem_feature[i_elem]; - } - } - mean.push_back(sum / stim_params.size()); - return stim_params.size(); - } else { - return -1; - } -} - -// standard deviation over all traces obtained with the same stimulus -int std_traces_double(mapStr2doubleVec& DoubleFeatureData, - const string& feature, const string& stimulus_name, - double mean, int i_elem, vector& std) { - double sum = 0.; - double v; - vector stim_params; - getTraces(DoubleFeatureData, stimulus_name, stim_params); - if (stim_params.size() > 0) { - for (unsigned i = 0; i < stim_params.size(); i++) { - vector elem_feature; - getDoubleParam(DoubleFeatureData, feature + stim_params[i], elem_feature); - if (i_elem > (int)elem_feature.size() - 1 || - (int)elem_feature.size() == 0) { - GErrorStr += - "std_traces_double: feature vector of the elementary feature does " - "not contain that many elements.\n"; - } - if (i_elem == -1) { - v = elem_feature.back(); - } else { - v = elem_feature[i_elem]; - } - double deviation = v - mean; - sum += deviation * deviation; - } - std.push_back(sqrt(sum / (double)(stim_params.size() - 1))); - return stim_params.size(); - } else { - return -1; - } -} - template void setVec(std::map >& FeatureData, mapStr2Str& StringData, string key, const vector& value); template void setVec(std::map >& FeatureData, mapStr2Str& StringData, diff --git a/efel/cppcore/mapoperations.h b/efel/cppcore/mapoperations.h index cb26edc7..df76f780 100644 --- a/efel/cppcore/mapoperations.h +++ b/efel/cppcore/mapoperations.h @@ -41,14 +41,4 @@ void setVec(std::map >& FeatureData, mapStr2Str& Str template int getVec(std::map >& FeatureData, mapStr2Str& StringData, string strFeature, vector& v); -// eCode feature convenience function -int mean_traces_double(mapStr2doubleVec& DoubleFeatureData, - const string& feature, const string& stimulus_name, - int i_elem, vector& mean); -int std_traces_double(mapStr2doubleVec& DoubleFeatureData, - const string& feature, const string& stimulus_name, - double mean, int i_elem, vector& std); -void getTraces(mapStr2doubleVec& DoubleFeatureData, const string& wildcard, - vector& traces); - #endif diff --git a/efel/cppcore/types.h b/efel/cppcore/types.h index e7a8787b..d213e60c 100644 --- a/efel/cppcore/types.h +++ b/efel/cppcore/types.h @@ -37,6 +37,4 @@ typedef int (*feature_function)(mapStr2intVec &, */ typedef std::map feature2function; -typedef std::pair featureStringPair; - #endif From 655cd030b11e441ade188c6c6ff355817a56f879 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 3 Nov 2023 17:41:52 +0100 Subject: [PATCH 14/85] make AddUniqueItem void --- efel/cppcore/DependencyTree.cpp | 11 +++++------ efel/cppcore/DependencyTree.h | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/efel/cppcore/DependencyTree.cpp b/efel/cppcore/DependencyTree.cpp index 804d7fc5..e71108c0 100644 --- a/efel/cppcore/DependencyTree.cpp +++ b/efel/cppcore/DependencyTree.cpp @@ -27,7 +27,7 @@ static void removeAllWhiteSpace(string &str) { } cTree::cTree(const char *strFileName) { - std::string line; + string line; std::ifstream input(strFileName); if (input.is_open()) { @@ -170,8 +170,9 @@ int cTree::getChilds(string str, list &childs) { return 1; } -int cTree::getDependency(const std::string& strLine) { - std::list tmpChild; + +int cTree::getDependency(const string& strLine) { + std::list tmpChild; getChilds(strLine, tmpChild); for (const auto& childFeature : tmpChild) { @@ -181,11 +182,9 @@ int cTree::getDependency(const std::string& strLine) { return 0; } -bool cTree::AddUniqueItem(const std::string& strFeature) { +void cTree::AddUniqueItem(const string& strFeature) { auto it = std::find(FinalList.begin(), FinalList.end(), strFeature); if (it == FinalList.end()) { FinalList.push_back(strFeature); - return true; // Item was added } - return false; // Item was not added (already present) } diff --git a/efel/cppcore/DependencyTree.h b/efel/cppcore/DependencyTree.h index 0644e209..adaaf83b 100644 --- a/efel/cppcore/DependencyTree.h +++ b/efel/cppcore/DependencyTree.h @@ -47,8 +47,8 @@ class cTree { feature2function *FptrTable, map > *FptrLookup); int getChilds(string strLine, list &childs); - int getDependency(const std::string& strLine); - bool AddUniqueItem(const std::string& strFeature); + int getDependency(const string& strLine); + void AddUniqueItem(const string& strFeature); int getAllParents(vector &vecFeature); }; From 34cfb4da9f250532600452c56989c6ffab015605 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 3 Nov 2023 17:43:03 +0100 Subject: [PATCH 15/85] remove empty function getDependencyList --- efel/cppcore/DependencyTree.cpp | 5 ----- efel/cppcore/DependencyTree.h | 1 - 2 files changed, 6 deletions(-) diff --git a/efel/cppcore/DependencyTree.cpp b/efel/cppcore/DependencyTree.cpp index e71108c0..69acb7f8 100644 --- a/efel/cppcore/DependencyTree.cpp +++ b/efel/cppcore/DependencyTree.cpp @@ -47,11 +47,6 @@ cTree::cTree(const char *strFileName) { } getAllParents(vecFeature); } -int cTree::getDependencyList(string) { - for (unsigned i = 0; i < strDependencyFile.size(); i++) { - } - return 1; -} /** * diff --git a/efel/cppcore/DependencyTree.h b/efel/cppcore/DependencyTree.h index adaaf83b..d699ee0c 100644 --- a/efel/cppcore/DependencyTree.h +++ b/efel/cppcore/DependencyTree.h @@ -42,7 +42,6 @@ class cTree { list ChildList; cTree() {}; cTree(const char *strFileName); - int getDependencyList(string str); int setFeaturePointers(map &mapFptrLib, feature2function *FptrTable, map > *FptrLookup); From b8f629a43390c4d0dbb3830aa4e735d5c12a32e5 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 3 Nov 2023 17:49:17 +0100 Subject: [PATCH 16/85] directly check stream's state after opening the file --- efel/cppcore/DependencyTree.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/efel/cppcore/DependencyTree.cpp b/efel/cppcore/DependencyTree.cpp index 69acb7f8..c7f5ad48 100644 --- a/efel/cppcore/DependencyTree.cpp +++ b/efel/cppcore/DependencyTree.cpp @@ -27,24 +27,20 @@ static void removeAllWhiteSpace(string &str) { } cTree::cTree(const char *strFileName) { - string line; - std::ifstream input(strFileName); - if (input.is_open()) { - std::getline(input, line); + if (!input) { + ErrorStr += "\nCould not open the file " + string(strFileName); + return; + } + + for (string line; std::getline(input, line); ) { removeAllWhiteSpace(line); - if (!line.empty()) - strDependencyFile.push_back(line); - while (!(input.fail() || input.eof())) { - std::getline(input, line); - removeAllWhiteSpace(line); - if (!line.empty()) - strDependencyFile.push_back(line); + if (!line.empty()) { + strDependencyFile.push_back(std::move(line)); } - } else { - ErrorStr = ErrorStr + string("\nCould not open the file ") + strFileName; } + getAllParents(vecFeature); } From d91d476c8b721eb506bd8bb6d0665392c06b6bfd Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 3 Nov 2023 18:12:22 +0100 Subject: [PATCH 17/85] remove dead code in efel and cfeature --- efel/cppcore/cfeature.cpp | 49 ----------------------- efel/cppcore/cfeature.h | 3 -- efel/cppcore/efel.cpp | 81 --------------------------------------- efel/cppcore/efel.h | 11 ------ 4 files changed, 144 deletions(-) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index e0dc8517..2738a897 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -241,20 +241,6 @@ void cFeature::get_feature_names(vector& feature_names) { } } -int cFeature::printMapMember(FILE* fp) { - map >::iterator mapstr2IntItr; - fprintf(fin, "\n\n\n IntData....."); - for (mapstr2IntItr = mapIntData.begin(); mapstr2IntItr != mapIntData.end(); - mapstr2IntItr++) - fprintf(fin, "\n\t%s", mapstr2IntItr->first.c_str()); - fprintf(fin, "\n\n DoubleData.........."); - map >::iterator mapstr2DoubleItr; - for (mapstr2DoubleItr = mapDoubleData.begin(); - mapstr2DoubleItr != mapDoubleData.end(); mapstr2DoubleItr++) - fprintf(fin, "\n\t%s", mapstr2DoubleItr->first.c_str()); - return 1; -} - int cFeature::setFeatureInt(string strName, vector& v) { logger << "Set " << strName << ":" << v << endl; // printf ("Setting int feature [%s] = %d\n", strName.c_str(),v[0]); @@ -356,41 +342,6 @@ int cFeature::setFeatureDouble(string strName, vector& v) { return 1; } -int cFeature::printFeature(const char* strFileName) { - FILE* fp = fopen(strFileName, "w"); - if (fp) { - map >::iterator mapItrInt; - int n = mapIntData.size(); - fprintf(fp, "\n mapIntData.. Total element = [%d]", n); - for (mapItrInt = mapIntData.begin(); mapItrInt != mapIntData.end(); - mapItrInt++) { - string str = mapItrInt->first; - vector* v = &(mapItrInt->second); - fprintf(fp, "\n ParameterName = [%s] size = [%d]\n\t", str.c_str(), - (int)v->size()); - for (unsigned j = 0; j < v->size(); j++) { - fprintf(fp, "[%d]", v->at(j)); - } - } - - map >::iterator mapItrDouble; - n = mapDoubleData.size(); - fprintf(fp, "\n mapDoubleData.. Total element = [%d]", n); - for (mapItrDouble = mapDoubleData.begin(); - mapItrDouble != mapDoubleData.end(); mapItrDouble++) { - string str = mapItrDouble->first; - vector* v = &(mapItrDouble->second); - fprintf(fp, "\n ParameterName = [%s] size = [%d]\n\t", str.c_str(), - (int)v->size()); - for (unsigned j = 0; j < v->size(); j++) { - fprintf(fp, "[%f]", v->at(j)); - } - } - fclose(fp); - } - return 1; -} - double cFeature::getDistance(string strName, double mean, double std, bool trace_check, double error_dist) { diff --git a/efel/cppcore/cfeature.h b/efel/cppcore/cfeature.h index 62713622..2d8c984d 100644 --- a/efel/cppcore/cfeature.h +++ b/efel/cppcore/cfeature.h @@ -51,7 +51,6 @@ class cFeature { const vector getMapData(const string& strName, const map>& mapData); const vector getmapIntData(string strName); const vector getmapDoubleData(string strName); - int getmapfptrVec(string strName, vector& vFptr); int calc_features(const string& name); template int getFeature(string strName, vector& vec); @@ -59,8 +58,6 @@ class cFeature { int setFeatureDouble(string strName, vector& DoubleVec); int setFeatureString(const string& key, const string& value); int getFeatureString(const string& key, string& value); - int printFeature(const char* strFileName); - int printMapMember(FILE* fp); string featuretype(string featurename); string getGError(); diff --git a/efel/cppcore/efel.cpp b/efel/cppcore/efel.cpp index b9e813c0..343cda88 100644 --- a/efel/cppcore/efel.cpp +++ b/efel/cppcore/efel.cpp @@ -16,7 +16,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include "efel.h" #include "cfeature.h" @@ -35,88 +34,8 @@ int Initialize(const char *strDepFile, const char *outdir) { } } -int FeaturePrint(const char *strFile) { - pFeature->printFeature(strFile); - return 1; -} -int setFeatureInt(const char *strName, int *A, unsigned nValue) { - vector v(nValue); - for (unsigned i = 0; i < nValue; i++) { - v[i] = A[i]; - } - pFeature->setFeatureInt(string(strName), v); - return 1; -} - -int setFeatureDouble(const char *strName, double *A, unsigned nValue) { - // printf("\nInside featureLibrary.. Before setdouble [%s = %f add = %d nVal= - // %d]\n", strName, A[0], pFeature, nValue); - vector v(nValue); - for (unsigned i = 0; i < nValue; i++) { - v[i] = A[i]; - } - // mapDoubleData.insert(pair > (string(strName), v)); - pFeature->setFeatureDouble(string(strName), v); - // printf("\nInside featureLibrary.. After setdouble [%s = %f]\n", strName, - // A[0]); - return 1; -} - -int getFeatureInt(const char *strName, int **A) { - vector vec; - if (pFeature->getFeature(string(strName), vec) < 0) { - return -1; - } - *A = new int[vec.size()]; - for (unsigned i = 0; i < vec.size(); i++) { - (*A)[i] = vec[i]; - } - return vec.size(); -} - -int getFeatureDouble(const char *strName, double **A) { - vector vec; - // printf("\nInside featureLibrary.. Before getdouble [%s ]\n", strName); - if (pFeature->getFeature(string(strName), vec) < 0) { - return -1; - } - *A = new double[vec.size()]; - for (unsigned i = 0; i < vec.size(); i++) { - (*A)[i] = vec[i]; - } - // printf("\nInside featureLibrary.. After getdouble [%s= %f ]\n", strName, - // (*A)[0]); - return vec.size(); -} - -int getFeatureString(const char *key, char *&value) { - string strvalue; - pFeature->getFeatureString(key, strvalue); - value = new char[strvalue.length() + 1]; - copy(strvalue.begin(), strvalue.end(), value); - value[strvalue.length()] = '\0'; - return 1; -} - -int setFeatureString(const char *key, const char *value) { - pFeature->setFeatureString(key, value); - return 1; -} - char *getgError() { string error = GErrorStr + pFeature->getGError(); GErrorStr.clear(); return (char *)error.c_str(); } - -double getDistance(const char *strName, double mean, double std, - bool trace_check) { - double value; - value = pFeature->getDistance(string(strName), mean, std, trace_check); - return value; -} - -int printFptr() { - printf("\n size of fptrlookup %d", (int)pFeature->fptrlookup.size()); - return 1; -} diff --git a/efel/cppcore/efel.h b/efel/cppcore/efel.h index e2801d70..941e8fbd 100644 --- a/efel/cppcore/efel.h +++ b/efel/cppcore/efel.h @@ -21,17 +21,6 @@ #define FEATURELIB_API extern "C" { FEATURELIB_API int Initialize(const char *strDepFile, const char *outdir); -FEATURELIB_API int setFeatureInt(const char *strName, int *A, unsigned nValue); -FEATURELIB_API int setFeatureDouble(const char *strName, double *A, unsigned nValue); -FEATURELIB_API int getTotalIntData(); -FEATURELIB_API int getTotalDoubleData(); -FEATURELIB_API int FeaturePrint(const char *strName); -FEATURELIB_API int getFeatureInt(const char *strName, int **A); -FEATURELIB_API int getFeatureDouble(const char *strName, double **A); -FEATURELIB_API int setFeatureString(const char *key, const char *value); -FEATURELIB_API int getFeatureString(const char *key, char **value); -FEATURELIB_API int printFptr(); FEATURELIB_API char *getgError(); -FEATURELIB_API double getDistance(const char *strName, double mean, double std, bool trace_check); } #endif From 9172cc718c3d80c498f3f058846d8084d506a82e Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 3 Nov 2023 18:30:29 +0100 Subject: [PATCH 18/85] merge efel into cppcore --- efel/cppcore/CMakeLists.txt | 4 ++-- efel/cppcore/cppcore.cpp | 27 +++++++++++++++++++++--- efel/cppcore/efel.cpp | 41 ------------------------------------- efel/cppcore/efel.h | 26 ----------------------- setup.py | 2 -- 5 files changed, 26 insertions(+), 74 deletions(-) delete mode 100644 efel/cppcore/efel.cpp delete mode 100644 efel/cppcore/efel.h diff --git a/efel/cppcore/CMakeLists.txt b/efel/cppcore/CMakeLists.txt index bbd8e61c..81ae4be5 100644 --- a/efel/cppcore/CMakeLists.txt +++ b/efel/cppcore/CMakeLists.txt @@ -25,7 +25,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_BUILD_TYPE Debug) set(FEATURESRCS Utils.cpp LibV1.cpp LibV2.cpp LibV3.cpp LibV5.cpp - FillFptrTable.cpp DependencyTree.cpp efel.cpp cfeature.cpp + FillFptrTable.cpp DependencyTree.cpp cfeature.cpp mapoperations.cpp) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") @@ -39,7 +39,7 @@ install(TARGETS efelStatic ARCHIVE DESTINATION lib) add_library(efel SHARED ${FEATURESRCS}) install(TARGETS efel LIBRARY DESTINATION lib) -install(FILES efel.h cfeature.h FillFptrTable.h LibV1.h LibV2.h LibV3.h +install(FILES cfeature.h FillFptrTable.h LibV1.h LibV2.h LibV3.h LibV5.h mapoperations.h Utils.h DependencyTree.h eFELLogger.h EfelExceptions.h types.h DESTINATION include) diff --git a/efel/cppcore/cppcore.cpp b/efel/cppcore/cppcore.cpp index 938a0646..e08e88c0 100644 --- a/efel/cppcore/cppcore.cpp +++ b/efel/cppcore/cppcore.cpp @@ -38,9 +38,22 @@ #include #include -#include -extern cFeature* pFeature; +cFeature *pFeature = NULL; + + +int Initialize(const char *strDepFile, const char *outdir) { + if (pFeature != NULL) { + delete pFeature; + } + + pFeature = new cFeature(string(strDepFile), string(outdir)); + if (pFeature == NULL) { + return -1; + } else { + return 1; + } +} static PyObject* CppCoreInitialize(PyObject* self, PyObject* args) { @@ -296,7 +309,15 @@ static PyObject* featuretype(PyObject* self, PyObject* args) { } static PyObject* getgerrorstr(PyObject* self, PyObject* args) { - return Py_BuildValue("s", pFeature->getGError().c_str()); + if (!pFeature) { + PyErr_SetString(PyExc_RuntimeError, "Feature system is not initialized."); + return NULL; + } + string errorStr = GErrorStr + pFeature->getGError(); + GErrorStr.clear(); + + + return Py_BuildValue("s", errorStr.c_str()); } static PyMethodDef CppCoreMethods[] = { diff --git a/efel/cppcore/efel.cpp b/efel/cppcore/efel.cpp deleted file mode 100644 index 343cda88..00000000 --- a/efel/cppcore/efel.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (c) 2015, EPFL/Blue Brain Project - * - * This file is part of eFEL - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "efel.h" -#include "cfeature.h" - -cFeature *pFeature = NULL; - -int Initialize(const char *strDepFile, const char *outdir) { - if (pFeature != NULL) { - delete pFeature; - } - - pFeature = new cFeature(string(strDepFile), string(outdir)); - if (pFeature == NULL) { - return -1; - } else { - return 1; - } -} - -char *getgError() { - string error = GErrorStr + pFeature->getGError(); - GErrorStr.clear(); - return (char *)error.c_str(); -} diff --git a/efel/cppcore/efel.h b/efel/cppcore/efel.h deleted file mode 100644 index 941e8fbd..00000000 --- a/efel/cppcore/efel.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (c) 2015, EPFL/Blue Brain Project - * - * This file is part of eFEL - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef __EFEL_H -#define __EFEL_H -#define FEATURELIB_API -extern "C" { -FEATURELIB_API int Initialize(const char *strDepFile, const char *outdir); -FEATURELIB_API char *getgError(); -} -#endif diff --git a/setup.py b/setup.py index 995b333b..8608ee12 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,6 @@ 'LibV5.cpp', 'FillFptrTable.cpp', 'DependencyTree.cpp', - 'efel.cpp', 'cfeature.cpp', 'mapoperations.cpp'] cppcore_headers = ['Utils.h', @@ -46,7 +45,6 @@ 'LibV5.h', 'FillFptrTable.h', 'DependencyTree.h', - 'efel.h', 'cfeature.h', 'Global.h', 'mapoperations.h', From 8ed52a883d9fff1d9341505d7f5f033febbf5dbf Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Mon, 6 Nov 2023 16:36:44 +0100 Subject: [PATCH 19/85] add template to getParam --- efel/cppcore/LibV1.cpp | 24 +++++++++---------- efel/cppcore/LibV5.cpp | 32 +++++++++++++------------- efel/cppcore/mapoperations.cpp | 42 +++++++++++++--------------------- efel/cppcore/mapoperations.h | 7 +++--- 4 files changed, 47 insertions(+), 58 deletions(-) diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index 25c1eee1..1342929a 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -56,7 +56,7 @@ int LibV1::interpolate(mapStr2intVec& IntFeatureData, retVal = getVec(DoubleFeatureData, StringData, "T", T); if (retVal <= 0) return -1; // interp_step is a stimulus independent parameter - retVal = getDoubleParam(DoubleFeatureData, "interp_step", InterpStepVec); + retVal = getParam(DoubleFeatureData, "interp_step", InterpStepVec); if (retVal <= 0) InterpStep = 0.1; else @@ -118,7 +118,7 @@ int LibV1::ISI_values(mapStr2intVec& IntFeatureData, int IgnoreFirstISI; vector retIgnore; - retVal = getIntParam(IntFeatureData, "ignore_first_ISI", retIgnore); + retVal = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); if ((retVal == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { IgnoreFirstISI = 0; } @@ -473,7 +473,7 @@ int LibV1::burst_ISI_indices(mapStr2intVec& IntFeatureData, } retVal = getVec(DoubleFeatureData, StringData, "ISI_values", ISIValues); if (retVal < 0) return -1; - retVal = getDoubleParam(DoubleFeatureData, "burst_factor", tVec); + retVal = getParam(DoubleFeatureData, "burst_factor", tVec); if (retVal < 0) BurstFactor = 2; else @@ -530,7 +530,7 @@ int LibV1::burst_mean_freq(mapStr2intVec& IntFeatureData, BurstIndex); if (retVal < 0) return -1; - retVal = getIntParam(IntFeatureData, "ignore_first_ISI", retIgnore); + retVal = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); if ((retVal == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { IgnoreFirstISI = 0; } @@ -613,7 +613,7 @@ int LibV1::interburst_voltage(mapStr2intVec& IntFeatureData, retVal = getVec(DoubleFeatureData, StringData, "V", V); if (retVal < 0) return -1; - retVal = getIntParam(IntFeatureData, "ignore_first_ISI", retIgnore); + retVal = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); if ((retVal == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { IgnoreFirstISI = 0; } @@ -697,16 +697,16 @@ int LibV1::adaptation_index(mapStr2intVec& IntFeatureData, if (retVal < 0) return -1; retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); if (retVal < 0) return -1; - retVal = getDoubleParam(DoubleFeatureData, "spike_skipf", spikeSkipf); + retVal = getParam(DoubleFeatureData, "spike_skipf", spikeSkipf); if (retVal < 0) return -1; // spikeSkipf is a fraction hence value should lie between >=0 and <1. [0 1) if ((spikeSkipf[0] < 0) || (spikeSkipf[0] >= 1)) { GErrorStr += "\nspike_skipf should lie between [0 1).\n"; return -1; } - retVal = getIntParam(IntFeatureData, "max_spike_skip", maxnSpike); + retVal = getParam(IntFeatureData, "max_spike_skip", maxnSpike); if (retVal < 0) return -1; - retVal = getDoubleParam(DoubleFeatureData, "offset", OffSetVec); + retVal = getParam(DoubleFeatureData, "offset", OffSetVec); if (retVal < 0) Offset = 0; else @@ -792,7 +792,7 @@ int LibV1::adaptation_index2(mapStr2intVec& IntFeatureData, }; vector OffSetVec; double Offset; - retval = getDoubleParam(DoubleFeatureData, "offset", OffSetVec); + retval = getParam(DoubleFeatureData, "offset", OffSetVec); if (retval < 0) Offset = 0; else @@ -1205,7 +1205,7 @@ int LibV1::ohmic_input_resistance(mapStr2intVec& IntFeatureData, "voltage_deflection", voltage_deflection); if (retVal < 0) return -1; vector stimulus_current; - retVal = getDoubleParam(DoubleFeatureData, "stimulus_current", + retVal = getParam(DoubleFeatureData, "stimulus_current", stimulus_current); if (retVal < 0) return -1; vector oir; @@ -1489,7 +1489,7 @@ int LibV1::AP_width(mapStr2intVec& IntFeatureData, retval = getVec(DoubleFeatureData, StringData, "V", v); if (retval < 0) return -1; vector threshold; - retval = getDoubleParam(DoubleFeatureData, "Threshold", threshold); + retval = getParam(DoubleFeatureData, "Threshold", threshold); if (retval < 0) return -1; vector stimstart; retval = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); @@ -1509,7 +1509,7 @@ int LibV1::AP_width(mapStr2intVec& IntFeatureData, if (retval < 0) return -1; bool strict_stiminterval; vector strict_stiminterval_vec; - retval = getIntParam(IntFeatureData, "strict_stiminterval", + retval = getParam(IntFeatureData, "strict_stiminterval", strict_stiminterval_vec); if (retval <= 0) { strict_stiminterval = false; diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 96687d5d..d06bd0cc 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -128,7 +128,7 @@ int LibV5::ISI_log_slope_skip(mapStr2intVec& IntFeatureData, 0) { return -1; } - retVal = getDoubleParam(DoubleFeatureData, "spike_skipf", spikeSkipf); + retVal = getParam(DoubleFeatureData, "spike_skipf", spikeSkipf); { if (retVal <= 0) return -1; }; @@ -137,7 +137,7 @@ int LibV5::ISI_log_slope_skip(mapStr2intVec& IntFeatureData, GErrorStr += "\nspike_skipf should lie between [0 1).\n"; return -1; } - retVal = getIntParam(IntFeatureData, "max_spike_skip", maxnSpike); + retVal = getParam(IntFeatureData, "max_spike_skip", maxnSpike); { if (retVal <= 0) return -1; }; @@ -418,7 +418,7 @@ int LibV5::min_AHP_indices(mapStr2intVec& IntFeatureData, } // Get strict_stiminterval - retVal = getIntParam(IntFeatureData, "strict_stiminterval", + retVal = getParam(IntFeatureData, "strict_stiminterval", strict_stiminterval_vec); if (retVal <= 0) { strict_stiminterval = false; @@ -682,7 +682,7 @@ int LibV5::AP_begin_indices(mapStr2intVec& IntFeatureData, // Get DerivativeThreshold vector dTh; - retVal = getDoubleParam(DoubleFeatureData, "DerivativeThreshold", dTh); + retVal = getParam(DoubleFeatureData, "DerivativeThreshold", dTh); if (retVal <= 0) { // derivative at peak start according to eCode specification 10mV/ms // according to Shaul 12mV/ms @@ -691,7 +691,7 @@ int LibV5::AP_begin_indices(mapStr2intVec& IntFeatureData, // Get DerivativeWindow vector derivative_window; - retVal = getIntParam(IntFeatureData, "DerivativeWindow", derivative_window); + retVal = getParam(IntFeatureData, "DerivativeWindow", derivative_window); if (retVal <= 0) { GErrorStr += "\nDerivativeWindow not set\n"; return -1; @@ -757,7 +757,7 @@ int LibV5::AP_end_indices(mapStr2intVec& IntFeatureData, // Get DerivativeThreshold vector dTh; - retVal = getDoubleParam(DoubleFeatureData, "DownDerivativeThreshold", dTh); + retVal = getParam(DoubleFeatureData, "DownDerivativeThreshold", dTh); if (retVal <= 0) { // derivative at peak end dTh.push_back(-12.0); @@ -833,7 +833,7 @@ int LibV5::number_initial_spikes(mapStr2intVec& IntFeatureData, retVal = getVec(DoubleFeatureData, StringData, "peak_time", peak_times); if (retVal < 0) return -1; - retVal = getDoubleParam(DoubleFeatureData, "initial_perc", initial_perc); + retVal = getParam(DoubleFeatureData, "initial_perc", initial_perc); if (retVal <= 0) return -1; if ((initial_perc[0] < 0) || (initial_perc[0] >= 1)) { GErrorStr += "\ninitial_perc should lie between [0 1).\n"; @@ -1879,7 +1879,7 @@ int LibV5::voltage_base(mapStr2intVec& IntFeatureData, vector precisionThreshold; - retVal = getDoubleParam(DoubleFeatureData, "precision_threshold", + retVal = getParam(DoubleFeatureData, "precision_threshold", precisionThreshold); if (retVal < 0) return -1; @@ -1954,7 +1954,7 @@ int LibV5::current_base(mapStr2intVec& IntFeatureData, vector precisionThreshold; - retVal = getDoubleParam(DoubleFeatureData, "precision_threshold", + retVal = getParam(DoubleFeatureData, "precision_threshold", precisionThreshold); if (retVal < 0) return -1; @@ -2309,7 +2309,7 @@ int LibV5::ohmic_input_resistance_vb_ssse(mapStr2intVec& IntFeatureData, voltage_deflection_vb_ssse); if (retVal <= 0) return -1; vector stimulus_current; - retVal = getDoubleParam(DoubleFeatureData, "stimulus_current", + retVal = getParam(DoubleFeatureData, "stimulus_current", stimulus_current); if (retVal <= 0) return -1; @@ -2490,12 +2490,12 @@ int LibV5::peak_indices(mapStr2intVec& IntFeatureData, return -1; } - retVal = getDoubleParam(DoubleFeatureData, "Threshold", threshold); + retVal = getParam(DoubleFeatureData, "Threshold", threshold); if (retVal <= 0) { return -1; } - retVal = getIntParam(IntFeatureData, "strict_stiminterval", + retVal = getParam(IntFeatureData, "strict_stiminterval", strict_stiminterval_vec); if (retVal <= 0) { strict_stiminterval = false; @@ -2852,7 +2852,7 @@ int LibV5::min_between_peaks_indices(mapStr2intVec& IntFeatureData, } // Get strict_stiminterval - retVal = getIntParam(IntFeatureData, "strict_stiminterval", + retVal = getParam(IntFeatureData, "strict_stiminterval", strict_stiminterval_vec); if (retVal <= 0) { strict_stiminterval = false; @@ -2941,7 +2941,7 @@ int LibV5::AP_width_between_threshold(mapStr2intVec& IntFeatureData, retval = getVec(DoubleFeatureData, StringData, "V", v); if (retval < 0) return -1; vector threshold; - retval = getDoubleParam(DoubleFeatureData, "Threshold", threshold); + retval = getParam(DoubleFeatureData, "Threshold", threshold); if (retval < 0) return -1; vector stimstart; retval = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); @@ -3029,13 +3029,13 @@ int LibV5::burst_begin_indices(mapStr2intVec& IntFeatureData, GErrorStr += "\nError: At least than 3 spikes are needed for burst calculation.\n"; return -1; } - retVal = getDoubleParam(DoubleFeatureData, "strict_burst_factor", tVec); + retVal = getParam(DoubleFeatureData, "strict_burst_factor", tVec); if (retVal < 0) burst_factor = 2; else burst_factor = tVec[0]; - retVal = getIntParam(IntFeatureData, "ignore_first_ISI", retIgnore); + retVal = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); if ((retVal == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { IgnoreFirstISI = 0; } diff --git a/efel/cppcore/mapoperations.cpp b/efel/cppcore/mapoperations.cpp index 19b46da8..ef8d064a 100644 --- a/efel/cppcore/mapoperations.cpp +++ b/efel/cppcore/mapoperations.cpp @@ -25,32 +25,18 @@ extern string GErrorStr; * get(Int|Double|Str)Param provides access to the Int, Double, Str map * */ -int getIntParam(mapStr2intVec& IntFeatureData, const string& param, - vector& vec) { - mapStr2intVec::iterator mapstr2IntItr(IntFeatureData.find(param)); - if (mapstr2IntItr == IntFeatureData.end()) { - GErrorStr += "Parameter [" + param + "] is missing in int map." - "In the python interface this can be set using the " - "setIntSetting() function\n"; - return -1; - } - vec = mapstr2IntItr->second; - return (vec.size()); -} - -int getDoubleParam(mapStr2doubleVec& DoubleFeatureData, const string& param, - vector& vec) { - mapStr2doubleVec::iterator mapstr2DoubleItr; - mapstr2DoubleItr = DoubleFeatureData.find(param); - if (mapstr2DoubleItr == DoubleFeatureData.end()) { - GErrorStr += "Parameter [" + param + - "] is missing in double map. " - "In the python interface this can be set using the " - "setDoubleSetting() function\n"; - return -1; - } - vec = mapstr2DoubleItr->second; - return (vec.size()); +template +int getParam(std::map>& featureData, + const std::string& param, std::vector& vec) { + auto itr = featureData.find(param); + if (itr == featureData.end()) { + GErrorStr += "Parameter [" + param + "] is missing in the map. " + "In the python interface, this can be set using the " + "appropriate setting function\n"; + return -1; + } + vec = itr->second; + return static_cast(vec.size()); } int getStrParam(mapStr2Str& StringData, const string& param, string& value) { @@ -100,6 +86,10 @@ int getVec(std::map >& FeatureData, mapStr2Str& Stri return (v.size()); } +template int getParam(std::map>& featureData, + const std::string& param, std::vector& vec); +template int getParam(std::map>& featureData, + const std::string& param, std::vector& vec); template void setVec(std::map >& FeatureData, mapStr2Str& StringData, string key, const vector& value); template void setVec(std::map >& FeatureData, mapStr2Str& StringData, diff --git a/efel/cppcore/mapoperations.h b/efel/cppcore/mapoperations.h index df76f780..26a6a670 100644 --- a/efel/cppcore/mapoperations.h +++ b/efel/cppcore/mapoperations.h @@ -30,10 +30,9 @@ using std::vector; extern string GErrorStr; -int getIntParam(mapStr2intVec& IntFeatureData, const string& param, - vector& vec); -int getDoubleParam(mapStr2doubleVec& DoubleFeatureData, const string& param, - vector& vec); +template +int getParam(std::map>& featureData, + const std::string& param, std::vector& vec); int getStrParam(mapStr2Str& StringData, const string& param, string& value); template void setVec(std::map >& FeatureData, mapStr2Str& StringData, From 786f6367d6da2df368b07339edcecbd7a0a3bcd6 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Mon, 6 Nov 2023 19:09:27 +0100 Subject: [PATCH 20/85] add getFeatures fn to get all dependent features --- efel/cppcore/cfeature.cpp | 18 +++++++++--------- efel/cppcore/cppcore.cpp | 6 +++++- efel/cppcore/mapoperations.cpp | 26 +++++++++++++++++++++++++- efel/cppcore/mapoperations.h | 5 +++++ 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 2738a897..9a580f69 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -24,7 +24,6 @@ #include -using std::cout; using std::endl; @@ -251,20 +250,13 @@ int cFeature::setFeatureInt(string strName, vector& v) { int cFeature::calc_features(const std::string& name) { // stimulus extension auto lookup_it = fptrlookup.find(name); - // print lookup_it - std::cout<<"lookup_it first: "<first<second) { - std::cout<& vec) { } else { // 2) If it's not in the map, compute. logger << "Going to calculate feature " << strName << " ..." << endl; - if (calc_features(strName) < 0) { + int retVal = 0; + try{ + retVal = calc_features(strName); + } + catch (const std::out_of_range& e) { + GErrorStr += e.what(); + return -1; + } + if (retVal < 0) { logger << "Failed to calculate feature " << strName << ": " << GErrorStr << endl; return -1; } diff --git a/efel/cppcore/cppcore.cpp b/efel/cppcore/cppcore.cpp index e08e88c0..c5529ca4 100644 --- a/efel/cppcore/cppcore.cpp +++ b/efel/cppcore/cppcore.cpp @@ -155,7 +155,11 @@ _getfeature(PyObject* self, PyObject* args, const string &input_type) { PyErr_SetString(PyExc_AssertionError, e.what()); return NULL; } - catch(const std::runtime_error& e) { + catch(const std::out_of_range& e) { // feature exists but its dependency is missing + PyErr_SetString(PyExc_KeyError, e.what()); + return NULL; + } + catch(const std::runtime_error& e) { // e.g. feature does not exist PyErr_SetString(PyExc_RuntimeError, e.what()); return NULL; } diff --git a/efel/cppcore/mapoperations.cpp b/efel/cppcore/mapoperations.cpp index ef8d064a..76c75a24 100644 --- a/efel/cppcore/mapoperations.cpp +++ b/efel/cppcore/mapoperations.cpp @@ -17,10 +17,28 @@ */ #include "mapoperations.h" -#include extern string GErrorStr; +template +std::map> getFeatures( + const std::map>& allFeatures, + const std::vector& requestedFeatures) { + + std::map> selectedFeatures; + for (const auto& featureKey : requestedFeatures) { + auto it = allFeatures.find(featureKey); + if (it != allFeatures.end() && !it->second.empty()) { + selectedFeatures.insert(*it); + } else { + // If the feature is not found or is empty, throw an exception + throw std::out_of_range("Feature " + featureKey + " not found or is empty"); + } + } + return selectedFeatures; +} + + /* * get(Int|Double|Str)Param provides access to the Int, Double, Str map * @@ -86,6 +104,12 @@ int getVec(std::map >& FeatureData, mapStr2Str& Stri return (v.size()); } +template std::map> getFeatures( + const std::map>& allFeatures, + const std::vector& requestedFeatures); +template std::map> getFeatures( + const std::map>& allFeatures, + const std::vector& requestedFeatures); template int getParam(std::map>& featureData, const std::string& param, std::vector& vec); template int getParam(std::map>& featureData, diff --git a/efel/cppcore/mapoperations.h b/efel/cppcore/mapoperations.h index 26a6a670..602f6b46 100644 --- a/efel/cppcore/mapoperations.h +++ b/efel/cppcore/mapoperations.h @@ -22,6 +22,7 @@ #include "types.h" +#include #include #include @@ -30,6 +31,10 @@ using std::vector; extern string GErrorStr; +template +std::map> getFeatures( + const std::map>& allFeatures, + const std::vector& requestedFeatures); template int getParam(std::map>& featureData, const std::string& param, std::vector& vec); From 6a80aeba014c08786304710109aa64af8a881c93 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Mon, 6 Nov 2023 19:11:30 +0100 Subject: [PATCH 21/85] LibV5.cpp update until time_to_last_spike --- efel/cppcore/LibV5.cpp | 106 ++++++++++++++--------------------------- tests/test_basic.py | 3 +- 2 files changed, 36 insertions(+), 73 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index d06bd0cc..51557851 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -80,17 +80,14 @@ static int __ISI_log_slope(const vector& isiValues, int LibV5::ISI_log_slope(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - vector isivalues; + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); + const auto& isivalues = doubleFeatures.at("ISI_values"); vector slope; - if (getVec(DoubleFeatureData, StringData, "ISI_values", isivalues) <= - 0) { - return -1; - } bool semilog = false; - int retval = __ISI_log_slope(isivalues, slope, false, 0, 0, semilog); + int retval = __ISI_log_slope(isivalues, slope, false, 0.0, 0, semilog); if (retval >= 0) { setVec(DoubleFeatureData, StringData, "ISI_log_slope", slope); - return slope.size(); + return static_cast(slope.size()); } else { return retval; } @@ -99,17 +96,14 @@ int LibV5::ISI_log_slope(mapStr2intVec& IntFeatureData, int LibV5::ISI_semilog_slope(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - vector isivalues; + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); + const auto& isivalues = doubleFeatures.at("ISI_values"); vector slope; - if (getVec(DoubleFeatureData, StringData, "ISI_values", isivalues) <= - 0) { - return -1; - } bool semilog = true; - int retval = __ISI_log_slope(isivalues, slope, false, 0, 0, semilog); + int retval = __ISI_log_slope(isivalues, slope, false, 0.0, 0, semilog); if (retval >= 0) { setVec(DoubleFeatureData, StringData, "ISI_semilog_slope", slope); - return slope.size(); + return static_cast(slope.size()); } else { return retval; } @@ -118,36 +112,26 @@ int LibV5::ISI_semilog_slope(mapStr2intVec& IntFeatureData, int LibV5::ISI_log_slope_skip(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector maxnSpike; - vector spikeSkipf; + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); + const auto doubleParams = getFeatures(DoubleFeatureData, {"spike_skipf"}); + const auto intParams = getFeatures(IntFeatureData, {"max_spike_skip"}); - vector isivalues; - vector slope; - if (getVec(DoubleFeatureData, StringData, "ISI_values", isivalues) <= - 0) { - return -1; - } - retVal = getParam(DoubleFeatureData, "spike_skipf", spikeSkipf); - { - if (retVal <= 0) return -1; - }; - // spikeSkipf is a fraction hence value should lie between >=0 and <1. [0 1) - if ((spikeSkipf[0] < 0) || (spikeSkipf[0] >= 1)) { + const auto& isivalues = doubleFeatures.at("ISI_values"); + const auto spikeSkipf = doubleParams.at("spike_skipf").front(); + const auto maxnSpike = intParams.at("max_spike_skip").front(); + + // Check the validity of spikeSkipf value + if (spikeSkipf < 0 || spikeSkipf >= 1) { GErrorStr += "\nspike_skipf should lie between [0 1).\n"; return -1; } - retVal = getParam(IntFeatureData, "max_spike_skip", maxnSpike); - { - if (retVal <= 0) return -1; - }; + vector slope; bool semilog = false; - retVal = __ISI_log_slope(isivalues, slope, true, spikeSkipf[0], maxnSpike[0], - semilog); + int retVal = __ISI_log_slope(isivalues, slope, true, spikeSkipf, maxnSpike, semilog); if (retVal >= 0) { setVec(DoubleFeatureData, StringData, "ISI_log_slope_skip", slope); - return slope.size(); + return static_cast(slope.size()); } else { return retVal; } @@ -157,49 +141,29 @@ int LibV5::ISI_log_slope_skip(mapStr2intVec& IntFeatureData, int LibV5::time_to_second_spike(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector second_spike; - vector peaktime; - vector stimstart; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", peaktime); - if (retVal < 2) { - GErrorStr += "\n Two spikes required for time_to_second_spike.\n"; - return -1; + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); + const auto& peaktime = doubleFeatures.at("peak_time"); + const auto& stimstart = doubleFeatures.at("stim_start"); + if (peaktime.size() < 2) { + GErrorStr += "\n Two spikes required for time_to_second_spike.\n"; + return -1; } - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retVal <= 0) return -1; - - second_spike.push_back(peaktime[1] - stimstart[0]); - setVec(DoubleFeatureData, StringData, "time_to_second_spike", - second_spike); - return second_spike.size(); + vector second_spike = {peaktime[1] - stimstart[0]}; + setVec(DoubleFeatureData, StringData, "time_to_second_spike", second_spike); + return 1; } // time from stimulus start to last spike int LibV5::time_to_last_spike(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); + const auto& peaktime = doubleFeatures.at("peak_time"); + const auto& stimstart = doubleFeatures.at("stim_start"); - vector last_spike; - vector peaktime; - vector stimstart; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", peaktime); - if (retVal < 0) { - GErrorStr += "\n Error in peak_time calculation in time_to_last_spike.\n"; - return -1; - } else if (retVal == 0) { - last_spike.push_back(0.0); - setVec(DoubleFeatureData, StringData, "time_to_last_spike", - last_spike); - } else { - retVal = - getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retVal <= 0) return -1; - last_spike.push_back(peaktime[peaktime.size() - 1] - stimstart[0]); - setVec(DoubleFeatureData, StringData, "time_to_last_spike", - last_spike); - } + vector last_spike = {peaktime.back() - stimstart[0]}; + + setVec(DoubleFeatureData, StringData, "time_to_last_spike", last_spike); return 1; } diff --git a/tests/test_basic.py b/tests/test_basic.py index 5ea54062..f5da13f9 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -298,7 +298,7 @@ def test_empty_trace(): for feature, value in \ efel.getFeatureValues([trace], features)[0].items(): - assert value[0] == 0.0 + assert value is None or value[0] == 0.0 def test_multiprocessing_traces(): @@ -1117,7 +1117,6 @@ def test_currentbase(): current_base = numpy.mean(current[numpy.where( (time >= 0.9 * stim_start) & (time <= stim_start))]) - # nt.set_trace() numpy.testing.assert_allclose(current_base, feature_values[0]['current_base'][0], rtol=0, atol=1e-8) From cf52d1db0520132514ca718c1fdba1df11cf0eae Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Mon, 6 Nov 2023 19:25:57 +0100 Subject: [PATCH 22/85] libv5 update ISI computations --- efel/cppcore/LibV5.cpp | 125 ++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 82 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 51557851..d38e7cfa 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -167,24 +167,24 @@ int LibV5::time_to_last_spike(mapStr2intVec& IntFeatureData, return 1; } +double calculateInvISI(const std::vector& all_isi_values_vec, size_t index) { + if (index < all_isi_values_vec.size()) { + return 1000.0 / all_isi_values_vec[index]; + } + return 0.0; +} + // 1.0 over first ISI (in Hz); returns 0 when no ISI int LibV5::inv_first_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector all_isi_values_vec; - double inv_first_ISI; - vector inv_first_ISI_vec; - retVal = getVec(DoubleFeatureData, StringData, "all_ISI_values", - all_isi_values_vec); - if (retVal < 1) { - inv_first_ISI = 0.0; - } else { - inv_first_ISI = 1000.0 / all_isi_values_vec[0]; - } - inv_first_ISI_vec.push_back(inv_first_ISI); - setVec(DoubleFeatureData, StringData, "inv_first_ISI", - inv_first_ISI_vec); + // Retrieve all_ISI_values using the getFeatures function + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); + const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); + + double inv_first_ISI = calculateInvISI(all_isi_values_vec, 0); // 0 for first ISI + vector inv_first_ISI_vec = {inv_first_ISI}; + setVec(DoubleFeatureData, StringData, "inv_first_ISI", inv_first_ISI_vec); return 1; } @@ -192,20 +192,12 @@ int LibV5::inv_first_ISI(mapStr2intVec& IntFeatureData, int LibV5::inv_second_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector all_isi_values_vec; - double inv_second_ISI; - vector inv_second_ISI_vec; - retVal = getVec(DoubleFeatureData, StringData, "all_ISI_values", - all_isi_values_vec); - if (retVal < 2) { - inv_second_ISI = 0.0; - } else { - inv_second_ISI = 1000.0 / all_isi_values_vec[1]; - } - inv_second_ISI_vec.push_back(inv_second_ISI); - setVec(DoubleFeatureData, StringData, "inv_second_ISI", - inv_second_ISI_vec); + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); + const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); + + double inv_second_ISI = calculateInvISI(all_isi_values_vec, 1); // 1 for second ISI + vector inv_second_ISI_vec = {inv_second_ISI}; + setVec(DoubleFeatureData, StringData, "inv_second_ISI", inv_second_ISI_vec); return 1; } @@ -213,20 +205,12 @@ int LibV5::inv_second_ISI(mapStr2intVec& IntFeatureData, int LibV5::inv_third_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector all_isi_values_vec; - double inv_third_ISI; - vector inv_third_ISI_vec; - retVal = getVec(DoubleFeatureData, StringData, "all_ISI_values", - all_isi_values_vec); - if (retVal < 3) { - inv_third_ISI = 0.0; - } else { - inv_third_ISI = 1000.0 / all_isi_values_vec[2]; - } - inv_third_ISI_vec.push_back(inv_third_ISI); - setVec(DoubleFeatureData, StringData, "inv_third_ISI", - inv_third_ISI_vec); + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); + const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); + + double inv_third_ISI = calculateInvISI(all_isi_values_vec, 2); // 2 for third ISI + vector inv_third_ISI_vec = {inv_third_ISI}; + setVec(DoubleFeatureData, StringData, "inv_third_ISI", inv_third_ISI_vec); return 1; } @@ -234,20 +218,12 @@ int LibV5::inv_third_ISI(mapStr2intVec& IntFeatureData, int LibV5::inv_fourth_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector all_isi_values_vec; - double inv_fourth_ISI; - vector inv_fourth_ISI_vec; - retVal = getVec(DoubleFeatureData, StringData, "all_ISI_values", - all_isi_values_vec); - if (retVal < 4) { - inv_fourth_ISI = 0.0; - } else { - inv_fourth_ISI = 1000.0 / all_isi_values_vec[3]; - } - inv_fourth_ISI_vec.push_back(inv_fourth_ISI); - setVec(DoubleFeatureData, StringData, "inv_fourth_ISI", - inv_fourth_ISI_vec); + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); + const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); + + double inv_fourth_ISI = calculateInvISI(all_isi_values_vec, 3); // 3 for fourth ISI + vector inv_fourth_ISI_vec = {inv_fourth_ISI}; + setVec(DoubleFeatureData, StringData, "inv_fourth_ISI", inv_fourth_ISI_vec); return 1; } @@ -255,20 +231,12 @@ int LibV5::inv_fourth_ISI(mapStr2intVec& IntFeatureData, int LibV5::inv_fifth_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector all_isi_values_vec; - double inv_fifth_ISI; - vector inv_fifth_ISI_vec; - retVal = getVec(DoubleFeatureData, StringData, "all_ISI_values", - all_isi_values_vec); - if (retVal < 5) { - inv_fifth_ISI = 0.0; - } else { - inv_fifth_ISI = 1000.0 / all_isi_values_vec[4]; - } - inv_fifth_ISI_vec.push_back(inv_fifth_ISI); - setVec(DoubleFeatureData, StringData, "inv_fifth_ISI", - inv_fifth_ISI_vec); + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); + const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); + + double inv_fifth_ISI = calculateInvISI(all_isi_values_vec, 4); // 4 for fifth ISI + vector inv_fifth_ISI_vec = {inv_fifth_ISI}; + setVec(DoubleFeatureData, StringData, "inv_fifth_ISI", inv_fifth_ISI_vec); return 1; } @@ -276,18 +244,11 @@ int LibV5::inv_fifth_ISI(mapStr2intVec& IntFeatureData, int LibV5::inv_last_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector all_isi_values_vec; - double inv_last_ISI; - vector inv_last_ISI_vec; - retVal = getVec(DoubleFeatureData, StringData, "all_ISI_values", - all_isi_values_vec); - if (retVal < 1) { - inv_last_ISI = 0.0; - } else { - inv_last_ISI = 1000.0 / all_isi_values_vec[all_isi_values_vec.size() - 1]; - } - inv_last_ISI_vec.push_back(inv_last_ISI); + const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); + const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); + + double inv_last_ISI = calculateInvISI(all_isi_values_vec, all_isi_values_vec.size() - 1); // Last ISI + vector inv_last_ISI_vec = {inv_last_ISI}; setVec(DoubleFeatureData, StringData, "inv_last_ISI", inv_last_ISI_vec); return 1; } From 1abfbac974f266c1ae00e2142d5aa3732a8bbb61 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Mon, 6 Nov 2023 19:53:04 +0100 Subject: [PATCH 23/85] LibV5 remove ISI first, second etc. duplication --- efel/cppcore/FillFptrTable.cpp | 20 ++++++--- efel/cppcore/LibV5.cpp | 82 ++++++++++------------------------ efel/cppcore/LibV5.h | 14 ++---- tests/test_cppcore.py | 1 - 4 files changed, 42 insertions(+), 75 deletions(-) diff --git a/efel/cppcore/FillFptrTable.cpp b/efel/cppcore/FillFptrTable.cpp index 7005f89b..9892f094 100644 --- a/efel/cppcore/FillFptrTable.cpp +++ b/efel/cppcore/FillFptrTable.cpp @@ -103,11 +103,21 @@ int FillFptrTable() { FptrTableV5["ISI_log_slope_skip"] = &LibV5::ISI_log_slope_skip; FptrTableV5["time_to_second_spike"] = &LibV5::time_to_second_spike; FptrTableV5["time_to_last_spike"] = &LibV5::time_to_last_spike; - FptrTableV5["inv_first_ISI"] = &LibV5::inv_first_ISI; - FptrTableV5["inv_second_ISI"] = &LibV5::inv_second_ISI; - FptrTableV5["inv_third_ISI"] = &LibV5::inv_third_ISI; - FptrTableV5["inv_fourth_ISI"] = &LibV5::inv_fourth_ISI; - FptrTableV5["inv_fifth_ISI"] = &LibV5::inv_fifth_ISI; + FptrTableV5["inv_first_ISI"] = [](mapStr2intVec& intData, mapStr2doubleVec& doubleData, mapStr2Str& strData) { + return LibV5::inv_ISI_generic(intData, doubleData, strData, 0); + }; + FptrTableV5["inv_second_ISI"] = [](mapStr2intVec& intData, mapStr2doubleVec& doubleData, mapStr2Str& strData) { + return LibV5::inv_ISI_generic(intData, doubleData, strData, 1); + }; + FptrTableV5["inv_third_ISI"] = [](mapStr2intVec& intData, mapStr2doubleVec& doubleData, mapStr2Str& strData) { + return LibV5::inv_ISI_generic(intData, doubleData, strData, 2); + }; + FptrTableV5["inv_fourth_ISI"] = [](mapStr2intVec& intData, mapStr2doubleVec& doubleData, mapStr2Str& strData) { + return LibV5::inv_ISI_generic(intData, doubleData, strData, 3); + }; + FptrTableV5["inv_fifth_ISI"] = [](mapStr2intVec& intData, mapStr2doubleVec& doubleData, mapStr2Str& strData) { + return LibV5::inv_ISI_generic(intData, doubleData, strData, 4); + }; FptrTableV5["inv_last_ISI"] = &LibV5::inv_last_ISI; FptrTableV5["inv_time_to_first_spike"] = &LibV5::inv_time_to_first_spike; FptrTableV5["min_AHP_indices"] = &LibV5::min_AHP_indices; diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index d38e7cfa..d623d2cf 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -174,69 +174,33 @@ double calculateInvISI(const std::vector& all_isi_values_vec, size_t ind return 0.0; } -// 1.0 over first ISI (in Hz); returns 0 when no ISI -int LibV5::inv_first_ISI(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - // Retrieve all_ISI_values using the getFeatures function - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); - const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); - - double inv_first_ISI = calculateInvISI(all_isi_values_vec, 0); // 0 for first ISI - vector inv_first_ISI_vec = {inv_first_ISI}; - setVec(DoubleFeatureData, StringData, "inv_first_ISI", inv_first_ISI_vec); - return 1; -} - -// 1.0 over second ISI (in Hz); returns 0 when no ISI -int LibV5::inv_second_ISI(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); - const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); - - double inv_second_ISI = calculateInvISI(all_isi_values_vec, 1); // 1 for second ISI - vector inv_second_ISI_vec = {inv_second_ISI}; - setVec(DoubleFeatureData, StringData, "inv_second_ISI", inv_second_ISI_vec); - return 1; -} - -// 1.0 over third ISI (in Hz); returns 0 when no ISI -int LibV5::inv_third_ISI(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); - const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); - - double inv_third_ISI = calculateInvISI(all_isi_values_vec, 2); // 2 for third ISI - vector inv_third_ISI_vec = {inv_third_ISI}; - setVec(DoubleFeatureData, StringData, "inv_third_ISI", inv_third_ISI_vec); - return 1; -} - -// 1.0 over fourth ISI (in Hz); returns 0 when no ISI -int LibV5::inv_fourth_ISI(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { +int LibV5::inv_ISI_generic(mapStr2intVec& IntFeatureData, + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData, + size_t index) { const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); - double inv_fourth_ISI = calculateInvISI(all_isi_values_vec, 3); // 3 for fourth ISI - vector inv_fourth_ISI_vec = {inv_fourth_ISI}; - setVec(DoubleFeatureData, StringData, "inv_fourth_ISI", inv_fourth_ISI_vec); - return 1; -} + double inv_ISI = calculateInvISI(all_isi_values_vec, index); + std::string featureName; + + switch (index) { + case 0: featureName = "inv_first_ISI"; break; + case 1: featureName = "inv_second_ISI"; break; + case 2: featureName = "inv_third_ISI"; break; + case 3: featureName = "inv_fourth_ISI"; break; + case 4: featureName = "inv_fifth_ISI"; break; + default: + if (index == all_isi_values_vec.size() - 1) { + featureName = "inv_last_ISI"; + } else { + featureName = "inv_" + std::to_string(index + 1) + "th_ISI"; + } + break; + } -// 1.0 over fifth ISI (in Hz); returns 0 when no ISI -int LibV5::inv_fifth_ISI(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); - const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); - - double inv_fifth_ISI = calculateInvISI(all_isi_values_vec, 4); // 4 for fifth ISI - vector inv_fifth_ISI_vec = {inv_fifth_ISI}; - setVec(DoubleFeatureData, StringData, "inv_fifth_ISI", inv_fifth_ISI_vec); + vector inv_ISI_vec = {inv_ISI}; + setVec(DoubleFeatureData, StringData, featureName, inv_ISI_vec); return 1; } diff --git a/efel/cppcore/LibV5.h b/efel/cppcore/LibV5.h index 3f7efaea..e2aff3cb 100644 --- a/efel/cppcore/LibV5.h +++ b/efel/cppcore/LibV5.h @@ -45,16 +45,10 @@ int time_to_last_spike(mapStr2intVec& IntFeatureData, int inv_time_to_first_spike(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int inv_first_ISI(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int inv_second_ISI(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int inv_third_ISI(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int inv_fourth_ISI(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int inv_fifth_ISI(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); +int inv_ISI_generic(mapStr2intVec& IntFeatureData, + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData, + size_t index); int inv_last_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); diff --git a/tests/test_cppcore.py b/tests/test_cppcore.py index 50199d04..1682cee4 100644 --- a/tests/test_cppcore.py +++ b/tests/test_cppcore.py @@ -200,7 +200,6 @@ def test_caching(self, feature_name): efel.cppcore.getFeature(feature_name, feature_values) with (Path(tempdir) / 'fllog.txt').open() as fd: contents = fd.read() - # breakpoint() # re-call efel's Initialize with current dir to remove pointer to tempdir. # this pointer was preventing the deletion of tempdir on windows. efel.cppcore.Initialize(efel.getDependencyFileLocation(), '.') From 32eb094f50b65164d3ff75e626b8598c0b37868b Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Mon, 6 Nov 2023 19:59:47 +0100 Subject: [PATCH 24/85] calculateInvISI throw except instead of return 0 --- efel/cppcore/LibV5.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index d623d2cf..e82a61d9 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -171,7 +171,7 @@ double calculateInvISI(const std::vector& all_isi_values_vec, size_t ind if (index < all_isi_values_vec.size()) { return 1000.0 / all_isi_values_vec[index]; } - return 0.0; + throw std::out_of_range("inverse ISI index out of range"); } int LibV5::inv_ISI_generic(mapStr2intVec& IntFeatureData, From 13c21f653d758da059a75f4fcaa4314427cfac33 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Mon, 6 Nov 2023 22:30:47 +0100 Subject: [PATCH 25/85] use getFeatures in depolarized_base --- efel/cppcore/LibV3.cpp | 44 +++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/efel/cppcore/LibV3.cpp b/efel/cppcore/LibV3.cpp index 3f878934..340e4af0 100644 --- a/efel/cppcore/LibV3.cpp +++ b/efel/cppcore/LibV3.cpp @@ -65,31 +65,23 @@ static int __depolarized_base(const vector& t, const vector& v, int LibV3::depolarized_base(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector t; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - vector stimstart; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retVal < 0) return -1; - vector stimend; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimend); - if (retVal < 0) return -1; - vector apendi; - retVal = getVec(IntFeatureData, StringData, "AP_end_indices", apendi); - if (retVal < 0) return -1; - vector apbi; - retVal = getVec(IntFeatureData, StringData, "AP_begin_indices", apbi); - if (retVal < 0) return -1; + // Retrieve all required double and int features at once + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "stim_start", "stim_end"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_end_indices", "AP_begin_indices"}); - vector dep_base; - retVal = __depolarized_base(t, v, stimstart[0], stimend[0], apbi, apendi, - dep_base); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "depolarized_base", dep_base); - } - return retVal; + vector dep_base; + int retVal = __depolarized_base( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + doubleFeatures.at("stim_start").front(), + doubleFeatures.at("stim_end").front(), + intFeatures.at("AP_begin_indices"), + intFeatures.at("AP_end_indices"), + dep_base + ); + + if (retVal >= 0) { + setVec(DoubleFeatureData, StringData, "depolarized_base", dep_base); + } + return retVal; } From 9ad88fd9278d3ee88ed1ff803eee181e0866f33b Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Mon, 6 Nov 2023 22:33:40 +0100 Subject: [PATCH 26/85] use getFeatures in steady_state_hyper --- efel/cppcore/LibV2.cpp | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/efel/cppcore/LibV2.cpp b/efel/cppcore/LibV2.cpp index a3ede731..acdb8ede 100644 --- a/efel/cppcore/LibV2.cpp +++ b/efel/cppcore/LibV2.cpp @@ -772,23 +772,21 @@ static int __steady_state_hyper(const vector& v, int LibV2::steady_state_hyper(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector v; - retval = getVec(DoubleFeatureData, StringData, "V", v); - if (retval < 0) return -1; - vector t; - retval = getVec(DoubleFeatureData, StringData, "T", t); - if (retval < 0) return -1; - vector stimend; - retval = getVec(DoubleFeatureData, StringData, "stim_end", stimend); - if (retval < 0) return -1; - vector steady_state_hyper; - retval = __steady_state_hyper(v, t, stimend[0], steady_state_hyper); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "steady_state_hyper", - steady_state_hyper); - } - return retval; + // Retrieve all required features at once + const auto& features = getFeatures(DoubleFeatureData, {"V", "T", "stim_end"}); + + vector steady_state_hyper; + int retval = __steady_state_hyper( + features.at("V"), + features.at("T"), + features.at("stim_end").front(), + steady_state_hyper + ); + + if (retval >= 0) { + setVec(DoubleFeatureData, StringData, "steady_state_hyper", steady_state_hyper); + } + return retval; } From 4de7876ff1e55df1ae4d1811bb7abcfa947cf0cb Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 7 Nov 2023 13:45:37 +0100 Subject: [PATCH 27/85] depolarized_based consider retVal==0 failure --- efel/cppcore/LibV3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efel/cppcore/LibV3.cpp b/efel/cppcore/LibV3.cpp index 340e4af0..5076fd1f 100644 --- a/efel/cppcore/LibV3.cpp +++ b/efel/cppcore/LibV3.cpp @@ -80,7 +80,7 @@ int LibV3::depolarized_base(mapStr2intVec& IntFeatureData, dep_base ); - if (retVal >= 0) { + if (retVal > 0) { setVec(DoubleFeatureData, StringData, "depolarized_base", dep_base); } return retVal; From 3c86f4e8ea642bbaf60fda64d0d21f1655006da3 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 7 Nov 2023 13:57:54 +0100 Subject: [PATCH 28/85] use getFeatures in LibV2 --- efel/cppcore/LibV2.cpp | 467 ++++++++++++++++------------------------- 1 file changed, 181 insertions(+), 286 deletions(-) diff --git a/efel/cppcore/LibV2.cpp b/efel/cppcore/LibV2.cpp index acdb8ede..23d54d53 100644 --- a/efel/cppcore/LibV2.cpp +++ b/efel/cppcore/LibV2.cpp @@ -55,22 +55,19 @@ static int __AP_rise_indices(const vector& v, const vector& apbi, int LibV2::AP_rise_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - vector apbi; - retVal = getVec(IntFeatureData, StringData, "AP_begin_indices", apbi); - if (retVal < 0) return -1; - vector pi; - retVal = getVec(IntFeatureData, StringData, "peak_indices", pi); - if (retVal < 0) return -1; - vector apri; - retVal = __AP_rise_indices(v, apbi, pi, apri); - if (retVal >= 0) { - setVec(IntFeatureData, StringData, "AP_rise_indices", apri); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "peak_indices"}); + vector apriseindices; + int retval = __AP_rise_indices( + doubleFeatures.at("V"), + intFeatures.at("AP_begin_indices"), + intFeatures.at("peak_indices"), + apriseindices + ); + if (retval > 0) { + setVec(IntFeatureData, StringData, "AP_rise_indices", apriseindices); + } + return retval; } // *** AP fall indices *** @@ -92,25 +89,20 @@ static int __AP_fall_indices(const vector& v, const vector& apbi, int LibV2::AP_fall_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - vector apbi; - retVal = getVec(IntFeatureData, StringData, "AP_begin_indices", apbi); - if (retVal < 0) return -1; - vector apei; - retVal = getVec(IntFeatureData, StringData, "AP_end_indices", apei); - if (retVal < 0) return -1; - vector pi; - retVal = getVec(IntFeatureData, StringData, "peak_indices", pi); - if (retVal < 0) return -1; - vector apfi; - retVal = __AP_fall_indices(v, apbi, apei, pi, apfi); - if (retVal >= 0) { - setVec(IntFeatureData, StringData, "AP_fall_indices", apfi); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "AP_end_indices", "peak_indices"}); + vector apfallindices; + int retval = __AP_fall_indices( + doubleFeatures.at("V"), + intFeatures.at("AP_begin_indices"), + intFeatures.at("AP_end_indices"), + intFeatures.at("peak_indices"), + apfallindices + ); + if (retval > 0) { + setVec(IntFeatureData, StringData, "AP_fall_indices", apfallindices); + } + return retval; } // eFeatures @@ -130,26 +122,22 @@ static int __AP_duration(const vector& t, int LibV2::AP_duration(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector t; - retval = getVec(DoubleFeatureData, StringData, "T", t); - if (retval < 0) return -1; - vector apbeginindices; - retval = getVec(IntFeatureData, StringData, "AP_begin_indices", - apbeginindices); - if (retval < 0) return -1; - vector endindices; - retval = getVec(IntFeatureData, StringData, "AP_end_indices", - endindices); - if (retval < 0) return -1; - vector apduration; - retval = __AP_duration(t, apbeginindices, endindices, apduration); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AP_duration", apduration); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "AP_end_indices"}); + + vector apduration; + int retval = __AP_duration( + doubleFeatures.at("T"), + intFeatures.at("AP_begin_indices"), + intFeatures.at("AP_end_indices"), + apduration + ); + + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_duration", apduration); + } + return retval; } -// end of AP_duration // *** AP_duration_half_width according to E8 and E16 *** static int __AP_duration_half_width(const vector& t, @@ -165,28 +153,22 @@ static int __AP_duration_half_width(const vector& t, int LibV2::AP_duration_half_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector t; - retval = getVec(DoubleFeatureData, StringData, "T", t); - if (retval < 0) return -1; - vector apriseindices; - retval = getVec(IntFeatureData, StringData, "AP_rise_indices", - apriseindices); - if (retval < 0) return -1; - vector apfallindices; - retval = getVec(IntFeatureData, StringData, "AP_fall_indices", - apfallindices); - if (retval < 0) return -1; + // Fetching all required features in one go. + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_rise_indices", "AP_fall_indices"}); + vector apdurationhalfwidth; - retval = __AP_duration_half_width(t, apriseindices, apfallindices, - apdurationhalfwidth); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AP_duration_half_width", - apdurationhalfwidth); + int retval = __AP_duration_half_width( + doubleFeatures.at("T"), + intFeatures.at("AP_rise_indices"), + intFeatures.at("AP_fall_indices"), + apdurationhalfwidth + ); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_duration_half_width", apdurationhalfwidth); } return retval; } -// end of AP_duration_half_width // *** AP_rise_time according to E9 and E17 *** static int __AP_rise_time(const vector& t, @@ -231,54 +213,27 @@ static int __AP_rise_time(const vector& t, int LibV2::AP_rise_time(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector t; - retval = getVec(DoubleFeatureData, StringData, "T", t); - if (retval < 0) return -1; - vector apbeginindices; - retval = getVec(IntFeatureData, StringData, "AP_begin_indices", - apbeginindices); - if (retval < 0) return -1; - vector peakindices; - retval = getVec(IntFeatureData, StringData, "peak_indices", - peakindices); - if (retval < 0) return -1; - vector v; - retval = getVec(DoubleFeatureData, StringData, "V", v); - if (retval < 0) return -1; - vector AP_amplitude; - retval = - getVec(DoubleFeatureData, StringData, "AP_amplitude", AP_amplitude); - if (retval < 0) { - GErrorStr += "Error calculating AP_amplitude for mean_AP_amplitude"; - return -1; - } else if (retval == 0) { - GErrorStr += "No spikes found when calculating mean_AP_amplitude"; - return -1; - } else if (AP_amplitude.size() == 0) { - GErrorStr += "No spikes found when calculating mean_AP_amplitude"; - return -1; - } - // Get rise begin percentage - vector risebeginperc; - retval = getVec(DoubleFeatureData, StringData, "rise_start_perc", risebeginperc); - if (retval <= 0) { - risebeginperc.push_back(0.0); - } - // Get rise end percentage - vector riseendperc; - retval = getVec(DoubleFeatureData, StringData, "rise_end_perc", riseendperc); - if (retval <= 0) { - riseendperc.push_back(1.0); - } + // Fetching all required features in one go. + const auto& doubleFeatures = getFeatures(DoubleFeatureData, + {"T", "V", "AP_amplitude", "rise_start_perc", "rise_end_perc"}); + const auto& intFeatures = getFeatures(IntFeatureData, + {"AP_begin_indices", "peak_indices"}); vector aprisetime; - retval = __AP_rise_time(t, v, apbeginindices, peakindices, AP_amplitude, risebeginperc[0], riseendperc[0], aprisetime); - if (retval >= 0) { + int retval = __AP_rise_time( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + intFeatures.at("AP_begin_indices"), + intFeatures.at("peak_indices"), + doubleFeatures.at("AP_amplitude"), + doubleFeatures.at("rise_start_perc").empty() ? 0.0 : doubleFeatures.at("rise_start_perc").front(), + doubleFeatures.at("rise_end_perc").empty() ? 1.0 : doubleFeatures.at("rise_end_perc").front(), + aprisetime + ); + if (retval > 0) { setVec(DoubleFeatureData, StringData, "AP_rise_time", aprisetime); } return retval; } -// end of AP_rise_time // *** AP_fall_time according to E10 and E18 *** static int __AP_fall_time(const vector& t, @@ -294,26 +249,21 @@ static int __AP_fall_time(const vector& t, int LibV2::AP_fall_time(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector t; - retval = getVec(DoubleFeatureData, StringData, "T", t); - if (retval < 0) return -1; - vector peakindices; - retval = getVec(IntFeatureData, StringData, "peak_indices", - peakindices); - if (retval < 0) return -1; - vector apendindices; - retval = getVec(IntFeatureData, StringData, "AP_end_indices", - apendindices); - if (retval < 0) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "AP_end_indices"}); + + const vector& t = doubleFeatures.at("T"); + const vector& peakindices = intFeatures.at("peak_indices"); + const vector& apendindices = intFeatures.at("AP_end_indices"); + vector apfalltime; - retval = __AP_fall_time(t, peakindices, apendindices, apfalltime); - if (retval >= 0) { + int retval = __AP_fall_time(t, peakindices, apendindices, apfalltime); + + if (retval > 0) { setVec(DoubleFeatureData, StringData, "AP_fall_time", apfalltime); - } + } return retval; } -// end of AP_fall_time // *** AP_rise_rate according to E11 and E19 *** static int __AP_rise_rate(const vector& t, const vector& v, @@ -330,26 +280,19 @@ static int __AP_rise_rate(const vector& t, const vector& v, int LibV2::AP_rise_rate(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector t; - retval = getVec(DoubleFeatureData, StringData, "T", t); - if (retval < 0) return -1; - vector v; - retval = getVec(DoubleFeatureData, StringData, "V", v); - if (retval < 0) return -1; - vector apbeginindices; - retval = getVec(IntFeatureData, StringData, "AP_begin_indices", - apbeginindices); - if (retval < 0) return -1; - vector peakindices; - retval = getVec(IntFeatureData, StringData, "peak_indices", - peakindices); - if (retval < 0) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "peak_indices"}); + + const vector& t = doubleFeatures.at("T"); + const vector& v = doubleFeatures.at("V"); + const vector& apbeginindices = intFeatures.at("AP_begin_indices"); + const vector& peakindices = intFeatures.at("peak_indices"); + vector apriserate; - retval = __AP_rise_rate(t, v, apbeginindices, peakindices, apriserate); - if (retval >= 0) { + int retval = __AP_rise_rate(t, v, apbeginindices, peakindices, apriserate); + if (retval > 0) { setVec(DoubleFeatureData, StringData, "AP_rise_rate", apriserate); - } + } return retval; } // end of AP_rise_rate @@ -369,28 +312,22 @@ static int __AP_fall_rate(const vector& t, const vector& v, int LibV2::AP_fall_rate(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector t; - retval = getVec(DoubleFeatureData, StringData, "T", t); - if (retval < 0) return -1; - vector v; - retval = getVec(DoubleFeatureData, StringData, "V", v); - if (retval < 0) return -1; - vector peakindices; - retval = getVec(IntFeatureData, StringData, "peak_indices", peakindices); - if (retval < 0) return -1; - vector apendindices; - retval = getVec(IntFeatureData, StringData, "AP_end_indices", - apendindices); - if (retval < 0) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "AP_end_indices"}); + + const vector& t = doubleFeatures.at("T"); + const vector& v = doubleFeatures.at("V"); + const vector& peakindices = intFeatures.at("peak_indices"); + const vector& apendindices = intFeatures.at("AP_end_indices"); + vector apfallrate; - retval = __AP_fall_rate(t, v, peakindices, apendindices, apfallrate); - if (retval >= 0) { + int retval = __AP_fall_rate(t, v, peakindices, apendindices, apfallrate); + + if (retval > 0) { setVec(DoubleFeatureData, StringData, "AP_fall_rate", apfallrate); } return retval; } -// end of AP_fall_rate // *** fast_AHP according to E13 and E21 *** static int __fast_AHP(const vector& v, @@ -409,26 +346,21 @@ static int __fast_AHP(const vector& v, int LibV2::fast_AHP(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector v; - retval = getVec(DoubleFeatureData, StringData, "V", v); - if (retval < 0) return -1; - vector apbeginindices; - retval = getVec(IntFeatureData, StringData, "AP_begin_indices", - apbeginindices); - if (retval < 0) return -1; - vector minahpindices; - retval = getVec(IntFeatureData, StringData, "min_AHP_indices", - minahpindices); - if (retval < 0) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "min_AHP_indices"}); + + const vector& v = doubleFeatures.at("V"); + const vector& apbeginindices = intFeatures.at("AP_begin_indices"); + const vector& minahpindices = intFeatures.at("min_AHP_indices"); + vector fastahp; - retval = __fast_AHP(v, apbeginindices, minahpindices, fastahp); - if (retval >= 0) { + int retval = __fast_AHP(v, apbeginindices, minahpindices, fastahp); + + if (retval > 0) { setVec(DoubleFeatureData, StringData, "fast_AHP", fastahp); } return retval; } -// end of fast_AHP // *** AP_amplitude_change according to E22 *** static int __AP_amplitude_change(const vector& apamplitude, @@ -446,20 +378,17 @@ static int __AP_amplitude_change(const vector& apamplitude, int LibV2::AP_amplitude_change(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector apamplitude; - retval = getVec(DoubleFeatureData, StringData, "AP_amplitude", - apamplitude); - if (retval < 0) return -1; + const auto& features = getFeatures(DoubleFeatureData, {"AP_amplitude"}); + const vector& apamplitude = features.at("AP_amplitude"); + vector apamplitudechange; - retval = __AP_amplitude_change(apamplitude, apamplitudechange); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AP_amplitude_change", - apamplitudechange); + int retval = __AP_amplitude_change(apamplitude, apamplitudechange); + + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_amplitude_change", apamplitudechange); } return retval; } -// end of AP_amplitude_change // *** AP_duration_change according to E23 *** static int __AP_duration_change(const vector& apduration, @@ -476,16 +405,13 @@ static int __AP_duration_change(const vector& apduration, int LibV2::AP_duration_change(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector apduration; - retval = getVec(DoubleFeatureData, StringData, "AP_duration", - apduration); - if (retval < 0) return -1; + const auto& features = getFeatures(DoubleFeatureData, {"AP_duration"}); + const vector& apduration = features.at("AP_duration"); + vector apdurationchange; - retval = __AP_duration_change(apduration, apdurationchange); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AP_duration_change", - apdurationchange); + int retval = __AP_duration_change(apduration, apdurationchange); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_duration_change", apdurationchange); } return retval; } @@ -509,17 +435,12 @@ static int __AP_duration_half_width_change( int LibV2::AP_duration_half_width_change(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector apdurationhalfwidth; - retval = getVec(DoubleFeatureData, StringData, - "AP_duration_half_width", apdurationhalfwidth); - if (retval < 0) return -1; + const auto& features = getFeatures(DoubleFeatureData, {"AP_duration_half_width"}); + const vector& apdurationhalfwidth = features.at("AP_duration_half_width"); vector apdurationhalfwidthchange; - retval = __AP_duration_half_width_change(apdurationhalfwidth, - apdurationhalfwidthchange); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AP_duration_half_width_change", - apdurationhalfwidthchange); + int retval = __AP_duration_half_width_change(apdurationhalfwidth, apdurationhalfwidthchange); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_duration_half_width_change", apdurationhalfwidthchange); } return retval; } @@ -541,16 +462,12 @@ static int __AP_rise_rate_change(const vector& apriserate, int LibV2::AP_rise_rate_change(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector apriserate; - retval = getVec(DoubleFeatureData, StringData, "AP_rise_rate", - apriserate); - if (retval < 0) return -1; + const auto& features = getFeatures(DoubleFeatureData, {"AP_rise_rate"}); + const vector& apriserate = features.at("AP_rise_rate"); vector apriseratechange; - retval = __AP_rise_rate_change(apriserate, apriseratechange); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AP_rise_rate_change", - apriseratechange); + int retval = __AP_rise_rate_change(apriserate, apriseratechange); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_rise_rate_change", apriseratechange); } return retval; } @@ -571,20 +488,15 @@ static int __AP_fall_rate_change(const vector& apfallrate, int LibV2::AP_fall_rate_change(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector apfallrate; - retval = getVec(DoubleFeatureData, StringData, "AP_fall_rate", - apfallrate); - if (retval < 0) return -1; + const auto& features = getFeatures(DoubleFeatureData, {"AP_fall_rate"}); + const vector& apfallrate = features.at("AP_fall_rate"); vector apfallratechange; - retval = __AP_fall_rate_change(apfallrate, apfallratechange); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AP_fall_rate_change", - apfallratechange); + int retval = __AP_fall_rate_change(apfallrate, apfallratechange); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_fall_rate_change", apfallratechange); } return retval; } -// end of AP_fall_rate_change // *** fast_AHP_change according to E27 *** static int __fast_AHP_change(const vector& fastahp, @@ -601,15 +513,12 @@ static int __fast_AHP_change(const vector& fastahp, int LibV2::fast_AHP_change(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector fastahp; - retval = getVec(DoubleFeatureData, StringData, "fast_AHP", fastahp); - if (retval < 0) return -1; + const auto& features = getFeatures(DoubleFeatureData, {"fast_AHP"}); + const vector& fastahp = features.at("fast_AHP"); vector fastahpchange; - retval = __fast_AHP_change(fastahp, fastahpchange); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "fast_AHP_change", - fastahpchange); + int retval = __fast_AHP_change(fastahp, fastahpchange); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "fast_AHP_change", fastahpchange); } return retval; } @@ -624,24 +533,20 @@ static int __amp_drop_first_second(const vector& peakvoltage, int LibV2::amp_drop_first_second(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector peakvoltage; - retval = getVec(DoubleFeatureData, StringData, "peak_voltage", - peakvoltage); - if (retval < 2) { - GErrorStr += - "At least 2 spikes needed for calculation of amp_drop_first_second.\n"; + const auto& features = getFeatures(DoubleFeatureData, {"peak_voltage"}); + const vector peakvoltage = features.at("peak_voltage"); + + if (peakvoltage.size() < 2) { + GErrorStr += "At least 2 spikes needed for calculation of amp_drop_first_second.\n"; return -1; } vector ampdropfirstsecond; - retval = __amp_drop_first_second(peakvoltage, ampdropfirstsecond); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "amp_drop_first_second", - ampdropfirstsecond); + int retval = __amp_drop_first_second(peakvoltage, ampdropfirstsecond); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "amp_drop_first_second", ampdropfirstsecond); } return retval; } -// end of amp_drop_first_second // *** amp_drop_first_last *** static int __amp_drop_first_last(const vector& peakvoltage, @@ -652,20 +557,17 @@ static int __amp_drop_first_last(const vector& peakvoltage, int LibV2::amp_drop_first_last(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector peakvoltage; - retval = getVec(DoubleFeatureData, StringData, "peak_voltage", - peakvoltage); - if (retval < 2) { - GErrorStr += - "At least 2 spikes needed for calculation of amp_drop_first_last.\n"; + const auto& peakVoltageFeature = getFeatures(DoubleFeatureData, {"peak_voltage"}); + const vector peakvoltage = peakVoltageFeature.at("peak_voltage"); + + if (peakvoltage.size() < 2) { + GErrorStr += "At least 2 spikes needed for calculation of amp_drop_first_last.\n"; return -1; } vector ampdropfirstlast; - retval = __amp_drop_first_last(peakvoltage, ampdropfirstlast); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "amp_drop_first_last", - ampdropfirstlast); + int retval = __amp_drop_first_last(peakvoltage, ampdropfirstlast); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "amp_drop_first_last", ampdropfirstlast); } return retval; } @@ -680,24 +582,20 @@ static int __amp_drop_second_last(const vector& peakvoltage, int LibV2::amp_drop_second_last(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector peakvoltage; - retval = getVec(DoubleFeatureData, StringData, "peak_voltage", - peakvoltage); - if (retval < 3) { - GErrorStr += - "At least 3 spikes needed for calculation of amp_drop_second_last.\n"; + const auto& peakVoltageFeatures = getFeatures(DoubleFeatureData, {"peak_voltage"}); + const vector& peakvoltage = peakVoltageFeatures.at("peak_voltage"); + // Ensure there are at least 3 spikes for calculation + if (peakvoltage.size() < 3) { + GErrorStr += "At least 3 spikes needed for calculation of amp_drop_second_last.\n"; return -1; } vector ampdropsecondlast; - retval = __amp_drop_second_last(peakvoltage, ampdropsecondlast); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "amp_drop_second_last", - ampdropsecondlast); + int retval = __amp_drop_second_last(peakvoltage, ampdropsecondlast); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "amp_drop_second_last", ampdropsecondlast); } return retval; } -// end of amp_drop_second_last // *** max_amp_difference *** static int __max_amp_difference(const vector& peakvoltage, @@ -718,24 +616,21 @@ static int __max_amp_difference(const vector& peakvoltage, int LibV2::max_amp_difference(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector peakvoltage; - retval = getVec(DoubleFeatureData, StringData, "peak_voltage", - peakvoltage); - if (retval < 2) { - GErrorStr += - "At least 2 spikes needed for calculation of max_amp_difference.\n"; - return -1; + const auto& features = getFeatures(DoubleFeatureData, {"peak_voltage"}); + + // Ensure there are at least 2 spikes for calculation + if (features.at("peak_voltage").size() < 2) { + GErrorStr += "At least 2 spikes needed for calculation of max_amp_difference.\n"; + return -1; } vector maxampdifference; - retval = __max_amp_difference(peakvoltage, maxampdifference); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "max_amp_difference", - maxampdifference); + int retval = __max_amp_difference(features.at("peak_voltage"), maxampdifference); + + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "max_amp_difference", maxampdifference); } return retval; } -// end of max_amp_difference // steady state of the voltage response during hyperpolarizing stimulus, // elementary feature for E29 @@ -783,7 +678,7 @@ int LibV2::steady_state_hyper(mapStr2intVec& IntFeatureData, steady_state_hyper ); - if (retval >= 0) { + if (retval > 0) { setVec(DoubleFeatureData, StringData, "steady_state_hyper", steady_state_hyper); } return retval; From 4d36018b90b2d6ec9554bbf6c86ad4ed7dee4264 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 7 Nov 2023 18:03:09 +0100 Subject: [PATCH 29/85] use getFeatures in LibV1 --- efel/cppcore/LibV1.cpp | 1162 +++++++++++++-------------------- efel/cppcore/LibV1.h | 3 - efel/pyfeatures/pyfeatures.py | 10 +- tests/test_basic.py | 2 + 4 files changed, 449 insertions(+), 728 deletions(-) diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index 1342929a..082d7731 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -107,29 +107,23 @@ int LibV1::Spikecount(mapStr2intVec& IntFeatureData, int LibV1::ISI_values(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); + if (doubleFeatures.at("peak_time").size() < 3) { + GErrorStr += "\n Three spikes required for calculation of ISI_values.\n"; + return -1; + } - vector VecISI, pvTime; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", pvTime); - if (retVal < 3) { - GErrorStr += "\n Three spikes required for calculation of ISI_values.\n"; - return -1; - } + const auto& intFeatures = getFeatures(IntFeatureData, {"ignore_first_ISI"}); + int IgnoreFirstISI = 1; + if (intFeatures.at("ignore_first_ISI").size() > 0 && intFeatures.at("ignore_first_ISI")[0] == 0) { + IgnoreFirstISI = 0; + } - int IgnoreFirstISI; - vector retIgnore; - retVal = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); - if ((retVal == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { - IgnoreFirstISI = 0; - } - else { - IgnoreFirstISI = 1; - } - - for (size_t i = IgnoreFirstISI + 1; i < pvTime.size(); i++) - VecISI.push_back(pvTime[i] - pvTime[i - 1]); - setVec(DoubleFeatureData, StringData, "ISI_values", VecISI); - return VecISI.size(); + vector VecISI; + for (size_t i = IgnoreFirstISI + 1; i < doubleFeatures.at("peak_time").size(); i++) + VecISI.push_back(doubleFeatures.at("peak_time")[i] - doubleFeatures.at("peak_time")[i - 1]); + setVec(DoubleFeatureData, StringData, "ISI_values", VecISI); + return VecISI.size(); } // *** ISI_CV *** @@ -154,205 +148,115 @@ static int __ISI_CV(const vector& isivalues, vector& isicv) { } int LibV1::ISI_CV(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - - vector isivalues; - retval = getVec(DoubleFeatureData, StringData, "ISI_values", - isivalues); - if (retval < 2) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); + if (doubleFeatures.at("ISI_values").size() < 2) return -1; - vector isicv; - retval = __ISI_CV(isivalues, isicv); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "ISI_CV", isicv); - } - return retval; + vector isicv; + int retval = __ISI_CV(doubleFeatures.at("ISI_values"), isicv); + if (retval >= 0) { + setVec(DoubleFeatureData, StringData, "ISI_CV", isicv); + } + return retval; } -// end of ISI_CV int LibV1::peak_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - // vector PeakI = getVec(IntFeatureData, StringData, - // string("peak_indices")); - vector PeakI; - vector V, peakV; - - retVal = getVec(IntFeatureData, StringData, "peak_indices", PeakI); - if (retVal <= 0) return -1; - - retVal = getVec(DoubleFeatureData, StringData, "V", V); - if (retVal <= 0) return -1; - - for (size_t i = 0; i < PeakI.size(); i++) { - peakV.push_back(V[PeakI[i]]); - } - setVec(DoubleFeatureData, StringData, "peak_voltage", peakV); - return peakV.size(); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); + vector peakV; + for (const auto& index : intFeatures.at("peak_indices")) { + peakV.push_back(doubleFeatures.at("V")[index]); + } + setVec(DoubleFeatureData, StringData, "peak_voltage", peakV); + return peakV.size(); } int LibV1::firing_rate(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - // printf("\n LibV1 This is inside firing_rate()"); - int retVal; - - vector stimStart, stimEnd, peakVTime, firing_rate; - double lastAPTime = 0.; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", peakVTime); - if (retVal <= 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal <= 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal <= 0) return -1; - - int nCount = 0; - for (size_t i = 0; i < peakVTime.size(); i++) { - if ((peakVTime[i] >= stimStart[0]) && (peakVTime[i] <= stimEnd[0])) { - lastAPTime = peakVTime[i]; - nCount++; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end"}); + double lastAPTime = 0.; + int nCount = 0; + for (const auto& time : doubleFeatures.at("peak_time")) { + if ((time >= doubleFeatures.at("stim_start")[0]) && (time <= doubleFeatures.at("stim_end")[0])) { + lastAPTime = time; + nCount++; + } } - } - if (lastAPTime == stimStart[0]) { - GErrorStr += "\nPrevent divide by zero.\n"; - return -1; - } - firing_rate.push_back(nCount * 1000 / (lastAPTime - stimStart[0])); - setVec(DoubleFeatureData, StringData, "mean_frequency", firing_rate); - return firing_rate.size(); + if (lastAPTime == doubleFeatures.at("stim_start")[0]) { + GErrorStr += "\nPrevent divide by zero.\n"; + return -1; + } + vector firing_rate; + firing_rate.push_back(nCount * 1000 / (lastAPTime - doubleFeatures.at("stim_start")[0])); + setVec(DoubleFeatureData, StringData, "mean_frequency", firing_rate); + return firing_rate.size(); } int LibV1::peak_time(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector PeakI; - vector T, pvTime; - retVal = getVec(IntFeatureData, StringData, "peak_indices", PeakI); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", T); - if (retVal < 0) return -1; - for (size_t i = 0; i < PeakI.size(); i++) { - pvTime.push_back(T[PeakI[i]]); - } - setVec(DoubleFeatureData, StringData, "peak_time", pvTime); - return pvTime.size(); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); + vector pvTime; + for (const auto& index : intFeatures.at("peak_indices")) { + pvTime.push_back(doubleFeatures.at("T")[index]); + } + setVec(DoubleFeatureData, StringData, "peak_time", pvTime); + return pvTime.size(); } // time from stimulus start to first threshold crossing int LibV1::first_spike_time(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector first_spike; - vector peaktime; - vector stimstart; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", peaktime); - if (retVal < 1) { - GErrorStr += "\n One spike required for time_to_first_spike.\n"; - return -1; - } - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retVal <= 0) return -1; - first_spike.push_back(peaktime[0] - stimstart[0]); - setVec(DoubleFeatureData, StringData, "time_to_first_spike", - first_spike); - return first_spike.size(); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); + if (doubleFeatures.at("peak_time").size() < 1) { + GErrorStr += "\n One spike required for time_to_first_spike.\n"; + return -1; + } + vector first_spike; + first_spike.push_back(doubleFeatures.at("peak_time")[0] - doubleFeatures.at("stim_start")[0]); + setVec(DoubleFeatureData, StringData, "time_to_first_spike", first_spike); + return first_spike.size(); } int LibV1::AP_height(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector vPeak; - retVal = getVec(DoubleFeatureData, StringData, "peak_voltage", vPeak); - if (retVal <= 0) return -1; - setVec(DoubleFeatureData, StringData, "AP_height", vPeak); - - return vPeak.size(); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_voltage"}); + setVec(DoubleFeatureData, StringData, "AP_height", doubleFeatures.at("peak_voltage")); + return doubleFeatures.at("peak_voltage").size(); } // spike amplitude: peak_voltage - v[AP_begin_indices] int LibV1::AP_amplitude(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector peakvoltage; - vector peaktime; - vector apbeginindices; - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal <= 0) { - GErrorStr += "AP_amplitude: Can't find voltage vector V"; - return -1; - } - - vector stimstart; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retVal != 1) { - GErrorStr += "AP_amplitude: Error getting stim_start"; - return -1; - } - - vector stimend; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimend); - if (retVal != 1) { - GErrorStr += "AP_amplitude: Error getting stim_end"; - return -1; - } - - retVal = getVec(DoubleFeatureData, StringData, "peak_voltage", - peakvoltage); - if (retVal <= 0) { - GErrorStr += "AP_amplitude: Error calculating peak_voltage"; - return -1; - } - - retVal = getVec(DoubleFeatureData, StringData, "peak_time", peaktime); - if (retVal <= 0) { - GErrorStr += "AP_amplitude: Error calculating peak_time"; - return -1; - } - - retVal = getVec(IntFeatureData, StringData, "AP_begin_indices", - apbeginindices); - if (retVal <= 0) { - GErrorStr += "AP_amplitude: Error calculating AP_begin_indicies"; - return -1; - } - - if (peakvoltage.size() != peaktime.size()) { - GErrorStr += "AP_amplitude: Not the same amount of peak_time and " - "peak_voltage entries"; - return -1; - } - - vector peakvoltage_duringstim; - for (size_t i = 0; i < peaktime.size(); i++) { - if (peaktime[i] >= stimstart[0] && peaktime[i] <= stimend[0]) { - peakvoltage_duringstim.push_back(peakvoltage[i]); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "stim_start", "stim_end", "peak_voltage", "peak_time"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices"}); + if (doubleFeatures.at("peak_voltage").size() != doubleFeatures.at("peak_time").size()) { + GErrorStr += "AP_amplitude: Not the same amount of peak_time and peak_voltage entries"; + return -1; } - } - - if (peakvoltage_duringstim.size() > apbeginindices.size()) { - GErrorStr += "AP_amplitude: More peak_voltage entries during the stimulus " - "than AP_begin_indices entries"; - return -1; - } - - vector apamplitude; - apamplitude.resize(peakvoltage_duringstim.size()); - for (size_t i = 0; i < apamplitude.size(); i++) { - apamplitude[i] = peakvoltage_duringstim[i] - v[apbeginindices[i]]; - } - setVec(DoubleFeatureData, StringData, "AP_amplitude", apamplitude); - return apamplitude.size(); + vector peakvoltage_duringstim; + for (size_t i = 0; i < doubleFeatures.at("peak_time").size(); i++) { + if (doubleFeatures.at("peak_time")[i] >= doubleFeatures.at("stim_start")[0] && doubleFeatures.at("peak_time")[i] <= doubleFeatures.at("stim_end")[0]) { + peakvoltage_duringstim.push_back(doubleFeatures.at("peak_voltage")[i]); + } + } + if (peakvoltage_duringstim.size() > intFeatures.at("AP_begin_indices").size()) { + GErrorStr += "AP_amplitude: More peak_voltage entries during the stimulus than AP_begin_indices entries"; + return -1; + } + vector apamplitude; + apamplitude.resize(peakvoltage_duringstim.size()); + for (size_t i = 0; i < apamplitude.size(); i++) { + apamplitude[i] = peakvoltage_duringstim[i] - doubleFeatures.at("V")[intFeatures.at("AP_begin_indices")[i]]; + } + setVec(DoubleFeatureData, StringData, "AP_amplitude", apamplitude); + return apamplitude.size(); } // *** AHP_depth_abs_slow *** @@ -384,43 +288,33 @@ static int __AHP_depth_abs_slow_indices(const vector& t, int LibV1::AHP_depth_abs_slow(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - - vector t; - retval = getVec(DoubleFeatureData, StringData, "T", t); - if (retval < 0) return -1; - vector v; - retval = getVec(DoubleFeatureData, StringData, "V", v); - if (retval < 0) return -1; - vector peakindices; - retval = getVec(IntFeatureData, StringData, "peak_indices", peakindices); - if (retval < 3) { - GErrorStr += "\n At least 3 spikes needed for AHP_depth_abs_slow and " - "AHP_slow_time.\n"; - return -1; - } - // time after the spike in ms after which to start searching for minimum - vector sahp_start; - retval = getVec(DoubleFeatureData, StringData, "sahp_start", sahp_start); - if (retval < 0){ - sahp_start.push_back(5); - }; - - vector adas_indices; - retval = __AHP_depth_abs_slow_indices(t, v, peakindices, sahp_start[0], adas_indices); - vector ahpdepthabsslow(adas_indices.size()); - vector ahpslowtime(adas_indices.size()); - for (size_t i = 0; i < adas_indices.size(); i++) { - ahpdepthabsslow[i] = v[adas_indices[i]]; - ahpslowtime[i] = (t[adas_indices[i]] - t[peakindices[i + 1]]) / - (t[peakindices[i + 2]] - t[peakindices[i + 1]]); - } - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AHP_depth_abs_slow", - ahpdepthabsslow); - setVec(DoubleFeatureData, StringData, "AHP_slow_time", ahpslowtime); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "sahp_start"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); + if (intFeatures.at("peak_indices").size() < 3) { + GErrorStr += "\n At least 3 spikes needed for AHP_depth_abs_slow and AHP_slow_time.\n"; + return -1; + } + double sahp_start = (doubleFeatures.at("sahp_start").empty()) ? 5 : doubleFeatures.at("sahp_start")[0]; + vector adas_indices; + int retval = __AHP_depth_abs_slow_indices( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + intFeatures.at("peak_indices"), + sahp_start, + adas_indices + ); + vector ahpdepthabsslow(adas_indices.size()); + vector ahpslowtime(adas_indices.size()); + for (size_t i = 0; i < adas_indices.size(); i++) { + ahpdepthabsslow[i] = doubleFeatures.at("V")[adas_indices[i]]; + ahpslowtime[i] = (doubleFeatures.at("T")[adas_indices[i]] - doubleFeatures.at("T")[intFeatures.at("peak_indices")[i + 1]]) / + (doubleFeatures.at("T")[intFeatures.at("peak_indices")[i + 2]] - doubleFeatures.at("T")[intFeatures.at("peak_indices")[i + 1]]); + } + if (retval >= 0) { + setVec(DoubleFeatureData, StringData, "AHP_depth_abs_slow", ahpdepthabsslow); + setVec(DoubleFeatureData, StringData, "AHP_slow_time", ahpslowtime); + } + return retval; } // end of AHP_depth_abs_slow @@ -430,8 +324,8 @@ int LibV1::AHP_slow_time(mapStr2intVec& IntFeatureData, return -1; } -static int __burst_ISI_indices(double BurstFactor, vector& PeakIndex, - vector& ISIValues, +static int __burst_ISI_indices(double BurstFactor, const vector& PeakIndex, + const vector& ISIValues, vector& BurstIndex) { vector ISIpcopy; int n, count = -1; @@ -460,35 +354,29 @@ static int __burst_ISI_indices(double BurstFactor, vector& PeakIndex, int LibV1::burst_ISI_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector PeakIndex, BurstIndex; - vector ISIValues, tVec; - double BurstFactor = 0; - retVal = getVec(IntFeatureData, StringData, "peak_indices", PeakIndex); - if (retVal < 0) return -1; - if (PeakIndex.size() < 5) { - GErrorStr += "\nError: More than 5 spike is needed for burst calculation.\n"; - return -1; - } - retVal = getVec(DoubleFeatureData, StringData, "ISI_values", ISIValues); - if (retVal < 0) return -1; - retVal = getParam(DoubleFeatureData, "burst_factor", tVec); - if (retVal < 0) - BurstFactor = 2; - else - BurstFactor = tVec[0]; - - retVal = __burst_ISI_indices(BurstFactor, PeakIndex, ISIValues, BurstIndex); - if (retVal >= 0) { - setVec(IntFeatureData, StringData, "burst_ISI_indices", BurstIndex); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values", "burst_factor"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); + if (intFeatures.at("peak_indices").size() < 5) { + GErrorStr += "\nError: More than 5 spike is needed for burst calculation.\n"; + return -1; + } + double BurstFactor = (doubleFeatures.at("burst_factor").empty()) ? 2 : doubleFeatures.at("burst_factor")[0]; + vector BurstIndex; + int retVal = __burst_ISI_indices( + BurstFactor, + intFeatures.at("peak_indices"), + doubleFeatures.at("ISI_values"), + BurstIndex + ); + if (retVal >= 0) { + setVec(IntFeatureData, StringData, "burst_ISI_indices", BurstIndex); + } + return retVal; } // discrepancy betwen PVTime indices and BurstIndex indices because // first ISI value is ignored -static int __burst_mean_freq(vector& PVTime, vector& BurstIndex, +static int __burst_mean_freq(const vector& PVTime, const vector& BurstIndex, int IgnoreFirstISI, vector& BurstMeanFreq) { // if no burst detected, do not consider all peaks in a single burst @@ -519,52 +407,44 @@ static int __burst_mean_freq(vector& PVTime, vector& BurstIndex, int LibV1::burst_mean_freq(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - int IgnoreFirstISI; - vector BurstIndex, retIgnore; - vector BurstMeanFreq, PVTime; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", PVTime); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "burst_ISI_indices", - BurstIndex); - if (retVal < 0) return -1; - - retVal = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); - if ((retVal == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { - IgnoreFirstISI = 0; - } - else { - IgnoreFirstISI = 1; - } - - retVal = __burst_mean_freq(PVTime, BurstIndex, IgnoreFirstISI, BurstMeanFreq); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "burst_mean_freq", - BurstMeanFreq); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"burst_ISI_indices", "ignore_first_ISI"}); + int IgnoreFirstISI = 1; + int retValIgnore; + vector retIgnore; + retValIgnore = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); + if ((retValIgnore == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { + IgnoreFirstISI = 0; + } + else { + IgnoreFirstISI = 1; + } + vector BurstMeanFreq; + int retVal = __burst_mean_freq( + doubleFeatures.at("peak_time"), + intFeatures.at("burst_ISI_indices"), + IgnoreFirstISI, + BurstMeanFreq + ); + if (retVal >= 0) { + setVec(DoubleFeatureData, StringData, "burst_mean_freq", BurstMeanFreq); + } + return retVal; } int LibV1::burst_number(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector BurstMeanFreq; - vector BurstNum; - retVal = getVec(DoubleFeatureData, StringData, - "burst_mean_freq", BurstMeanFreq); - if (retVal < 0) return -1; - - BurstNum.push_back(BurstMeanFreq.size()); - setVec(IntFeatureData, StringData, "burst_number", BurstNum); - return (BurstNum.size()); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"burst_mean_freq"}); + vector BurstNum; + BurstNum.push_back(doubleFeatures.at("burst_mean_freq").size()); + setVec(IntFeatureData, StringData, "burst_number", BurstNum); + return BurstNum.size(); } // reminder: first ISI value is ignored in burst_ISI_indices if IgnoreFirstISI=1 -static int __interburst_voltage(vector& BurstIndex, vector& PeakIndex, - vector& T, vector& V, +static int __interburst_voltage(const vector& BurstIndex, const vector& PeakIndex, + const vector& T, const vector& V, int IgnoreFirstISI, vector& IBV) { if (BurstIndex.size() < 1) return 0; @@ -598,39 +478,36 @@ static int __interburst_voltage(vector& BurstIndex, vector& PeakIndex, int LibV1::interburst_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - int IgnoreFirstISI; - vector BurstIndex, PeakIndex, retIgnore; - vector V, T, IBV; - retVal = getVec(IntFeatureData, StringData, "peak_indices", PeakIndex); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", T); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "burst_ISI_indices", - BurstIndex); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "V", V); - if (retVal < 0) return -1; - - retVal = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); - if ((retVal == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { - IgnoreFirstISI = 0; - } - else { - IgnoreFirstISI = 1; - } - - retVal = __interburst_voltage(BurstIndex, PeakIndex, T, V, IgnoreFirstISI, IBV); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "interburst_voltage", IBV); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "burst_ISI_indices"}); + int IgnoreFirstISI; + int retValIgnore; + vector retIgnore; + retValIgnore = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); + if ((retValIgnore == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { + IgnoreFirstISI = 0; + } + else { + IgnoreFirstISI = 1; + } + vector IBV; + int retVal = __interburst_voltage( + intFeatures.at("burst_ISI_indices"), + intFeatures.at("peak_indices"), + doubleFeatures.at("T"), + doubleFeatures.at("V"), + IgnoreFirstISI, + IBV + ); + if (retVal >= 0) { + setVec(DoubleFeatureData, StringData, "interburst_voltage", IBV); + } + return retVal; } static int __adaptation_index(double spikeSkipf, int maxnSpike, double StimStart, double StimEnd, double Offset, - vector& peakVTime, + const vector& peakVTime, vector& adaptation_index) { list SpikeTime; vector ISI; @@ -685,39 +562,36 @@ static int __adaptation_index(double spikeSkipf, int maxnSpike, int LibV1::adaptation_index(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end", "spike_skipf"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"max_spike_skip"}); - vector peakVTime, stimStart, stimEnd, OffSetVec, spikeSkipf, - adaptation_index; - vector maxnSpike; - double Offset; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", peakVTime); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal < 0) return -1; - retVal = getParam(DoubleFeatureData, "spike_skipf", spikeSkipf); - if (retVal < 0) return -1; - // spikeSkipf is a fraction hence value should lie between >=0 and <1. [0 1) - if ((spikeSkipf[0] < 0) || (spikeSkipf[0] >= 1)) { - GErrorStr += "\nspike_skipf should lie between [0 1).\n"; - return -1; - } - retVal = getParam(IntFeatureData, "max_spike_skip", maxnSpike); - if (retVal < 0) return -1; - retVal = getParam(DoubleFeatureData, "offset", OffSetVec); - if (retVal < 0) - Offset = 0; - else - Offset = OffSetVec[0]; + if (doubleFeatures.at("spike_skipf")[0] < 0 || doubleFeatures.at("spike_skipf")[0] >= 1) { + GErrorStr += "\nspike_skipf should lie between [0 1).\n"; + return -1; + } + vector OffSetVec; + double Offset; + int retval = getParam(DoubleFeatureData, "offset", OffSetVec); + if (retval < 0) { + Offset = 0; // Keep old behavior, set Offset to 0 if offset is not found + } else { + Offset = OffSetVec[0]; // Use the first element of OffSetVec if found + } - retVal = __adaptation_index(spikeSkipf[0], maxnSpike[0], stimStart[0], - stimEnd[0], Offset, peakVTime, adaptation_index); - if (retVal >= 0) - setVec(DoubleFeatureData, StringData, "adaptation_index", - adaptation_index); - return retVal; + vector adaptation_index; + int retVal = __adaptation_index( + doubleFeatures.at("spike_skipf")[0], + intFeatures.at("max_spike_skip")[0], + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], + Offset, + doubleFeatures.at("peak_time"), + adaptation_index + ); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "adaptation_index", adaptation_index); + } + return retVal; } // *** adaptation_index2 *** @@ -771,83 +645,63 @@ static int __adaptation_index2(double StimStart, double StimEnd, double Offset, int LibV1::adaptation_index2(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end"}); + vector OffSetVec; + double Offset; + int retval = getParam(DoubleFeatureData, "offset", OffSetVec); + if (retval < 0) + Offset = 0; + else + Offset = OffSetVec[0]; + + if (doubleFeatures.at("peak_time").size() < 4) { + GErrorStr += "\n At least 4 spikes needed for adaptation_index2.\n"; + return -1; + } - vector peakvoltagetime; - retval = getVec(DoubleFeatureData, StringData, "peak_time", - peakvoltagetime); - if (retval < 4) { - GErrorStr += "\n At least 4 spikes needed for adaptation_index2.\n"; - return -1; - } - vector stimStart; - retval = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - { - if (retval < 0) return -1; - }; - vector stimEnd; - retval = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - { - if (retval < 0) return -1; - }; - vector OffSetVec; - double Offset; - retval = getParam(DoubleFeatureData, "offset", OffSetVec); - if (retval < 0) - Offset = 0; - else - Offset = OffSetVec[0]; - vector adaptationindex2; - retval = __adaptation_index2(stimStart[0], stimEnd[0], Offset, - peakvoltagetime, adaptationindex2); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "adaptation_index2", - adaptationindex2); - } - return retval; + vector adaptationindex2; + retval = __adaptation_index2( + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], + Offset, + doubleFeatures.at("peak_time"), + adaptationindex2 + ); + + if (retval >= 0) { + setVec(DoubleFeatureData, StringData, "adaptation_index2", adaptationindex2); + } + return retval; } + // end of adaptation_index2 int LibV1::trace_check(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - - vector peak_time; - vector stim_start; - vector stim_end; - vector tc; - retval = getVec(DoubleFeatureData, StringData, "peak_time", peak_time); - if (retval < 0) return -1; - retval = getVec(DoubleFeatureData, StringData, "stim_start", stim_start); - if (retval < 0) return -1; - retval = getVec(DoubleFeatureData, StringData, "stim_end", stim_end); - if (retval < 0) return -1; - - bool sane = true; - for (size_t i = 0; i < peak_time.size(); i++) { - if (peak_time[i] < stim_start[0] || peak_time[i] > stim_end[0] * 1.05) { - sane = false; - break; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end"}); + bool sane = true; + for (const auto& peak : doubleFeatures.at("peak_time")) { + if (peak < doubleFeatures.at("stim_start")[0] || peak > doubleFeatures.at("stim_end")[0] * 1.05) { + sane = false; + break; + } + } + if (sane) { + vector tc = {0}; + setVec(IntFeatureData, StringData, "trace_check", tc); + return tc.size(); + } else { + GErrorStr += "Trace sanity check failed, there were spike outside the stimulus interval.\n"; + return -1; } - } - if (sane) { - tc.push_back(0); - setVec(IntFeatureData, StringData, "trace_check", tc); - return tc.size(); - } else { - GErrorStr += - "Trace sanity check failed, there were spike outside the stimulus " - "interval.\n"; - return -1; - } } // To find spike width using Central difference derivative vec1[i] = // ((vec[i+1]+vec[i-1])/2)/dx and half width is between // MinAHP and APThreshold -static int __spike_width2(vector& t, vector& V, - vector& PeakIndex, vector& minAHPIndex, +static int __spike_width2(const vector& t, const vector& V, + const vector& PeakIndex, const vector& minAHPIndex, vector& spike_width2) { vector v, dv1, dv2; double dx = t[1] - t[0]; @@ -929,30 +783,24 @@ static int __spike_width2(vector& t, vector& V, int LibV1::spike_width2(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector PeakIndex, minAHPIndex; - vector V, t, dv1, dv2, spike_width2; - retVal = getVec(DoubleFeatureData, StringData, "V", V); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "min_AHP_indices", minAHPIndex); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "peak_indices", PeakIndex); - if (retVal < 0) return -1; - if (PeakIndex.size() <= 1) { - GErrorStr += "\nError: More than one spike is needed for spikewidth " - "calculation.\n"; - return -1; - } - // Take derivative of voltage from 1st AHPmin to the peak of the spike - // Using Central difference derivative vec1[i] = ((vec[i+1]+vec[i-1])/2)/dx - retVal = __spike_width2(t, V, PeakIndex, minAHPIndex, spike_width2); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "spike_width2", spike_width2); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); + if (intFeatures.at("peak_indices").size() <= 1) { + GErrorStr += "\nError: More than one spike is needed for spikewidth calculation.\n"; + return -1; + } + vector spike_width2; + int retVal = __spike_width2( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + intFeatures.at("peak_indices"), + intFeatures.at("min_AHP_indices"), + spike_width2 + ); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "spike_width2", spike_width2); + } + return retVal; } // passive properties implementation @@ -1103,26 +951,19 @@ static int __time_constant(const vector& v, const vector& t, int LibV1::time_constant(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector v; - vector t; - vector stimStart; - vector stimEnd; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal < 0) return -1; - vector tc; - retVal = __time_constant(v, t, stimStart[0], stimEnd[0], tc); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "time_constant", tc); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + vector tc; + int retVal = __time_constant( + doubleFeatures.at("V"), + doubleFeatures.at("T"), + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], + tc + ); + if (retVal >= 0) { + setVec(DoubleFeatureData, StringData, "time_constant", tc); + } + return retVal; } // *** voltage deflection *** @@ -1164,26 +1005,19 @@ static int __voltage_deflection(const vector& v, int LibV1::voltage_deflection(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector v; - vector t; - vector stimStart; - vector stimEnd; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal < 0) return -1; - vector vd; - retVal = __voltage_deflection(v, t, stimStart[0], stimEnd[0], vd); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "voltage_deflection", vd); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + vector vd; + int retVal = __voltage_deflection( + doubleFeatures.at("V"), + doubleFeatures.at("T"), + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], + vd + ); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "voltage_deflection", vd); + } + return retVal; } // *** ohmic input resistance *** @@ -1198,23 +1032,17 @@ static int __ohmic_input_resistance(double voltage_deflection, int LibV1::ohmic_input_resistance(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector voltage_deflection; - retVal = getVec(DoubleFeatureData, StringData, - "voltage_deflection", voltage_deflection); - if (retVal < 0) return -1; - vector stimulus_current; - retVal = getParam(DoubleFeatureData, "stimulus_current", - stimulus_current); - if (retVal < 0) return -1; - vector oir; - retVal = __ohmic_input_resistance(voltage_deflection[0], - stimulus_current[0], oir); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "ohmic_input_resistance", oir); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_deflection", "stimulus_current"}); + vector oir; + int retVal = __ohmic_input_resistance( + doubleFeatures.at("voltage_deflection")[0], + doubleFeatures.at("stimulus_current")[0], + oir + ); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "ohmic_input_resistance", oir); + } + return retVal; } static int __maxmin_voltage(const vector& v, const vector& t, @@ -1252,31 +1080,23 @@ static int __maxmin_voltage(const vector& v, const vector& t, return 1; } -// *** maximum voltage *** int LibV1::maximum_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector v; - vector t; - vector stimStart; - vector stimEnd; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal < 0) return -1; - - vector maxV, minV; - retVal = __maxmin_voltage(v, t, stimStart[0], stimEnd[0], maxV, minV); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "maximum_voltage", maxV); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + vector maxV, minV; + int retVal = __maxmin_voltage( + doubleFeatures.at("V"), + doubleFeatures.at("T"), + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], + maxV, + minV + ); + if (retVal >= 0) { + setVec(DoubleFeatureData, StringData, "maximum_voltage", maxV); + } + return retVal; } // *** maximum voltage *** @@ -1284,26 +1104,20 @@ int LibV1::maximum_voltage(mapStr2intVec& IntFeatureData, int LibV1::minimum_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector v; - vector t; - vector stimStart; - vector stimEnd; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal < 0) return -1; - vector maxV, minV; - retVal = __maxmin_voltage(v, t, stimStart[0], stimEnd[0], maxV, minV); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "minimum_voltage", minV); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + vector maxV, minV; + int retVal = __maxmin_voltage( + doubleFeatures.at("V"), + doubleFeatures.at("T"), + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], + maxV, + minV + ); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "minimum_voltage", minV); + } + return retVal; } // *** steady state voltage *** @@ -1324,24 +1138,20 @@ static int __steady_state_voltage(const vector& v, int LibV1::steady_state_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 1) return -1; - vector t; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 1) return -1; - vector stimEnd; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal != 1) return -1; - - vector ssv; - retVal = __steady_state_voltage(v, t, stimEnd[0], ssv); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "steady_state_voltage", ssv); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_end"}); + if (doubleFeatures.at("stim_end").size() != 1) return -1; + + vector ssv; + int retVal = __steady_state_voltage( + doubleFeatures.at("V"), + doubleFeatures.at("T"), + doubleFeatures.at("stim_end")[0], + ssv + ); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "steady_state_voltage", ssv); + } + return retVal; } // *** single_burst_ratio *** @@ -1365,56 +1175,16 @@ static int __single_burst_ratio(const vector& isivalues, int LibV1::single_burst_ratio(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - - vector isivalues; - retval = getVec(DoubleFeatureData, StringData, "ISI_values", isivalues); - if (retval < 0) return -1; - vector singleburstratio; - - retval = __single_burst_ratio(isivalues, singleburstratio); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "single_burst_ratio", - singleburstratio); - } - return retval; -} - -int LibV1::printVectorI(char* strName, vector vec) { - size_t nSize = 0; - vector::iterator pos1, pos2; - nSize = vec.size(); - printf("\nName = [%s] size = [%zu] values = [", strName, nSize); - if (nSize > 0) { - if (nSize < 100.0) { - for (size_t i = 0; i < nSize; i++) { - printf("%d ", vec[i]); - } - } - pos1 = max_element(vec.begin(), vec.end()); - pos2 = min_element(vec.begin(), vec.end()); - std::cout << "max :" << *pos1 << " min :" << *pos2; - } - printf("]\n"); - return 0; -} - -int LibV1::printVectorD(char* strName, vector vec) { - size_t nSize = vec.size(); - vector::iterator pos1, pos2; - printf("\nName = [%s] size = [%zu] values = [", strName, nSize); - if (nSize > 0) { - if (nSize < 100.0) { - for (size_t i = 0; i < nSize; i++) { - printf("%f ", vec[i]); - } + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); + vector singleburstratio; + int retval = __single_burst_ratio( + doubleFeatures.at("ISI_values"), + singleburstratio + ); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "single_burst_ratio", singleburstratio); } - pos1 = max_element(vec.begin(), vec.end()); - pos2 = min_element(vec.begin(), vec.end()); - std::cout << "max :" << *pos1 << " min :" << *pos2; - } - printf("]\n"); - return 0; + return retval; } // *** AP_width *** @@ -1429,10 +1199,6 @@ static int __AP_width(const vector& t, const vector& v, const bool strict_stiminterval, vector& apwidth) { // printf("\n Inside AP_width...\n"); - // printVectorD("t", t); - // printVectorD("v", v); - // printVectorI("peakindices", peakindices); - // printVectorI("minahpindices", minahpindices); // printf("\nStimStart = %f , thereshold = %f ", stimstart, threshold); vector indices; if (strict_stiminterval){ @@ -1481,48 +1247,25 @@ static int __AP_width(const vector& t, const vector& v, int LibV1::AP_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector t; - retval = getVec(DoubleFeatureData, StringData, "T", t); - if (retval < 0) return -1; - vector v; - retval = getVec(DoubleFeatureData, StringData, "V", v); - if (retval < 0) return -1; - vector threshold; - retval = getParam(DoubleFeatureData, "Threshold", threshold); - if (retval < 0) return -1; - vector stimstart; - retval = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retval < 0) return -1; - vector stimend; - retval = getVec(DoubleFeatureData, StringData, "stim_end", stimend); - if (retval < 0) return -1; - vector peakindices; - retval = getVec(IntFeatureData, StringData, "peak_indices", peakindices); - if (retval <= 0) { - GErrorStr += "\nNo spike in trace.\n"; - return -1; - } - - vector minahpindices; - retval = getVec(IntFeatureData, StringData, "min_AHP_indices", minahpindices); - if (retval < 0) return -1; - bool strict_stiminterval; - vector strict_stiminterval_vec; - retval = getParam(IntFeatureData, "strict_stiminterval", - strict_stiminterval_vec); - if (retval <= 0) { - strict_stiminterval = false; - } else { - strict_stiminterval = bool(strict_stiminterval_vec[0]); - } - vector apwidth; - retval = __AP_width(t, v, stimstart[0], stimend[0], threshold[0], peakindices, - minahpindices, strict_stiminterval, apwidth); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AP_width", apwidth); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "Threshold", "stim_start", "stim_end"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices", "strict_stiminterval"}); + bool strict_stiminterval = intFeatures.at("strict_stiminterval").size() > 0 ? bool(intFeatures.at("strict_stiminterval")[0]) : false; + vector apwidth; + int retval = __AP_width( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], + doubleFeatures.at("Threshold")[0], + intFeatures.at("peak_indices"), + intFeatures.at("min_AHP_indices"), + strict_stiminterval, + apwidth + ); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_width", apwidth); + } + return retval; } // end of AP_width @@ -1531,19 +1274,15 @@ int LibV1::AP_width(mapStr2intVec& IntFeatureData, int LibV1::doublet_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector pvt; - retval = getVec(DoubleFeatureData, StringData, "peak_time", pvt); - if (retval < 2) { - GErrorStr += "\nNeed at least two spikes for doublet_ISI.\n"; - return -1; - } - - vector doubletisi(1, pvt[1] - pvt[0]); - setVec(DoubleFeatureData, StringData, "doublet_ISI", doubletisi); - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); + if (doubleFeatures.at("peak_time").size() < 2) { + GErrorStr += "\nNeed at least two spikes for doublet_ISI.\n"; + return -1; + } + vector doubletisi(1, doubleFeatures.at("peak_time")[1] - doubleFeatures.at("peak_time")[0]); + setVec(DoubleFeatureData, StringData, "doublet_ISI", doubletisi); + return doubleFeatures.at("peak_time").size(); } -// end of doublet_ISI // *** AHP_depth_slow *** static int __AHP_depth_slow(const vector& voltagebase, @@ -1558,25 +1297,18 @@ static int __AHP_depth_slow(const vector& voltagebase, int LibV1::AHP_depth_slow(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector voltagebase; - retval = getVec(DoubleFeatureData, StringData, "voltage_base", - voltagebase); - if (retval < 0) return -1; - vector ahpdepthabsslow; - retval = getVec(DoubleFeatureData, StringData, "AHP_depth_abs_slow", - ahpdepthabsslow); - std::cout << "retval:" << retval; - if (retval < 0) return -1; - - vector ahpdepthslow; - retval = __AHP_depth_slow(voltagebase, ahpdepthabsslow, ahpdepthslow); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AHP_depth_slow", ahpdepthslow); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_base", "AHP_depth_abs_slow"}); + vector ahpdepthslow; + int retval = __AHP_depth_slow( + doubleFeatures.at("voltage_base"), + doubleFeatures.at("AHP_depth_abs_slow"), + ahpdepthslow + ); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AHP_depth_slow", ahpdepthslow); + } + return retval; } -// end of AHP_depth_slow // *** AHP_depth *** @@ -1591,24 +1323,18 @@ static int __AHP_depth(const vector& voltagebase, int LibV1::AHP_depth(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector voltagebase; - retval = getVec(DoubleFeatureData, StringData, "voltage_base", - voltagebase); - if (retval < 0) return -1; - vector minahpvalues; - retval = getVec(DoubleFeatureData, StringData, "min_AHP_values", - minahpvalues); - if (retval < 0) return -1; - - vector ahpdepth; - retval = __AHP_depth(voltagebase, minahpvalues, ahpdepth); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AHP_depth", ahpdepth); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_base", "min_AHP_values"}); + vector ahpdepth; + int retval = __AHP_depth( + doubleFeatures.at("voltage_base"), + doubleFeatures.at("min_AHP_values"), + ahpdepth + ); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AHP_depth", ahpdepth); + } + return retval; } -// end of AHP_depth // *** AP_amplitude_diff based on AP_amplitude_change but not normalized *** static int __AP_amplitude_diff(const vector& apamplitude, @@ -1624,21 +1350,17 @@ static int __AP_amplitude_diff(const vector& apamplitude, int LibV1::AP_amplitude_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector apamplitude; - retval = getVec(DoubleFeatureData, StringData, "AP_amplitude", - apamplitude); - if (retval < 0) return -1; - - vector apamplitudediff; - retval = __AP_amplitude_diff(apamplitude, apamplitudediff); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AP_amplitude_diff", - apamplitudediff); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"AP_amplitude"}); + vector apamplitudediff; + int retval = __AP_amplitude_diff( + doubleFeatures.at("AP_amplitude"), + apamplitudediff + ); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_amplitude_diff", apamplitudediff); + } + return retval; } -// end of AP_amplitude_diff // *** AHP_depth_diff, returns AHP_depth[i+1] - AHP_depth[i] *** static int __AHP_depth_diff(const vector& ahpdepth, @@ -1653,19 +1375,15 @@ static int __AHP_depth_diff(const vector& ahpdepth, int LibV1::AHP_depth_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector ahpdepth; - retval = getVec(DoubleFeatureData, StringData, "AHP_depth", - ahpdepth); - if (retval < 0) return -1; - - vector ahpdepthdiff; - retval = __AHP_depth_diff(ahpdepth, ahpdepthdiff); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AHP_depth_diff", ahpdepthdiff); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"AHP_depth"}); + vector ahpdepthdiff; + int retval = __AHP_depth_diff( + doubleFeatures.at("AHP_depth"), + ahpdepthdiff + ); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AHP_depth_diff", ahpdepthdiff); + } + return retval; } -// end of AHP_depth_diff - // end of feature definition diff --git a/efel/cppcore/LibV1.h b/efel/cppcore/LibV1.h index 4443dcf7..9ed20207 100644 --- a/efel/cppcore/LibV1.h +++ b/efel/cppcore/LibV1.h @@ -27,9 +27,6 @@ using std::vector; namespace LibV1 { -int printVectorI(char* strName, vector vec); -int printVectorD(char* strName, vector vec); - int interpolate(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); diff --git a/efel/pyfeatures/pyfeatures.py b/efel/pyfeatures/pyfeatures.py index 309e16fc..f3d41d2f 100644 --- a/efel/pyfeatures/pyfeatures.py +++ b/efel/pyfeatures/pyfeatures.py @@ -99,10 +99,12 @@ def current(): def ISIs(): - """Get all ISIs""" - + """Get all ISIs.""" peak_times = _get_cpp_feature("peak_time") - return numpy.diff(peak_times) + if peak_times is None: + return None + else: + return numpy.diff(peak_times) def initburst_sahp_vb(): @@ -156,6 +158,8 @@ def initburst_sahp(): last_isi = None # Loop over ISIs until frequency higher than initburst_freq_threshold + if all_isis is None: + return None for isi_counter, isi in enumerate(all_isis): # Convert to Hz freq = 1000.0 / isi diff --git a/tests/test_basic.py b/tests/test_basic.py index f5da13f9..e5734347 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -2545,6 +2545,8 @@ def test_burst_mean_freq(): if i == 1: assert burst_mean_freq == burst_mean_freq_py assert burst_mean_freq is None + elif i == 2: + assert burst_mean_freq is None else: numpy.testing.assert_allclose(burst_mean_freq, burst_mean_freq_py) numpy.testing.assert_allclose(burst_mean_freq, expected_value) From 65e8f60840d247a75cfbe21473c7df7b97a82268 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Wed, 8 Nov 2023 13:29:52 +0100 Subject: [PATCH 30/85] using to replace scope resolution --- efel/cppcore/mapoperations.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/efel/cppcore/mapoperations.h b/efel/cppcore/mapoperations.h index 602f6b46..7108412b 100644 --- a/efel/cppcore/mapoperations.h +++ b/efel/cppcore/mapoperations.h @@ -28,21 +28,22 @@ using std::string; using std::vector; +using std::map; extern string GErrorStr; template -std::map> getFeatures( - const std::map>& allFeatures, - const std::vector& requestedFeatures); +map> getFeatures( + const map>& allFeatures, + const vector& requestedFeatures); template -int getParam(std::map>& featureData, - const std::string& param, std::vector& vec); +int getParam(map>& featureData, + const string& param, vector& vec); int getStrParam(mapStr2Str& StringData, const string& param, string& value); template -void setVec(std::map >& FeatureData, mapStr2Str& StringData, +void setVec(map>& FeatureData, mapStr2Str& StringData, string key, const vector& value); template -int getVec(std::map >& FeatureData, mapStr2Str& StringData, +int getVec(map>& FeatureData, mapStr2Str& StringData, string strFeature, vector& v); #endif From d0084a3a3351701e99c9f3843e653cbd38c55d3b Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Wed, 8 Nov 2023 13:30:37 +0100 Subject: [PATCH 31/85] define distinct errors: FeatureComputationError, EmptyFeatureError --- efel/cppcore/EfelExceptions.h | 13 +++++++++++++ efel/cppcore/LibV1.cpp | 23 ++++++++--------------- efel/cppcore/LibV5.cpp | 3 ++- efel/cppcore/cfeature.cpp | 7 ++++++- efel/cppcore/cppcore.cpp | 10 +++------- efel/cppcore/mapoperations.cpp | 10 ++++++---- 6 files changed, 38 insertions(+), 28 deletions(-) diff --git a/efel/cppcore/EfelExceptions.h b/efel/cppcore/EfelExceptions.h index ac7c85c2..e140061f 100644 --- a/efel/cppcore/EfelExceptions.h +++ b/efel/cppcore/EfelExceptions.h @@ -4,9 +4,22 @@ #include // Define the custom exception class +// Raise this error to mark the function failed when a required condition is not met class EfelAssertionError : public std::runtime_error { public: explicit EfelAssertionError(const std::string& message) : std::runtime_error(message) {} }; +class FeatureComputationError : public std::runtime_error { +public: + explicit FeatureComputationError(const std::string& message) + : std::runtime_error("An error occurred while computing the feature, feature is not found. " + message) {} +}; + +class EmptyFeatureError : public std::runtime_error { +public: + explicit EmptyFeatureError(const std::string& message) + : std::runtime_error("The feature is found in the feature dictionary but it is empty. " + message) {} +}; + #endif // EFEL_EXCEPTIONS_H diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index 082d7731..bfec9f6e 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -28,6 +28,7 @@ #include #include #include +#include "EfelExceptions.h" using std::distance; using std::find_if; @@ -83,24 +84,16 @@ int LibV1::interpolate(mapStr2intVec& IntFeatureData, int LibV1::Spikecount(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; size_t spikecount_value; - - vector peakindices; - retval = getVec(IntFeatureData, StringData, "peak_indices", - peakindices); - if (retval < 0) { - return -1; - } else if (retval == 0) { - spikecount_value = 0; - } else { - spikecount_value = peakindices.size(); + try { // handle empty peak_indices + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); + spikecount_value = intFeatures.at("peak_indices").size(); + } catch(const EmptyFeatureError& e) { + spikecount_value = 0; } vector spikecount(1, spikecount_value); - if (retval >= 0) { - setVec(IntFeatureData, StringData, "Spikecount", spikecount); - } - return retval; + setVec(IntFeatureData, StringData, "Spikecount", spikecount); + return spikecount_value; } // end of Spikecount diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index e82a61d9..ecd3ebc0 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -25,6 +25,7 @@ #include #include #include +#include "EfelExceptions.h" using std::distance; using std::find_if; @@ -171,7 +172,7 @@ double calculateInvISI(const std::vector& all_isi_values_vec, size_t ind if (index < all_isi_values_vec.size()) { return 1000.0 / all_isi_values_vec[index]; } - throw std::out_of_range("inverse ISI index out of range"); + throw FeatureComputationError("inverse ISI index out of range"); } int LibV5::inv_ISI_generic(mapStr2intVec& IntFeatureData, diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 9a580f69..82d1d378 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -290,7 +290,12 @@ int cFeature::getFeature(string strName, vector& vec) { try{ retVal = calc_features(strName); } - catch (const std::out_of_range& e) { + catch (const FeatureComputationError& e) { + GErrorStr += e.what(); + return -1; + } + catch (const EmptyFeatureError& e) + { GErrorStr += e.what(); return -1; } diff --git a/efel/cppcore/cppcore.cpp b/efel/cppcore/cppcore.cpp index c5529ca4..aa52a00e 100644 --- a/efel/cppcore/cppcore.cpp +++ b/efel/cppcore/cppcore.cpp @@ -155,17 +155,13 @@ _getfeature(PyObject* self, PyObject* args, const string &input_type) { PyErr_SetString(PyExc_AssertionError, e.what()); return NULL; } - catch(const std::out_of_range& e) { // feature exists but its dependency is missing - PyErr_SetString(PyExc_KeyError, e.what()); - return NULL; - } catch(const std::runtime_error& e) { // e.g. feature does not exist PyErr_SetString(PyExc_RuntimeError, e.what()); return NULL; } - catch(...) { - PyErr_SetString(PyExc_RuntimeError, "Unknown error"); - return NULL; + catch(const std::exception& e) { // catch standard exceptions + PyErr_SetString(PyExc_RuntimeError, e.what()); + return NULL; } } diff --git a/efel/cppcore/mapoperations.cpp b/efel/cppcore/mapoperations.cpp index 76c75a24..84adf223 100644 --- a/efel/cppcore/mapoperations.cpp +++ b/efel/cppcore/mapoperations.cpp @@ -17,6 +17,7 @@ */ #include "mapoperations.h" +# include "EfelExceptions.h" extern string GErrorStr; @@ -28,11 +29,12 @@ std::map> getFeatures( std::map> selectedFeatures; for (const auto& featureKey : requestedFeatures) { auto it = allFeatures.find(featureKey); - if (it != allFeatures.end() && !it->second.empty()) { - selectedFeatures.insert(*it); + if (it == allFeatures.end()) { + throw FeatureComputationError("Feature " + featureKey + " not found"); + } else if (it->second.empty()) { + throw EmptyFeatureError("Feature " + featureKey + " is empty"); } else { - // If the feature is not found or is empty, throw an exception - throw std::out_of_range("Feature " + featureKey + " not found or is empty"); + selectedFeatures.insert(*it); } } return selectedFeatures; From 84b30207413245961700d5f39b4374b49acd753c Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 9 Nov 2023 16:31:56 +0100 Subject: [PATCH 32/85] use getFeature/s in LibV5 for consistent handling of edge cases --- efel/cppcore/LibV5.cpp | 1912 ++++++----------- efel/cppcore/Utils.cpp | 2 +- efel/cppcore/Utils.h | 2 +- efel/cppcore/mapoperations.cpp | 19 + efel/cppcore/mapoperations.h | 4 + .../testdata/allfeatures/expectedresults.json | 2 +- 6 files changed, 642 insertions(+), 1299 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index ecd3ebc0..9879cd94 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -81,8 +81,7 @@ static int __ISI_log_slope(const vector& isiValues, int LibV5::ISI_log_slope(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); - const auto& isivalues = doubleFeatures.at("ISI_values"); + const auto& isivalues = getFeature(DoubleFeatureData, {"ISI_values"}); vector slope; bool semilog = false; int retval = __ISI_log_slope(isivalues, slope, false, 0.0, 0, semilog); @@ -97,8 +96,7 @@ int LibV5::ISI_log_slope(mapStr2intVec& IntFeatureData, int LibV5::ISI_semilog_slope(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); - const auto& isivalues = doubleFeatures.at("ISI_values"); + const auto& isivalues = getFeature(DoubleFeatureData, {"ISI_values"}); vector slope; bool semilog = true; int retval = __ISI_log_slope(isivalues, slope, false, 0.0, 0, semilog); @@ -113,13 +111,9 @@ int LibV5::ISI_semilog_slope(mapStr2intVec& IntFeatureData, int LibV5::ISI_log_slope_skip(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); - const auto doubleParams = getFeatures(DoubleFeatureData, {"spike_skipf"}); - const auto intParams = getFeatures(IntFeatureData, {"max_spike_skip"}); - - const auto& isivalues = doubleFeatures.at("ISI_values"); - const auto spikeSkipf = doubleParams.at("spike_skipf").front(); - const auto maxnSpike = intParams.at("max_spike_skip").front(); + const auto& isivalues = getFeature(DoubleFeatureData, {"ISI_values"}); + const auto spikeSkipf = getFeature(DoubleFeatureData, {"spike_skipf"}).front(); + const auto maxnSpike = getFeature(IntFeatureData, {"max_spike_skip"}).front(); // Check the validity of spikeSkipf value if (spikeSkipf < 0 || spikeSkipf >= 1) { @@ -179,9 +173,7 @@ int LibV5::inv_ISI_generic(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData, size_t index) { - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); - const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); - + const auto& all_isi_values_vec = getFeature(DoubleFeatureData, {"all_ISI_values"}); double inv_ISI = calculateInvISI(all_isi_values_vec, index); std::string featureName; @@ -209,8 +201,7 @@ int LibV5::inv_ISI_generic(mapStr2intVec& IntFeatureData, int LibV5::inv_last_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"all_ISI_values"}); - const auto& all_isi_values_vec = doubleFeatures.at("all_ISI_values"); + const auto& all_isi_values_vec = getFeature(DoubleFeatureData, {"all_ISI_values"}); double inv_last_ISI = calculateInvISI(all_isi_values_vec, all_isi_values_vec.size() - 1); // Last ISI vector inv_last_ISI_vec = {inv_last_ISI}; @@ -222,21 +213,13 @@ int LibV5::inv_last_ISI(mapStr2intVec& IntFeatureData, int LibV5::inv_time_to_first_spike(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector time_to_first_spike_vec; - double inv_time_to_first_spike; + vector time_to_first_spike_vec = getFeature(DoubleFeatureData, "time_to_first_spike"); vector inv_time_to_first_spike_vec; - retVal = getVec(DoubleFeatureData, StringData, "time_to_first_spike", - time_to_first_spike_vec); - if (retVal < 1) { - inv_time_to_first_spike = 0.0; - } else { - inv_time_to_first_spike = 1000.0 / time_to_first_spike_vec[0]; - } + + double inv_time_to_first_spike = 1000.0 / time_to_first_spike_vec[0]; inv_time_to_first_spike_vec.push_back(inv_time_to_first_spike); - setVec(DoubleFeatureData, StringData, "inv_time_to_first_spike", - inv_time_to_first_spike_vec); + + setVec(DoubleFeatureData, StringData, "inv_time_to_first_spike", inv_time_to_first_spike_vec); return 1; } @@ -633,36 +616,25 @@ static int __AP_end_indices(const vector& t, const vector& v, int LibV5::AP_end_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { + const auto& T = getFeature(DoubleFeatureData, "T"); + const auto& V = getFeature(DoubleFeatureData, "V"); + const auto& peak_indices = getFeature(IntFeatureData, "peak_indices"); - int retVal; - vector t; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - vector pi; - retVal = getVec(IntFeatureData, StringData, "peak_indices", pi); - if (retVal < 0) return -1; - - // Get DerivativeThreshold vector dTh; - retVal = getParam(DoubleFeatureData, "DownDerivativeThreshold", dTh); - if (retVal <= 0) { - // derivative at peak end - dTh.push_back(-12.0); - } + int retVal = getParam(DoubleFeatureData, "DownDerivativeThreshold", dTh); + double downDerivativeThreshold = (retVal <= 0) ? -12.0 : dTh[0]; - vector apei; - retVal = __AP_end_indices(t, v, pi, apei, dTh[0]); + vector AP_end_indices; + retVal = __AP_end_indices(T, V, peak_indices, AP_end_indices, downDerivativeThreshold); if (retVal >= 0) { - setVec(IntFeatureData, StringData, "AP_end_indices", apei); + setVec(IntFeatureData, StringData, "AP_end_indices", AP_end_indices); } return retVal; } -static int __irregularity_index(vector& isiValues, + +static int __irregularity_index(const vector& isiValues, vector& irregularity_index) { double ISISub, iRI; iRI = ISISub = 0; @@ -681,19 +653,16 @@ static int __irregularity_index(vector& isiValues, int LibV5::irregularity_index(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector isiValues, irregularity_index; - retVal = getVec(DoubleFeatureData, StringData, "ISI_values", isiValues); - if (retVal < 0) return -1; - - retVal = __irregularity_index(isiValues, irregularity_index); - if (retVal >= 0) - setVec(DoubleFeatureData, StringData, "irregularity_index", - irregularity_index); + const vector& isiValues = getFeature(DoubleFeatureData, "ISI_values"); + vector irregularity_index; + int retVal = __irregularity_index(isiValues, irregularity_index); + if (retVal >= 0) { + setVec(DoubleFeatureData, StringData, "irregularity_index", irregularity_index); + } return retVal; } -static int __number_initial_spikes(vector& peak_times, double stimstart, +static int __number_initial_spikes(const vector& peak_times, double stimstart, double stimend, double initial_perc, vector& number_initial_spikes) { double initialLength = (stimend - stimstart) * initial_perc; @@ -717,32 +686,23 @@ static int __number_initial_spikes(vector& peak_times, double stimstart, int LibV5::number_initial_spikes(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector peak_times, initial_perc; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "initial_perc", "stim_start", "stim_end"}); vector number_initial_spikes; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", peak_times); - if (retVal < 0) return -1; - retVal = getParam(DoubleFeatureData, "initial_perc", initial_perc); - if (retVal <= 0) return -1; + const vector& peak_times = doubleFeatures.at("peak_time"); + const vector& initial_perc = doubleFeatures.at("initial_perc"); + const vector& stimstart = doubleFeatures.at("stim_start"); + const vector& stimend = doubleFeatures.at("stim_end"); + if ((initial_perc[0] < 0) || (initial_perc[0] >= 1)) { - GErrorStr += "\ninitial_perc should lie between [0 1).\n"; - return -1; + throw FeatureComputationError("initial_perc should lie between [0 1)."); } - vector stimstart; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retVal < 0) return -1; - - vector stimend; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimend); - if (retVal < 0) return -1; - - retVal = __number_initial_spikes(peak_times, stimstart[0], stimend[0], - initial_perc[0], number_initial_spikes); - if (retVal >= 0) - setVec(IntFeatureData, StringData, "number_initial_spikes", - number_initial_spikes); + int retVal = __number_initial_spikes(peak_times, stimstart[0], stimend[0], + initial_perc[0], number_initial_spikes); + if (retVal >= 0) { + setVec(IntFeatureData, StringData, "number_initial_spikes", number_initial_spikes); + } return retVal; } @@ -750,17 +710,9 @@ int LibV5::number_initial_spikes(mapStr2intVec& IntFeatureData, int LibV5::AP1_amp(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector AP_amplitudes, AP1_amp; - retVal = getVec(DoubleFeatureData, StringData, "AP_amplitude", - AP_amplitudes); - if (retVal < 1) { - setVec(DoubleFeatureData, StringData, "AP1_amp", AP1_amp); - return 0; - } else { - AP1_amp.push_back(AP_amplitudes[0]); - } - + const vector& AP_amplitudes = getFeature(DoubleFeatureData, "AP_amplitude"); + vector AP1_amp; + AP1_amp.push_back(AP_amplitudes[0]); setVec(DoubleFeatureData, StringData, "AP1_amp", AP1_amp); return 1; } @@ -769,37 +721,21 @@ int LibV5::AP1_amp(mapStr2intVec& IntFeatureData, int LibV5::APlast_amp(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - vector AP_amplitudes, APlast_amp; - int AP_amplitude_size; - - AP_amplitude_size = getVec(DoubleFeatureData, StringData, - "AP_amplitude", AP_amplitudes); - if (AP_amplitude_size < 1) { - setVec(DoubleFeatureData, StringData, "APlast_amp", APlast_amp); - return 0; - } else { - APlast_amp.push_back(AP_amplitudes[AP_amplitude_size - 1]); - } - + const vector& AP_amplitudes = getFeature(DoubleFeatureData, "AP_amplitude"); + vector APlast_amp; + APlast_amp.push_back(AP_amplitudes[AP_amplitudes.size() - 1]); setVec(DoubleFeatureData, StringData, "APlast_amp", APlast_amp); return 1; } + // Peak voltage of the first spike int LibV5::AP1_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector peak_voltage, AP1_peak; - retVal = - getVec(DoubleFeatureData, StringData, "peak_voltage", peak_voltage); - if (retVal < 1) { - setVec(DoubleFeatureData, StringData, "AP1_peak", AP1_peak); - return 0; - } else { - AP1_peak.push_back(peak_voltage[0]); - } - + const vector& peak_voltage = getFeature(DoubleFeatureData, "peak_voltage"); + vector AP1_peak; + AP1_peak.push_back(peak_voltage[0]); setVec(DoubleFeatureData, StringData, "AP1_peak", AP1_peak); return 1; } @@ -808,103 +744,70 @@ int LibV5::AP1_peak(mapStr2intVec& IntFeatureData, int LibV5::AP2_amp(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector AP_amplitudes, AP2_amp; - retVal = getVec(DoubleFeatureData, StringData, "AP_amplitude", - AP_amplitudes); - if (retVal < 2) { - setVec(DoubleFeatureData, StringData, "AP2_amp", AP2_amp); - return 0; + const vector& AP_amplitudes = getFeature(DoubleFeatureData, "AP_amplitude"); + vector AP2_amp; + if (AP_amplitudes.size() < 2) { + throw FeatureComputationError("Size of AP_amplitude should be >= 2 for AP2_amp"); } else { AP2_amp.push_back(AP_amplitudes[1]); + setVec(DoubleFeatureData, StringData, "AP2_amp", AP2_amp); + return 1; } - - setVec(DoubleFeatureData, StringData, "AP2_amp", AP2_amp); - - return 1; } // Peak voltage of the second spike int LibV5::AP2_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector peak_voltage, AP2_peak; - retVal = - getVec(DoubleFeatureData, StringData, "peak_voltage", peak_voltage); - if (retVal < 2) { - setVec(DoubleFeatureData, StringData, "AP2_peak", AP2_peak); - return 0; + const vector& peak_voltage = getFeature(DoubleFeatureData, "peak_voltage"); + vector AP2_peak; + if (peak_voltage.size() < 2) { + throw FeatureComputationError("Size of peak_voltage should be >= 2 for AP2_peak"); } else { AP2_peak.push_back(peak_voltage[1]); + setVec(DoubleFeatureData, StringData, "AP2_peak", AP2_peak); + return 1; } - - setVec(DoubleFeatureData, StringData, "AP2_peak", AP2_peak); - return 1; } // Difference amplitude of the second to first spike int LibV5::AP2_AP1_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector AP_amplitudes, AP2_AP1_diff; - retVal = getVec(DoubleFeatureData, StringData, "AP_amplitude", - AP_amplitudes); - if (retVal < 2) { - setVec(DoubleFeatureData, StringData, "AP2_AP1_diff", AP2_AP1_diff); - return 0; + const vector& AP_amplitudes = getFeature(DoubleFeatureData, "AP_amplitude"); + vector AP2_AP1_diff; + if (AP_amplitudes.size() < 2) { + throw FeatureComputationError("Size of AP_amplitude should be >= 2 for AP2_AP1_diff"); } else { AP2_AP1_diff.push_back(AP_amplitudes[1] - AP_amplitudes[0]); + setVec(DoubleFeatureData, StringData, "AP2_AP1_diff", AP2_AP1_diff); + return 1; } - - setVec(DoubleFeatureData, StringData, "AP2_AP1_diff", AP2_AP1_diff); - - return 1; } // Difference peak_amp of the second to first spike int LibV5::AP2_AP1_peak_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector peak_voltage, AP2_AP1_peak_diff; - retVal = - getVec(DoubleFeatureData, StringData, "peak_voltage", peak_voltage); - if (retVal < 2) { - setVec(DoubleFeatureData, StringData, "AP2_AP1_peak_diff", - AP2_AP1_peak_diff); - return 0; + const vector& peak_voltage = getFeature(DoubleFeatureData, "peak_voltage"); + vector AP2_AP1_peak_diff; + if (peak_voltage.size() < 2) { + throw FeatureComputationError("Size of peak_voltage should be >= 2 for AP2_AP1_peak_diff"); } else { AP2_AP1_peak_diff.push_back(peak_voltage[1] - peak_voltage[0]); + setVec(DoubleFeatureData, StringData, "AP2_AP1_peak_diff", AP2_AP1_peak_diff); + return 1; } - - setVec(DoubleFeatureData, StringData, "AP2_AP1_peak_diff", - AP2_AP1_peak_diff); - - return 1; } // Width of the first spike int LibV5::AP1_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector spike_half_width, AP1_width; - retVal = getVec(DoubleFeatureData, StringData, "spike_half_width", - spike_half_width); - if (retVal < 1) { - setVec(DoubleFeatureData, StringData, "AP1_width", AP1_width); - return 0; - } else { - AP1_width.push_back(spike_half_width[0]); - } - + const vector& spike_half_width = getFeature(DoubleFeatureData, "spike_half_width"); + vector AP1_width; + AP1_width.push_back(spike_half_width[0]); setVec(DoubleFeatureData, StringData, "AP1_width", AP1_width); - return 1; } @@ -912,40 +815,24 @@ int LibV5::AP1_width(mapStr2intVec& IntFeatureData, int LibV5::AP2_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector spike_half_width, AP2_width; - retVal = getVec(DoubleFeatureData, StringData, "spike_half_width", - spike_half_width); - if (retVal < 2) { - setVec(DoubleFeatureData, StringData, "AP2_width", AP2_width); - return 0; + const vector& spike_half_width = getFeature(DoubleFeatureData, "spike_half_width"); + vector AP2_width; + if (spike_half_width.size() < 2) { + throw FeatureComputationError("Size of spike_half_width should be >= 2 for AP2_width"); } else { AP2_width.push_back(spike_half_width[1]); + setVec(DoubleFeatureData, StringData, "AP2_width", AP2_width); + return 1; } - - setVec(DoubleFeatureData, StringData, "AP2_width", AP2_width); - - return 1; } // Width of the last spike int LibV5::APlast_width(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - vector spike_half_width, APlast_width; - - int spike_half_width_size = - getVec(DoubleFeatureData, StringData, "spike_half_width", - spike_half_width); - - if (spike_half_width_size < 1) { - GErrorStr += - "\nError: At least one spike is needed for APlast_width.\n"; - return -1; - } else { - APlast_width.push_back(spike_half_width[spike_half_width_size - 1]); - } - + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const vector& spike_half_width = getFeature(DoubleFeatureData, "spike_half_width"); + vector APlast_width; + APlast_width.push_back(spike_half_width[spike_half_width.size() - 1]); setVec(DoubleFeatureData, StringData, "APlast_width", APlast_width); return 1; } @@ -965,27 +852,17 @@ static int __AHP_time_from_peak(const vector& t, int LibV5::AHP_time_from_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector T; - retval = getVec(DoubleFeatureData, StringData, "T", T); - if (retval < 0) return -1; - - vector peakIndices; - retval = getVec(IntFeatureData, StringData, "peak_indices", peakIndices); - if (retval < 0) return -1; - - vector minAHPIndices; - retval = - getVec(IntFeatureData, StringData, "min_AHP_indices", minAHPIndices); - if (retval < 0) return -1; - + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices"}); vector ahpTimeFromPeak; - retval = __AHP_time_from_peak(T, peakIndices, minAHPIndices, ahpTimeFromPeak); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AHP_time_from_peak", - ahpTimeFromPeak); + const vector& T = doubleFeatures.at("T"); + const vector& peakIndices = intFeatures.at("peak_indices"); + const vector& minAHPIndices = intFeatures.at("min_AHP_indices"); + int retVal = __AHP_time_from_peak(T, peakIndices, minAHPIndices, ahpTimeFromPeak); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "AHP_time_from_peak", ahpTimeFromPeak); } - return retval; + return retVal; } static int __AHP_depth_from_peak(const vector& v, @@ -1002,49 +879,27 @@ static int __AHP_depth_from_peak(const vector& v, int LibV5::AHP_depth_from_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector V; - retval = getVec(DoubleFeatureData, StringData, "V", V); - if (retval < 0) return -1; - - vector peakIndices; - retval = getVec(IntFeatureData, StringData, "peak_indices", peakIndices); - if (retval < 0) return -1; - - vector minAHPIndices; - retval = - getVec(IntFeatureData, StringData, "min_AHP_indices", minAHPIndices); - if (retval < 0) return -1; - + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices"}); vector ahpDepthFromPeak; - retval = - __AHP_depth_from_peak(V, peakIndices, minAHPIndices, ahpDepthFromPeak); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AHP_depth_from_peak", - ahpDepthFromPeak); + const vector& V = doubleFeatures.at("V"); + const vector& peakIndices = intFeatures.at("peak_indices"); + const vector& minAHPIndices = intFeatures.at("min_AHP_indices"); + int retVal = __AHP_depth_from_peak(V, peakIndices, minAHPIndices, ahpDepthFromPeak); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "AHP_depth_from_peak", ahpDepthFromPeak); } - return retval; + return retVal; } // AHP_depth_from_peak of first spike int LibV5::AHP1_depth_from_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector ahpDepthFromPeak, ahp1DepthFromPeak; - retVal = getVec(DoubleFeatureData, StringData, "AHP_depth_from_peak", - ahpDepthFromPeak); - if (retVal < 1) { - setVec(DoubleFeatureData, StringData, "AHP1_depth_from_peak", - ahp1DepthFromPeak); - return 0; - } else { - ahp1DepthFromPeak.push_back(ahpDepthFromPeak[0]); - } - - setVec(DoubleFeatureData, StringData, "AHP1_depth_from_peak", - ahp1DepthFromPeak); - + const vector& ahpDepthFromPeak = getFeature(DoubleFeatureData, "AHP_depth_from_peak"); + vector ahp1DepthFromPeak; + ahp1DepthFromPeak.push_back(ahpDepthFromPeak[0]); + setVec(DoubleFeatureData, StringData, "AHP1_depth_from_peak", ahp1DepthFromPeak); return 1; } @@ -1052,21 +907,14 @@ int LibV5::AHP1_depth_from_peak(mapStr2intVec& IntFeatureData, int LibV5::AHP2_depth_from_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector ahpDepthFromPeak, ahp2DepthFromPeak; - retVal = getVec(DoubleFeatureData, StringData, "AHP_depth_from_peak", - ahpDepthFromPeak); - if (retVal < 2) { - setVec(DoubleFeatureData, StringData, "AHP2_depth_from_peak", - ahp2DepthFromPeak); - return 0; + const vector& ahpDepthFromPeak = getFeature(DoubleFeatureData, "AHP_depth_from_peak"); + vector ahp2DepthFromPeak; + if (ahpDepthFromPeak.size() < 2) { + throw FeatureComputationError("Size of AHP_depth_from_peak should be >= 2 for AHP2_depth_from_peak"); } else { ahp2DepthFromPeak.push_back(ahpDepthFromPeak[1]); } - - setVec(DoubleFeatureData, StringData, "AHP2_depth_from_peak", - ahp2DepthFromPeak); - + setVec(DoubleFeatureData, StringData, "AHP2_depth_from_peak", ahp2DepthFromPeak); return 1; } @@ -1120,35 +968,17 @@ static int __AP_begin_width(const vector& t, const vector& v, int LibV5::AP_begin_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector AP_begin_indices, minAHPIndex; - vector V, t, dv1, dv2, AP_begin_width; - vector stim_start; - retVal = getVec(DoubleFeatureData, StringData, "V", V); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - vector stimstart; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retVal < 0) return -1; - retVal = - getVec(IntFeatureData, StringData, "min_AHP_indices", minAHPIndex); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "AP_begin_indices", - AP_begin_indices); - if (retVal < 0) return -1; - if (AP_begin_indices.size() < 1) { - GErrorStr += - "\nError: At least one spike is needed for spikewidth calculation.\n"; - return -1; - } - // Take derivative of voltage from 1st AHPmin to the peak of the spike - // Using Central difference derivative vec1[i] = ((vec[i+1]+vec[i-1])/2)/dx - retVal = - __AP_begin_width(t, V, stimstart[0], AP_begin_indices, minAHPIndex, AP_begin_width); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "AP_begin_width", - AP_begin_width); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "AP_begin_indices"}); + vector AP_begin_width; + const vector& V = doubleFeatures.at("V"); + const vector& t = doubleFeatures.at("T"); + const vector& stim_start = doubleFeatures.at("stim_start"); + const vector& min_AHP_indices = intFeatures.at("min_AHP_indices"); + const vector& AP_begin_indices = intFeatures.at("AP_begin_indices"); + int retVal = __AP_begin_width(t, V, stim_start[0], AP_begin_indices, min_AHP_indices, AP_begin_width); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "AP_begin_width", AP_begin_width); } return retVal; } @@ -1165,19 +995,14 @@ static int __AP_begin_time(const vector& t, const vector& v, int LibV5::AP_begin_time(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector AP_begin_indices; - vector V, t, AP_begin_time; - retVal = getVec(DoubleFeatureData, StringData, "V", V); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "AP_begin_indices", - AP_begin_indices); - if (retVal < 0) return -1; - - retVal = __AP_begin_time(t, V, AP_begin_indices, AP_begin_time); - if (retVal >= 0) { + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices"}); + vector AP_begin_time; + const vector& V = doubleFeatures.at("V"); + const vector& t = doubleFeatures.at("T"); + const vector& AP_begin_indices = intFeatures.at("AP_begin_indices"); + int retVal = __AP_begin_time(t, V, AP_begin_indices, AP_begin_time); + if (retVal > 0) { setVec(DoubleFeatureData, StringData, "AP_begin_time", AP_begin_time); } return retVal; @@ -1195,21 +1020,15 @@ static int __AP_begin_voltage(const vector& t, const vector& v, int LibV5::AP_begin_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector AP_begin_indices; - vector V, t, AP_begin_voltage; - retVal = getVec(DoubleFeatureData, StringData, "V", V); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "AP_begin_indices", - AP_begin_indices); - if (retVal < 0) return -1; - - retVal = __AP_begin_voltage(t, V, AP_begin_indices, AP_begin_voltage); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "AP_begin_voltage", - AP_begin_voltage); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices"}); + vector AP_begin_voltage; + const vector& V = doubleFeatures.at("V"); + const vector& t = doubleFeatures.at("T"); + const vector& AP_begin_indices = intFeatures.at("AP_begin_indices"); + int retVal = __AP_begin_voltage(t, V, AP_begin_indices, AP_begin_voltage); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "AP_begin_voltage", AP_begin_voltage); } return retVal; } @@ -1217,98 +1036,65 @@ int LibV5::AP_begin_voltage(mapStr2intVec& IntFeatureData, int LibV5::AP1_begin_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector AP_begin_voltage, AP1_begin_voltage; - retVal = getVec(DoubleFeatureData, StringData, "AP_begin_voltage", - AP_begin_voltage); - if (retVal < 1) { - setVec(DoubleFeatureData, StringData, "AP1_begin_voltage", - AP1_begin_voltage); - return 0; - } else { - AP1_begin_voltage.push_back(AP_begin_voltage[0]); - setVec(DoubleFeatureData, StringData, "AP1_begin_voltage", - AP1_begin_voltage); - return 1; - } + const vector& AP_begin_voltage = getFeature(DoubleFeatureData, "AP_begin_voltage"); + vector AP1_begin_voltage; + AP1_begin_voltage.push_back(AP_begin_voltage[0]); + setVec(DoubleFeatureData, StringData, "AP1_begin_voltage", AP1_begin_voltage); + return 1; } int LibV5::AP2_begin_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector AP_begin_voltage, AP2_begin_voltage; - retVal = getVec(DoubleFeatureData, StringData, "AP_begin_voltage", - AP_begin_voltage); - if (retVal < 2) { - setVec(DoubleFeatureData, StringData, "AP2_begin_voltage", - AP2_begin_voltage); - return 0; + const vector& AP_begin_voltage = getFeature(DoubleFeatureData, "AP_begin_voltage"); + vector AP2_begin_voltage; + + if (AP_begin_voltage.size() < 2) { + throw FeatureComputationError("There are less than 2 spikes in the trace."); } else { AP2_begin_voltage.push_back(AP_begin_voltage[1]); - setVec(DoubleFeatureData, StringData, "AP2_begin_voltage", - AP2_begin_voltage); - return 1; } + + setVec(DoubleFeatureData, StringData, "AP2_begin_voltage", AP2_begin_voltage); + return 1; } int LibV5::AP1_begin_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector AP_begin_width, AP1_begin_width; - retVal = getVec(DoubleFeatureData, StringData, "AP_begin_width", - AP_begin_width); - if (retVal < 1) { - setVec(DoubleFeatureData, StringData, "AP1_begin_width", - AP1_begin_width); - return 0; - } else { - AP1_begin_width.push_back(AP_begin_width[0]); - setVec(DoubleFeatureData, StringData, "AP1_begin_width", - AP1_begin_width); - return 1; - } + const vector& AP_begin_width = getFeature(DoubleFeatureData, "AP_begin_width"); + vector AP1_begin_width; + AP1_begin_width.push_back(AP_begin_width[0]); + setVec(DoubleFeatureData, StringData, "AP1_begin_width", AP1_begin_width); + return 1; } int LibV5::AP2_begin_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector AP_begin_width, AP2_begin_width; - retVal = getVec(DoubleFeatureData, StringData, "AP_begin_width", - AP_begin_width); - if (retVal < 2) { - setVec(DoubleFeatureData, StringData, "AP2_begin_width", - AP2_begin_width); - return 0; + const vector& AP_begin_width = getFeature(DoubleFeatureData, "AP_begin_width"); + vector AP2_begin_width; + if (AP_begin_width.size() < 2) { + throw FeatureComputationError("There are less than 2 spikes in the trace."); } else { AP2_begin_width.push_back(AP_begin_width[1]); - setVec(DoubleFeatureData, StringData, "AP2_begin_width", - AP2_begin_width); - return 1; } + setVec(DoubleFeatureData, StringData, "AP2_begin_width", AP2_begin_width); + return 1; } // Difference amplitude of the second to first spike int LibV5::AP2_AP1_begin_width_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector AP_begin_widths, AP2_AP1_begin_width_diff; - retVal = getVec(DoubleFeatureData, StringData, "AP_begin_width", - AP_begin_widths); - if (retVal < 2) { - setVec(DoubleFeatureData, StringData, "AP2_AP1_begin_width_diff", - AP2_AP1_begin_width_diff); - return 0; + const vector& AP_begin_widths = getFeature(DoubleFeatureData, "AP_begin_width"); + vector AP2_AP1_begin_width_diff; + if (AP_begin_widths.size() < 2) { + throw FeatureComputationError("There are less than 2 spikes in the trace."); } else { AP2_AP1_begin_width_diff.push_back(AP_begin_widths[1] - AP_begin_widths[0]); } - - setVec(DoubleFeatureData, StringData, "AP2_AP1_begin_width_diff", - AP2_AP1_begin_width_diff); - + setVec(DoubleFeatureData, StringData, "AP2_AP1_begin_width_diff", AP2_AP1_begin_width_diff); return 1; } @@ -1351,23 +1137,13 @@ static int __voltage_deflection_begin(const vector& v, int LibV5::voltage_deflection_begin(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector v; - vector t; - vector stimStart; - vector stimEnd; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal < 0) return -1; - + const vector& v = getFeature(DoubleFeatureData, "V"); + const vector& t = getFeature(DoubleFeatureData, "T"); + const vector& stimStart = getFeature(DoubleFeatureData, "stim_start"); + const vector& stimEnd = getFeature(DoubleFeatureData, "stim_end"); vector vd; - retVal = __voltage_deflection_begin(v, t, stimStart[0], stimEnd[0], vd); - if (retVal >= 0) { + int retVal = __voltage_deflection_begin(v, t, stimStart[0], stimEnd[0], vd); + if (retVal > 0) { setVec(DoubleFeatureData, StringData, "voltage_deflection_begin", vd); } return retVal; @@ -1380,28 +1156,18 @@ int LibV5::voltage_deflection_begin(mapStr2intVec& IntFeatureData, int LibV5::is_not_stuck(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - vector peak_time; - vector stim_start; - vector stim_end; - retval = getVec(DoubleFeatureData, StringData, "peak_time", peak_time); - if (retval < 0) return -1; - retval = - getVec(DoubleFeatureData, StringData, "stim_start", stim_start); - if (retval < 0) return -1; - retval = getVec(DoubleFeatureData, StringData, "stim_end", stim_end); - if (retval < 0) return -1; - + const vector& peak_time = getFeature(DoubleFeatureData, "peak_time"); + const vector& stim_start = getFeature(DoubleFeatureData, "stim_start"); + const vector& stim_end = getFeature(DoubleFeatureData, "stim_end"); bool stuck = true; - for (size_t i = 0; i < peak_time.size(); i++) { - if (peak_time[i] > stim_end[0] * 0.5 && peak_time[i] < stim_end[0]) { + for (const auto& pt : peak_time) { + if (pt > stim_end[0] * 0.5 && pt < stim_end[0]) { stuck = false; break; } } - vector tc; if (!stuck) { - tc.push_back(1); + vector tc = {1}; setVec(IntFeatureData, StringData, "is_not_stuck", tc); return tc.size(); } else { @@ -1412,67 +1178,45 @@ int LibV5::is_not_stuck(mapStr2intVec& IntFeatureData, // The mean voltage after the stimulus in (stim_end + 25%*end_period, stim_end + // 75%*end_period) int LibV5::voltage_after_stim(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - vector v, t, stimEnd, vRest; - double startTime, endTime; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal < 0) return -1; - - startTime = stimEnd[0] + (t[t.size() - 1] - stimEnd[0]) * .25; - endTime = stimEnd[0] + (t[t.size() - 1] - stimEnd[0]) * .75; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const vector& v = getFeature(DoubleFeatureData, "V"); + const vector& t = getFeature(DoubleFeatureData, "T"); + const vector& stimEnd = getFeature(DoubleFeatureData, "stim_end"); + double startTime = stimEnd[0] + (t.back() - stimEnd[0]) * .25; + double endTime = stimEnd[0] + (t.back() - stimEnd[0]) * .75; int nCount = 0; double vSum = 0; - // calculte the mean of voltage between startTime and endTime + for (size_t i = 0; i < t.size(); i++) { if (t[i] >= startTime) { - vSum = vSum + v[i]; + vSum += v[i]; nCount++; } if (t[i] > endTime) break; } + if (nCount == 0) return -1; - vRest.push_back(vSum / nCount); + + vector vRest = {vSum / nCount}; setVec(DoubleFeatureData, StringData, "voltage_after_stim", vRest); + return 1; } int LibV5::mean_AP_amplitude(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector AP_amplitude; - retVal = - getVec(DoubleFeatureData, StringData, "AP_amplitude", AP_amplitude); - - if (retVal < 0) { - GErrorStr += "Error calculating AP_amplitude for mean_AP_amplitude"; - return -1; - } else if (retVal == 0) { - GErrorStr += "No spikes found when calculating mean_AP_amplitude"; - return -1; - } else if (AP_amplitude.size() == 0) { - GErrorStr += "No spikes found when calculating mean_AP_amplitude"; - return -1; - } - - vector mean_AP_amplitude; + const vector& AP_amplitude = getFeature(DoubleFeatureData, "AP_amplitude"); double mean_amp = 0.0; - - for (size_t i = 0; i < AP_amplitude.size(); i++) { - mean_amp += AP_amplitude[i]; + for (const auto& amplitude : AP_amplitude) { + mean_amp += amplitude; } mean_amp /= AP_amplitude.size(); - mean_AP_amplitude.push_back(mean_amp); + vector mean_AP_amplitude = {mean_amp}; - setVec(DoubleFeatureData, StringData, "mean_AP_amplitude", - mean_AP_amplitude); + setVec(DoubleFeatureData, StringData, "mean_AP_amplitude", mean_AP_amplitude); return mean_AP_amplitude.size(); } @@ -1516,38 +1260,21 @@ static int __AP_phaseslope(const vector& v, const vector& t, int LibV5::AP_phaseslope(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - - vector t; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - - vector stimStart; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal < 0) return -1; - - vector stimEnd; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal < 0) return -1; - - vector range_param; - retVal = getVec(DoubleFeatureData, StringData, "AP_phaseslope_range", - range_param); - if (retVal < 0) return -1; - - vector apbi; - retVal = getVec(IntFeatureData, StringData, "AP_begin_indices", apbi); - if (retVal < 0) return -1; - + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end", "AP_phaseslope_range"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices"}); vector ap_phaseslopes; - retVal = __AP_phaseslope(v, t, stimStart[0], stimEnd[0], ap_phaseslopes, apbi, - range_param[0]); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "AP_phaseslope", - ap_phaseslopes); + int retVal = __AP_phaseslope( + doubleFeatures.at("V"), + doubleFeatures.at("T"), + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], + ap_phaseslopes, + intFeatures.at("AP_begin_indices"), + doubleFeatures.at("AP_phaseslope_range")[0] + ); + + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "AP_phaseslope", ap_phaseslopes); } return retVal; } @@ -1555,15 +1282,15 @@ int LibV5::AP_phaseslope(mapStr2intVec& IntFeatureData, int LibV5::all_ISI_values(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector VecISI, pvTime; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", pvTime); - if (retVal < 2) { + const vector& peak_time = getFeature(DoubleFeatureData, "peak_time"); + if (peak_time.size() < 2) { GErrorStr += "\n Two spikes required for calculation of all_ISI_values.\n"; return -1; } - for (size_t i = 1; i < pvTime.size(); i++) { - VecISI.push_back(pvTime[i] - pvTime[i - 1]); + + vector VecISI; + for (size_t i = 1; i < peak_time.size(); i++) { + VecISI.push_back(peak_time[i] - peak_time[i - 1]); } setVec(DoubleFeatureData, StringData, "all_ISI_values", VecISI); return VecISI.size(); @@ -1573,34 +1300,12 @@ int LibV5::all_ISI_values(mapStr2intVec& IntFeatureData, int LibV5::AP_amplitude_from_voltagebase(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector peakvoltage; - vector voltage_base_vec; - double voltage_base; - retVal = getVec(DoubleFeatureData, StringData, "voltage_base", - voltage_base_vec); - if (retVal <= 0) { - GErrorStr += - "Error calculating voltage_base for AP_amplitude_from_voltagebase"; - return -1; - } else { - voltage_base = voltage_base_vec[0]; - } - retVal = - getVec(DoubleFeatureData, StringData, "peak_voltage", peakvoltage); - if (retVal <= 0) { - GErrorStr += - "Error calculating peak_voltage for AP_amplitude_from_voltagebase"; - return -1; - } - + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_base", "peak_voltage"}); vector apamplitude; - apamplitude.resize(peakvoltage.size()); - for (size_t i = 0; i < apamplitude.size(); i++) { - apamplitude[i] = peakvoltage[i] - voltage_base; + for (const auto& peak : doubleFeatures.at("peak_voltage")) { + apamplitude.push_back(peak - doubleFeatures.at("voltage_base")[0]); } - setVec(DoubleFeatureData, StringData, "AP_amplitude_from_voltagebase", - apamplitude); + setVec(DoubleFeatureData, StringData, "AP_amplitude_from_voltagebase", apamplitude); return apamplitude.size(); } @@ -1608,33 +1313,22 @@ int LibV5::AP_amplitude_from_voltagebase(mapStr2intVec& IntFeatureData, int LibV5::min_voltage_between_spikes(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector peak_indices; - vector v; - vector min_voltage_between_spikes; - retVal = getVec(IntFeatureData, StringData, "peak_indices", peak_indices); - if (retVal < 0) { - GErrorStr += - "Error calculating peak_indices for min_voltage_between_spikes"; - return -1; - } else if (retVal < 2) { - setVec(DoubleFeatureData, StringData, "min_voltage_between_spikes", - min_voltage_between_spikes); - return 0; - } + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal <= 0) { - GErrorStr += "Error getting V for min_voltage_between_spikes"; - return -1; + if (intFeatures.at("peak_indices").size() < 2) { + setVec(DoubleFeatureData, StringData, "min_voltage_between_spikes", vector()); + return 0; } - for (size_t i = 0; i < peak_indices.size() - 1; i++) { + vector min_voltage_between_spikes; + for (size_t i = 0; i < intFeatures.at("peak_indices").size() - 1; i++) { min_voltage_between_spikes.push_back(*min_element( - v.begin() + peak_indices[i], v.begin() + peak_indices[i + 1])); + doubleFeatures.at("V").begin() + intFeatures.at("peak_indices")[i], + doubleFeatures.at("V").begin() + intFeatures.at("peak_indices")[i + 1])); } - setVec(DoubleFeatureData, StringData, "min_voltage_between_spikes", - min_voltage_between_spikes); + + setVec(DoubleFeatureData, StringData, "min_voltage_between_spikes", min_voltage_between_spikes); return min_voltage_between_spikes.size(); } @@ -1642,166 +1336,122 @@ int LibV5::min_voltage_between_spikes(mapStr2intVec& IntFeatureData, int LibV5::voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) { - GErrorStr += "Error getting V for voltage"; - return -1; - } - - setVec(DoubleFeatureData, StringData, "voltage", v); - return v.size(); + const vector& v = getFeature(DoubleFeatureData, "V"); + setVec(DoubleFeatureData, StringData, "voltage", v); + return v.size(); } // return (possibly interpolate) current trace int LibV5::current(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector i; - retVal = getVec(DoubleFeatureData, StringData, "I", i); - if (retVal < 0) { - GErrorStr += "Error getting I for current"; - return -1; - } - - setVec(DoubleFeatureData, StringData, "current", i); - return i.size(); + const vector& i = getFeature(DoubleFeatureData, "I"); + setVec(DoubleFeatureData, StringData, "current", i); + return i.size(); } // return (possibly interpolate) time trace int LibV5::time(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - vector t; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) { - GErrorStr += "Error getting T for voltage"; - return -1; - } - - setVec(DoubleFeatureData, StringData, "time", t); - return t.size(); + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const vector& t = getFeature(DoubleFeatureData, "T"); + setVec(DoubleFeatureData, StringData, "time", t); + return t.size(); } // *** The average voltage during the last 90% of the stimulus duration. *** int LibV5::steady_state_voltage_stimend(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector t, v, stimEnd, stimStart, ssv; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimEnd); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal < 0) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_end", "stim_start"}); - double start_time = stimEnd[0] - 0.1 * (stimEnd[0] - stimStart[0]); - size_t start_index = - distance(t.begin(), - find_if(t.begin(), t.end(), - [start_time](double x){ return x >= start_time; })); - size_t stop_index = - distance(t.begin(), - find_if(t.begin(), t.end(), - [stimEnd](double x){ return x >= stimEnd[0]; })); + const vector& voltages = doubleFeatures.at("V"); + const vector& times = doubleFeatures.at("T"); + const double stimStart = doubleFeatures.at("stim_start")[0]; + const double stimEnd = doubleFeatures.at("stim_end")[0]; - size_t mean_size = 0; - double mean = 0.0; - for (size_t i = start_index; i < stop_index; i++) { - mean += v[i]; - mean_size++; - } + double start_time = stimEnd - 0.1 * (stimEnd - stimStart); + auto start_it = find_if(times.begin(), times.end(), [start_time](double x) { return x >= start_time; }); + auto stop_it = find_if(times.begin(), times.end(), [stimEnd](double x) { return x >= stimEnd; }); - // Check for division by zero - if (mean_size == 0) { - return -1; - } else { - mean /= mean_size; - ssv.push_back(mean); + size_t start_index = distance(times.begin(), start_it); + size_t stop_index = distance(times.begin(), stop_it); - setVec(DoubleFeatureData, StringData, "steady_state_voltage_stimend", - ssv); + double mean = accumulate(voltages.begin() + start_index, voltages.begin() + stop_index, 0.0); + size_t mean_size = stop_index - start_index; + vector ssv; + if (mean_size > 0) { + mean /= mean_size; + ssv.push_back(mean); + setVec(DoubleFeatureData, StringData, "steady_state_voltage_stimend", ssv); return 1; } + return -1; } int LibV5::voltage_base(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector v, t, stimStart, vRest, vb_start_perc_vec, vb_end_perc_vec; - double startTime, endTime, vb_start_perc, vb_end_perc; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, - "voltage_base_start_perc", vb_start_perc_vec); - if (retVal == 1) { - vb_start_perc = vb_start_perc_vec[0]; - } else { - vb_start_perc = 0.9; - } - retVal = getVec(DoubleFeatureData, StringData, "voltage_base_end_perc", - vb_end_perc_vec); - if (retVal == 1) { - vb_end_perc = vb_end_perc_vec[0]; - } else { - vb_end_perc = 1.0; - } - - startTime = stimStart[0] * vb_start_perc; - endTime = stimStart[0] * vb_end_perc; - + const vector& v = getFeature(DoubleFeatureData, "V"); + const vector& t = getFeature(DoubleFeatureData, "T"); + const vector& stimStart = getFeature(DoubleFeatureData, "stim_start"); + + // Retrieve percentage values or use defaults. + double vb_start_perc = 0.9; // Default value + double vb_end_perc = 1.0; // Default value + try { + auto vb_start_perc_vec = getFeature(DoubleFeatureData, "voltage_base_start_perc"); + if (vb_start_perc_vec.size() == 1) + vb_start_perc = vb_start_perc_vec[0]; + } catch (const EmptyFeatureError&) { + // If there's an error, use the default value. + } + + try { + auto vb_end_perc_vec = getFeature(DoubleFeatureData, "voltage_base_end_perc"); + if (vb_end_perc_vec.size() == 1) + vb_end_perc = vb_end_perc_vec[0]; + } catch (const EmptyFeatureError&) { + // If there's an error, use the default value. + } + + // Calculate start and end times based on stimStart and percentages. + double startTime = stimStart[0] * vb_start_perc; + double endTime = stimStart[0] * vb_end_perc; + + // Validate start and end times. if (startTime >= endTime) { GErrorStr += "\nvoltage_base: startTime >= endTime\n"; return -1; } + const auto& precisionThreshold = getFeature(DoubleFeatureData, "precision_threshold"); - vector precisionThreshold; - retVal = getParam(DoubleFeatureData, "precision_threshold", - precisionThreshold); - if (retVal < 0) return -1; + // Find index range for the time vector within the specified start and end times. + std::pair time_index = get_time_index(t, startTime, endTime, precisionThreshold[0]); - std::pair time_index = get_time_index(t, startTime, endTime, - precisionThreshold[0]); - - vector subVector(v.begin()+time_index.first, - v.begin()+time_index.second); + // Extract sub-vector of voltages based on calculated indices. + vector subVector(v.begin() + time_index.first, v.begin() + time_index.second); - double vBase; + // Determine computation mode and calculate voltage base. std::string computation_mode; - retVal = getStrParam(StringData, "voltage_base_mode", computation_mode); + int retVal = getStrParam(StringData, "voltage_base_mode", computation_mode); if (retVal < 0) return -1; + double vBase; - - try{ - if (computation_mode == "mean") - vBase = vec_mean(subVector); - else if (computation_mode == "median") - vBase = vec_median(subVector); - else - throw std::invalid_argument( - "Undefined computational mode. Only mean and median are enabled"); - } - catch(std::exception &e) { - GErrorStr += - "\nvoltage_base error:" + std::string(e.what()) + "\n"; + // Perform computation based on the mode. + if (computation_mode == "mean") + vBase = vec_mean(subVector); + else if (computation_mode == "median") + vBase = vec_median(subVector); + else { + GErrorStr += "\nUndefined computational mode. Only mean and median are enabled\n"; return -1; - } + } - vRest.push_back(vBase); + vector vRest = {vBase}; setVec(DoubleFeatureData, StringData, "voltage_base", vRest); return 1; } @@ -1989,57 +1639,38 @@ int LibV5::decay_time_constant_after_stim(mapStr2intVec& IntFeatureData, // Calculate the time constants after each step for a stimuli containing several // steps, as for example SpikeRec protocols int LibV5::multiple_decay_time_constant_after_stim(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - vector voltages; - retVal = getVec(DoubleFeatureData, StringData, "V", voltages); - if (retVal < 0) return -1; - - vector times; - retVal = getVec(DoubleFeatureData, StringData, "T", times); - if (retVal < 0) return -1; - - vector vect; - retVal = getVec(DoubleFeatureData, StringData, "multi_stim_end", vect); - if (retVal < 0) return -1; - vector stimsEnd = vect; - - retVal = getVec(DoubleFeatureData, StringData, "multi_stim_start", vect); - if (retVal < 0) return -1; - vector stimsStart = vect; - - double decay_start_after_stim, decay_end_after_stim; - retVal = getVec(DoubleFeatureData, StringData, "decay_start_after_stim", - vect); - if (retVal == 1) { - decay_start_after_stim = vect[0]; - } else { - decay_start_after_stim = 1.0; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "multi_stim_start", "multi_stim_end"}); + vector stimsEnd, stimsStart; + + stimsEnd = doubleFeatures.at("multi_stim_end"); + stimsStart = doubleFeatures.at("multi_stim_start"); + + // Attempt to get decay parameters, using defaults if not found or if not exactly one element + double decay_start_after_stim = 1.0; + double decay_end_after_stim = 10.0; + vector decayStartVec, decayEndVec; + + if (getVec(DoubleFeatureData, StringData, "decay_start_after_stim", decayStartVec) == 1) { + decay_start_after_stim = decayStartVec[0]; } - - retVal = - getVec(DoubleFeatureData, StringData, "decay_end_after_stim", vect); - if (retVal == 1) { - decay_end_after_stim = vect[0]; - } else { - decay_end_after_stim = 10.0; + if (getVec(DoubleFeatureData, StringData, "decay_end_after_stim", decayEndVec) == 1) { + decay_end_after_stim = decayEndVec[0]; } - - // Call the decay_time_constant_after_stim for each set of stim_start - // and stim_end - double ret_dtcas; vector dtcas; for (size_t i = 0; i < stimsStart.size(); i++) { - ret_dtcas = __decay_time_constant_after_stim(times, voltages, - decay_start_after_stim, decay_end_after_stim, stimsStart[i], - stimsEnd[i]); + double ret_dtcas = __decay_time_constant_after_stim( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + decay_start_after_stim, + decay_end_after_stim, + stimsStart[i], + stimsEnd[i] + ); dtcas.push_back(ret_dtcas); } - - setVec(DoubleFeatureData, StringData, "multiple_decay_time_constant_after_stim", - dtcas); - + setVec(DoubleFeatureData, StringData, "multiple_decay_time_constant_after_stim", dtcas); return 1; } @@ -2106,85 +1737,36 @@ static int __sag_time_constant(const vector& times, int LibV5::sag_time_constant(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector voltages; - retVal = getVec(DoubleFeatureData, StringData, "V", voltages); - if (retVal < 0) return -1; - - vector times; - retVal = getVec(DoubleFeatureData, StringData, "T", times); - if (retVal < 0) return -1; - - vector vect; - - retVal = getVec(DoubleFeatureData, StringData, "stim_end", vect); - if (retVal != 1) return -1; - const double stimEnd = vect[0]; - - retVal = getVec(DoubleFeatureData, StringData, "stim_start", vect); - if (retVal != 1) return -1; - const double stimStart = vect[0]; - - vector minimum_voltage; - retVal = getVec(DoubleFeatureData, StringData, - "minimum_voltage", - minimum_voltage); - if (retVal <= 0) return -1; - - vector steady_state_v; - retVal = getVec(DoubleFeatureData, StringData, - "steady_state_voltage_stimend", - steady_state_v); - if (retVal <= 0) return -1; - - vector sag_amplitude; - retVal = getVec(DoubleFeatureData, StringData, - "sag_amplitude", - sag_amplitude); - if (retVal <= 0) return -1; - + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_end", "stim_start", "minimum_voltage", "steady_state_voltage_stimend", "sag_amplitude"}); vector sagtc; - retVal = __sag_time_constant( - times, voltages, - minimum_voltage[0], - steady_state_v[0], - sag_amplitude[0], - stimStart, stimEnd, sagtc); + int retVal = __sag_time_constant( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + doubleFeatures.at("minimum_voltage")[0], + doubleFeatures.at("steady_state_voltage_stimend")[0], + doubleFeatures.at("sag_amplitude")[0], + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], + sagtc + ); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "sag_time_constant", - sagtc); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "sag_time_constant", sagtc); } return retVal; } /// *** Voltage deflection between voltage_base and steady_state_voltage_stimend - int LibV5::voltage_deflection_vb_ssse(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector voltage_base; - retVal = - getVec(DoubleFeatureData, StringData, "voltage_base", voltage_base); - if (retVal <= 0) return -1; - - vector steady_state_voltage_stimend; - retVal = getVec(DoubleFeatureData, StringData, - "steady_state_voltage_stimend", - steady_state_voltage_stimend); - if (retVal <= 0) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_base", "steady_state_voltage_stimend"}); vector voltage_deflection_vb_ssse; - - voltage_deflection_vb_ssse.push_back(steady_state_voltage_stimend[0] - - voltage_base[0]); - - setVec(DoubleFeatureData, StringData, "voltage_deflection_vb_ssse", - voltage_deflection_vb_ssse); - retVal = 1; - - return retVal; + voltage_deflection_vb_ssse.push_back(doubleFeatures.at("steady_state_voltage_stimend")[0] - + doubleFeatures.at("voltage_base")[0]); + setVec(DoubleFeatureData, StringData, "voltage_deflection_vb_ssse", voltage_deflection_vb_ssse); + return 1; } // *** ohmic input resistance based on voltage_deflection_vb_ssse*** @@ -2192,53 +1774,26 @@ int LibV5::voltage_deflection_vb_ssse(mapStr2intVec& IntFeatureData, int LibV5::ohmic_input_resistance_vb_ssse(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector voltage_deflection_vb_ssse; - retVal = - getVec(DoubleFeatureData, StringData, "voltage_deflection_vb_ssse", - voltage_deflection_vb_ssse); - if (retVal <= 0) return -1; - vector stimulus_current; - retVal = getParam(DoubleFeatureData, "stimulus_current", - stimulus_current); - - if (retVal <= 0) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_deflection_vb_ssse", "stimulus_current"}); vector ohmic_input_resistance_vb_ssse; + ohmic_input_resistance_vb_ssse.push_back(doubleFeatures.at("voltage_deflection_vb_ssse")[0] / + doubleFeatures.at("stimulus_current")[0]); + setVec(DoubleFeatureData, StringData, "ohmic_input_resistance_vb_ssse", ohmic_input_resistance_vb_ssse); - ohmic_input_resistance_vb_ssse.push_back(voltage_deflection_vb_ssse[0] / - stimulus_current[0]); - setVec(DoubleFeatureData, StringData, "ohmic_input_resistance_vb_ssse", - ohmic_input_resistance_vb_ssse); - retVal = 1; - - return retVal; + return 1; } // *** Diff between maximum voltage during stimulus and voltage_base *** int LibV5::maximum_voltage_from_voltagebase(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector maximum_voltage; - retVal = getVec(DoubleFeatureData, StringData, "maximum_voltage", - maximum_voltage); - if (retVal <= 0) return -1; - - vector voltage_base; - retVal = - getVec(DoubleFeatureData, StringData, "voltage_base", voltage_base); - if (retVal <= 0) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"maximum_voltage", "voltage_base"}); vector maximum_voltage_from_voltagebase; - - maximum_voltage_from_voltagebase.push_back(maximum_voltage[0] - - voltage_base[0]); - setVec(DoubleFeatureData, StringData, - "maximum_voltage_from_voltagebase", - maximum_voltage_from_voltagebase); - retVal = 1; - - return retVal; + maximum_voltage_from_voltagebase.push_back(doubleFeatures.at("maximum_voltage")[0] - + doubleFeatures.at("voltage_base")[0]); + setVec(DoubleFeatureData, StringData, "maximum_voltage_from_voltagebase", maximum_voltage_from_voltagebase); + return 1; } struct InInterval { @@ -2251,50 +1806,23 @@ struct InInterval { double lower, upper; }; -// *** Spikecount_stimint *** int LibV5::Spikecount_stimint(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retval; - int spikecount_stimint_value; - // Get stimulus start - vector stimstart; - retval = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retval <= 0) { - GErrorStr += "\nSpikecount_stimint: stim_start not found\n"; - return -1; - } + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"stim_start", "stim_end", "peak_time"}); - // Get stimulus end - vector stimend; - retval = getVec(DoubleFeatureData, StringData, "stim_end", stimend); - if (retval <= 0) { - GErrorStr += "\nSpikecount_stimint: stim_start not found\n"; - return -1; - } + // Get the number of peaks between stim start and end + int spikecount_stimint_value = count_if(doubleFeatures.at("peak_time").begin(), doubleFeatures.at("peak_time").end(), + InInterval(doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0])); - // Get the times of the peaks - vector peaktimes; - retval = getVec(DoubleFeatureData, StringData, "peak_time", peaktimes); + vector spikecount_stimint(1, spikecount_stimint_value); + setVec(IntFeatureData, StringData, "Spikecount_stimint", spikecount_stimint); - if (retval < 0) { - GErrorStr += "\nSpikecount_stimint: peak_time failed\n"; - return -1; - } else { - // Get the number of peaks between stim start and end - spikecount_stimint_value = count_if(peaktimes.begin(), peaktimes.end(), - InInterval(stimstart[0], stimend[0])); - - vector spikecount_stimint(1, spikecount_stimint_value); - setVec(IntFeatureData, StringData, "Spikecount_stimint", - spikecount_stimint); - return 1; - } + return 1; } -// end of Spikecount_stimint -static int __peak_indices(double threshold, vector& V, - vector& t, vector& PeakIndex, +static int __peak_indices(double threshold, const vector& V, + const vector& t, vector& PeakIndex, bool strict_stiminterval, double stim_start, double stim_end) { vector upVec, dnVec; @@ -2364,193 +1892,94 @@ static int __peak_indices(double threshold, vector& V, int LibV5::peak_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector PeakIndex, strict_stiminterval_vec; - vector v, t, threshold, stim_start_vec, stim_end_vec; - bool strict_stiminterval = false; - double stim_start = 0.0, stim_end = 0.0; - - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal <= 0) { - return -1; - } - - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal <= 0) { - return -1; - } - - retVal = getParam(DoubleFeatureData, "Threshold", threshold); - if (retVal <= 0) { - return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "Threshold", "stim_start", "stim_end"}); + bool strict_stiminterval; + try{ + const auto& intFeatures = getFeatures(IntFeatureData, {"strict_stiminterval"}); + strict_stiminterval = bool(intFeatures.at("strict_stiminterval")[0]); } - - retVal = getParam(IntFeatureData, "strict_stiminterval", - strict_stiminterval_vec); - if (retVal <= 0) { + catch (const std::runtime_error& e) { strict_stiminterval = false; - } else { - strict_stiminterval = bool(strict_stiminterval_vec[0]); - } - - retVal = - getVec(DoubleFeatureData, StringData, "stim_start", stim_start_vec); - if (retVal <= 0) { - return -1; - } else { - stim_start = stim_start_vec[0]; } + vector PeakIndex; + int retVal = __peak_indices( + doubleFeatures.at("Threshold")[0], + doubleFeatures.at("V"), + doubleFeatures.at("T"), + PeakIndex, + strict_stiminterval, + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0] + ); - retVal = - getVec(DoubleFeatureData, StringData, "stim_end", stim_end_vec); - if (retVal <= 0) { - return -1; - } else { - stim_end = stim_end_vec[0]; - } - - int retval = __peak_indices(threshold[0], v, t, PeakIndex, - strict_stiminterval, stim_start, stim_end); - - if (retval >= 0) { + if (retVal >= 0) { setVec(IntFeatureData, StringData, "peak_indices", PeakIndex); } - - return retval; + return retVal; } + int LibV5::sag_amplitude(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - // Get steady_state_voltage_stimend - vector steady_state_voltage_stimend; - retVal = - getVec(DoubleFeatureData, StringData, - "steady_state_voltage_stimend", - steady_state_voltage_stimend); - if (retVal <= 0) return -1; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"steady_state_voltage_stimend", "voltage_deflection_vb_ssse", "minimum_voltage"}); - // Get voltage_deflection_stim_ssse - double voltage_deflection_stim_ssse = 0.0; - vector voltage_deflection_vb_ssse_vec; - retVal = - getVec(DoubleFeatureData, StringData, - "voltage_deflection_vb_ssse", - voltage_deflection_vb_ssse_vec); - if (retVal <= 0) { - return -1; - } else { - voltage_deflection_stim_ssse = voltage_deflection_vb_ssse_vec[0]; - } - - // Get minimum_voltage - vector minimum_voltage; - retVal = - getVec(DoubleFeatureData, StringData, - "minimum_voltage", - minimum_voltage); - if (retVal <= 0) return -1; - - // Calculate sag_amplitude vector sag_amplitude; - if (voltage_deflection_stim_ssse <= 0) { - sag_amplitude.push_back(steady_state_voltage_stimend[0] - - minimum_voltage[0]); + if (doubleFeatures.at("voltage_deflection_vb_ssse")[0] <= 0) { + sag_amplitude.push_back(doubleFeatures.at("steady_state_voltage_stimend")[0] - doubleFeatures.at("minimum_voltage")[0]); } else { - //In case of positive voltage deflection, return an error - GErrorStr += "\nsag_amplitude: voltage_deflection is positive\n"; - return -1; + //In case of positive voltage deflection, return an error + GErrorStr += "\nsag_amplitude: voltage_deflection is positive\n"; + return -1; } - setVec(DoubleFeatureData, StringData, "sag_amplitude", - sag_amplitude); - retVal = 1; - return retVal; + + if (!sag_amplitude.empty()) { + setVec(DoubleFeatureData, StringData, "sag_amplitude", sag_amplitude); + } + return sag_amplitude.empty() ? -1 : 1; } int LibV5::sag_ratio1(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - // Get sag_amplitude - vector sag_amplitude; - retVal = - getVec(DoubleFeatureData, StringData, - "sag_amplitude", - sag_amplitude); - if (retVal <= 0) return -1; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + // Retrieve all required double features at once + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"sag_amplitude", "voltage_base", "minimum_voltage"}); - // Get voltage_base - vector voltage_base; - retVal = - getVec(DoubleFeatureData, StringData, - "voltage_base", - voltage_base); - if (retVal <= 0) {return -1;} - - // Get minimum_voltage - vector minimum_voltage; - retVal = - getVec(DoubleFeatureData, StringData, - "minimum_voltage", - minimum_voltage); - if (retVal <= 0) return -1; - - // Calculate sag_ratio1 vector sag_ratio1; - if (minimum_voltage[0] == voltage_base[0]) { - GErrorStr += "\nsag_ratio1: voltage_base equals minimum_voltage\n"; - //In case of possible division by zero return error - return -1; + if (doubleFeatures.at("minimum_voltage")[0] == doubleFeatures.at("voltage_base")[0]) { + GErrorStr += "\nsag_ratio1: voltage_base equals minimum_voltage\n"; + //In case of possible division by zero return error + return -1; } else { - sag_ratio1.push_back(sag_amplitude[0] / (voltage_base[0] - minimum_voltage[0])); + sag_ratio1.push_back(doubleFeatures.at("sag_amplitude")[0] / + (doubleFeatures.at("voltage_base")[0] - doubleFeatures.at("minimum_voltage")[0])); } - setVec(DoubleFeatureData, StringData, "sag_ratio1", - sag_ratio1); - retVal = 1; - return retVal; + + if (!sag_ratio1.empty()) { + setVec(DoubleFeatureData, StringData, "sag_ratio1", sag_ratio1); + } + return sag_ratio1.empty() ? -1 : 1; } int LibV5::sag_ratio2(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - // Get voltage_base - vector voltage_base; - retVal = - getVec(DoubleFeatureData, StringData, - "voltage_base", - voltage_base); - if (retVal <= 0) {return -1;} - - // Get minimum_voltage - vector minimum_voltage; - retVal = - getVec(DoubleFeatureData, StringData, - "minimum_voltage", - minimum_voltage); - if (retVal <= 0) return -1; - - // Get steady_state_voltage_stimend - vector steady_state_voltage_stimend; - retVal = - getVec(DoubleFeatureData, StringData, - "steady_state_voltage_stimend", - steady_state_voltage_stimend); - if (retVal <= 0) return -1; - - // Calculate sag_ratio2 + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + // Retrieve all required double features at once + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_base", "minimum_voltage", "steady_state_voltage_stimend"}); + vector sag_ratio2; - if (minimum_voltage[0] == voltage_base[0]) { - GErrorStr += "\nsag_ratio2: voltage_base equals minimum_voltage\n"; - //In case of possible division by zero return error - return -1; + if (doubleFeatures.at("minimum_voltage")[0] == doubleFeatures.at("voltage_base")[0]) { + GErrorStr += "\nsag_ratio2: voltage_base equals minimum_voltage\n"; + //In case of possible division by zero return error + return -1; } else { - sag_ratio2.push_back((voltage_base[0] - steady_state_voltage_stimend[0]) / (voltage_base[0] - minimum_voltage[0])); + sag_ratio2.push_back((doubleFeatures.at("voltage_base")[0] - doubleFeatures.at("steady_state_voltage_stimend")[0]) / + (doubleFeatures.at("voltage_base")[0] - doubleFeatures.at("minimum_voltage")[0])); } - setVec(DoubleFeatureData, StringData, "sag_ratio2", - sag_ratio2); - retVal = 1; - return retVal; + + if (!sag_ratio2.empty()) { + setVec(DoubleFeatureData, StringData, "sag_ratio2", sag_ratio2); + } + return sag_ratio2.empty() ? -1 : 1; } @@ -2593,28 +2022,19 @@ static int __AP_peak_upstroke(const vector& t, const vector& v, int LibV5::AP_peak_upstroke(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - // Get input parameters - vector t; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - vector apbi; - retVal = getVec(IntFeatureData, StringData, "AP_begin_indices", apbi); - if (retVal < 0) return -1; - vector pi; - retVal = getVec(IntFeatureData, StringData, "peak_indices", pi); - if (retVal < 0) return -1; - vector pus; + // Retrieve all required double and int features at once + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "peak_indices"}); - - // Calculate feature - retVal = - __AP_peak_upstroke(t, v, pi, apbi, pus); + vector pus; + int retVal = __AP_peak_upstroke( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + intFeatures.at("peak_indices"), + intFeatures.at("AP_begin_indices"), + pus + ); - // Save feature value if (retVal >= 0) { setVec(DoubleFeatureData, StringData, "AP_peak_upstroke", pus); } @@ -2645,30 +2065,20 @@ static int __AP_peak_downstroke(const vector& t, const vector& v } int LibV5::AP_peak_downstroke(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - // Get input parameters - vector t; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - vector ahpi; - retVal = getVec(IntFeatureData, StringData, "min_AHP_indices", ahpi); - if (retVal < 0) return -1; - vector pi; - retVal = getVec(IntFeatureData, StringData, "peak_indices", pi); - if (retVal < 0) return -1; - vector pds; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); - - // Calculate feature - retVal = - __AP_peak_downstroke(t, v, pi, ahpi, pds); + vector pds; + int retVal = __AP_peak_downstroke( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + intFeatures.at("peak_indices"), + intFeatures.at("min_AHP_indices"), + pds + ); - // Save feature value if (retVal >= 0) { setVec(DoubleFeatureData, StringData, "AP_peak_downstroke", pds); } @@ -2716,68 +2126,28 @@ static int __min_between_peaks_indices(const vector& t, const vector min_btw_peaks_indices, strict_stiminterval_vec, peak_indices; - vector v, t, stim_start_vec, stim_end_vec, min_btw_peaks_values; - bool strict_stiminterval; - - // Get voltage - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal <= 0) return -1; - - // Get time - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal <= 0) return -1; - - // Get peak_indices - retVal = getVec(IntFeatureData, StringData, "peak_indices", peak_indices); - if (retVal < 1) { - GErrorStr += - "\n At least one spike required for calculation of " - "min_between_peaks_indices.\n"; - return -1; - } - - // Get strict_stiminterval - retVal = getParam(IntFeatureData, "strict_stiminterval", - strict_stiminterval_vec); - if (retVal <= 0) { - strict_stiminterval = false; - } else { - strict_stiminterval = bool(strict_stiminterval_vec[0]); - } - - // Get stim_start - retVal = - getVec(DoubleFeatureData, StringData, "stim_start", stim_start_vec); - if (retVal <= 0) { - return -1; - } else { - stim_start = stim_start_vec[0]; - } - - /// Get stim_end - retVal = - getVec(DoubleFeatureData, StringData, "stim_end", stim_end_vec); - if (retVal <= 0) { - return -1; - } else { - stim_end = stim_end_vec[0]; - } - - retVal = - __min_between_peaks_indices(t, v, peak_indices, stim_start, stim_end, - strict_stiminterval, min_btw_peaks_indices, min_btw_peaks_values); + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + // Retrieve all required double and int features at once + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "stim_start", "stim_end"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "strict_stiminterval"}); + + vector min_btw_peaks_indices; + vector min_btw_peaks_values; + int retVal = __min_between_peaks_indices( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + intFeatures.at("peak_indices"), + doubleFeatures.at("stim_start").front(), + doubleFeatures.at("stim_end").front(), + intFeatures.at("strict_stiminterval").empty() ? false : intFeatures.at("strict_stiminterval").front(), + min_btw_peaks_indices, + min_btw_peaks_values + ); - if (retVal == 0) - return -1; if (retVal > 0) { setVec(IntFeatureData, StringData, "min_between_peaks_indices", min_btw_peaks_indices); - setVec(DoubleFeatureData, StringData, "min_between_peaks_values", - min_btw_peaks_values); + setVec(DoubleFeatureData, StringData, "min_between_peaks_values", min_btw_peaks_values); } return retVal; } @@ -2821,30 +2191,23 @@ static int __AP_width_between_threshold(const vector& t, const vector t; - retval = getVec(DoubleFeatureData, StringData, "T", t); - if (retval < 0) return -1; - vector v; - retval = getVec(DoubleFeatureData, StringData, "V", v); - if (retval < 0) return -1; - vector threshold; - retval = getParam(DoubleFeatureData, "Threshold", threshold); - if (retval < 0) return -1; - vector stimstart; - retval = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retval < 0) return -1; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + // Retrieve all required double and int features at once + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "Threshold", "stim_start"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"min_between_peaks_indices"}); - vector min_between_peaks_indices; - retval = getVec(IntFeatureData, StringData, "min_between_peaks_indices", min_between_peaks_indices); - if (retval < 0) return -1; vector ap_width_threshold; - retval = __AP_width_between_threshold(t, v, stimstart[0], threshold[0], - min_between_peaks_indices, ap_width_threshold); + int retval = __AP_width_between_threshold( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + doubleFeatures.at("stim_start").front(), + doubleFeatures.at("Threshold").front(), + intFeatures.at("min_between_peaks_indices"), + ap_width_threshold + ); if (retval == 0) - return -1; + throw EmptyFeatureError("AP_width_between_threshold is empty"); else if (retval > 0) { setVec(DoubleFeatureData, StringData, "AP_width_between_threshold", ap_width_threshold); } @@ -2950,9 +2313,9 @@ int LibV5::burst_end_indices(mapStr2intVec& IntFeatureData, } -static int __strict_burst_mean_freq(vector& PVTime, - vector& burst_begin_indices, - vector& burst_end_indices, +static int __strict_burst_mean_freq(const vector& PVTime, + const vector& burst_begin_indices, + const vector& burst_end_indices, vector& BurstMeanFreq) { if (burst_begin_indices.size() == 0) return BurstMeanFreq.size(); double span; @@ -2969,25 +2332,22 @@ static int __strict_burst_mean_freq(vector& PVTime, } int LibV5::strict_burst_mean_freq(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - vector burst_begin_indices, burst_end_indices; - vector BurstMeanFreq, PVTime; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", PVTime); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "burst_begin_indices", - burst_begin_indices); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "burst_end_indices", - burst_end_indices); - if (retVal < 0) return -1; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + // Retrieve all required double and int features at once + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"burst_begin_indices", "burst_end_indices"}); + + vector BurstMeanFreq; + int retVal = __strict_burst_mean_freq( + doubleFeatures.at("peak_time"), + intFeatures.at("burst_begin_indices"), + intFeatures.at("burst_end_indices"), + BurstMeanFreq + ); - retVal = __strict_burst_mean_freq(PVTime, burst_begin_indices, - burst_end_indices, BurstMeanFreq); if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "strict_burst_mean_freq", - BurstMeanFreq); + setVec(DoubleFeatureData, StringData, "strict_burst_mean_freq", BurstMeanFreq); } return retVal; } @@ -2995,22 +2355,17 @@ int LibV5::strict_burst_mean_freq(mapStr2intVec& IntFeatureData, int LibV5::strict_burst_number(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector BurstMeanFreq; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"strict_burst_mean_freq"}); vector BurstNum; - retVal = getVec(DoubleFeatureData, StringData, - "strict_burst_mean_freq", BurstMeanFreq); - if (retVal < 0) return -1; - - BurstNum.push_back(BurstMeanFreq.size()); + BurstNum.push_back(doubleFeatures.at("strict_burst_mean_freq").size()); setVec(IntFeatureData, StringData, "strict_burst_number", BurstNum); - return (BurstNum.size()); + return BurstNum.size(); } -static int __strict_interburst_voltage(vector& burst_begin_indices, - vector& PeakIndex, - vector& T, vector& V, +static int __strict_interburst_voltage(const vector& burst_begin_indices, + const vector& PeakIndex, + const vector& T, const vector& V, vector& IBV) { if (burst_begin_indices.size() < 1) return 0; int j, pIndex, tsIndex, teIndex, cnt; @@ -3043,21 +2398,18 @@ static int __strict_interburst_voltage(vector& burst_begin_indices, int LibV5::strict_interburst_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector burst_begin_indices, PeakIndex; - vector V, T, IBV; - retVal = getVec(IntFeatureData, StringData, "peak_indices", PeakIndex); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", T); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "burst_begin_indices", - burst_begin_indices); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "V", V); - if (retVal < 0) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "burst_begin_indices"}); + vector IBV; + int retVal = __strict_interburst_voltage( + intFeatures.at("burst_begin_indices"), + intFeatures.at("peak_indices"), + doubleFeatures.at("T"), + doubleFeatures.at("V"), + IBV + ); - retVal = __strict_interburst_voltage(burst_begin_indices, PeakIndex, T, V, IBV); - if (retVal >= 0) { + if (retVal > 0) { setVec(DoubleFeatureData, StringData, "strict_interburst_voltage", IBV); } return retVal; @@ -3065,9 +2417,9 @@ int LibV5::strict_interburst_voltage(mapStr2intVec& IntFeatureData, // strict_stiminterval should be True when using this feature -static int __ADP_peak_indices(vector& v, - vector& min_AHP_indices, - vector& min_between_peaks_indices, +static int __ADP_peak_indices(const vector& v, + const vector& min_AHP_indices, + const vector& min_between_peaks_indices, vector& ADP_peak_indices, vector& ADP_peak_values) { if (min_AHP_indices.size() > min_between_peaks_indices.size()){ @@ -3091,65 +2443,57 @@ static int __ADP_peak_indices(vector& v, // strict_stiminterval should be True when using this feature int LibV5::ADP_peak_indices(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - vector min_AHP_indices, min_between_peaks_indices, ADP_peak_indices; - vector ADP_peak_values, v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal <= 0) return -1; - retVal = getVec(IntFeatureData, StringData, "min_AHP_indices", - min_AHP_indices); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "min_between_peaks_indices", - min_between_peaks_indices); - if (retVal < 0) return -1; - - retVal = __ADP_peak_indices(v, min_AHP_indices, min_between_peaks_indices, - ADP_peak_indices, ADP_peak_values); - if (retVal >= 0) { - setVec(IntFeatureData, StringData, "ADP_peak_indices", - ADP_peak_indices); - setVec(DoubleFeatureData, StringData, "ADP_peak_values", - ADP_peak_values); + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "min_between_peaks_indices"}); + vector ADP_peak_indices; + vector ADP_peak_values; + int retVal = __ADP_peak_indices(doubleFeatures.at("V"), + intFeatures.at("min_AHP_indices"), + intFeatures.at("min_between_peaks_indices"), + ADP_peak_indices, + ADP_peak_values); + if (retVal > 0) { + setVec(IntFeatureData, StringData, "ADP_peak_indices", ADP_peak_indices); + setVec(DoubleFeatureData, StringData, "ADP_peak_values", ADP_peak_values); } return retVal; } // strict_stiminterval should be True when using this feature int LibV5::ADP_peak_values(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - return 1; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { +return 1; } // strict_stiminterval should be True when using this feature int LibV5::ADP_peak_amplitude(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - int retVal; - vector ADP_peak_amplitude, min_AHP_values, ADP_peak_values; - retVal = getVec(DoubleFeatureData, StringData, "min_AHP_values", - min_AHP_values); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "ADP_peak_values", - ADP_peak_values); - if (retVal < 0) return -1; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"min_AHP_values", "ADP_peak_values"}); + vector ADP_peak_amplitude; + const vector& min_AHP_values = doubleFeatures.at("min_AHP_values"); + const vector& ADP_peak_values = doubleFeatures.at("ADP_peak_values"); + if (min_AHP_values.size() != ADP_peak_values.size()){ + GErrorStr += + "\nmin_AHP_values and ADP_peak_values should have the same number of elements\n"; + return -1; + } for (size_t i = 0; i < ADP_peak_values.size(); i++) { ADP_peak_amplitude.push_back(ADP_peak_values[i] - min_AHP_values[i]); } - setVec(DoubleFeatureData, StringData, "ADP_peak_amplitude", - ADP_peak_amplitude); - return (ADP_peak_amplitude.size()); + setVec(DoubleFeatureData, StringData, "ADP_peak_amplitude", ADP_peak_amplitude); + return ADP_peak_amplitude.size(); } - -static int __interburst_min_indices(vector& v, - vector& peak_indices, - vector& burst_end_indices, +static int __interburst_min_indices(const vector& v, + const vector& peak_indices, + const vector& burst_end_indices, vector& interburst_min_indices, vector& interburst_min_values) { unsigned interburst_min_index; @@ -3164,33 +2508,29 @@ static int __interburst_min_indices(vector& v, interburst_min_indices.push_back(interburst_min_index); interburst_min_values.push_back(v[interburst_min_index]); } - return interburst_min_indices.size(); } int LibV5::interburst_min_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector peak_indices, burst_end_indices, interburst_min_indices; - vector interburst_min_values, v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal <= 0) return -1; - retVal = getVec(IntFeatureData, StringData, "peak_indices", - peak_indices); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "burst_end_indices", - burst_end_indices); - if (retVal < 0) return -1; - - retVal = __interburst_min_indices(v, peak_indices, burst_end_indices, - interburst_min_indices, - interburst_min_values); - if (retVal >= 0) { - setVec(IntFeatureData, StringData, "interburst_min_indices", - interburst_min_indices); - setVec(DoubleFeatureData, StringData, "interburst_min_values", - interburst_min_values); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "burst_end_indices"}); + vector interburst_min_indices; + vector interburst_min_values; + const vector& v = doubleFeatures.at("V"); + const vector& peak_indices = intFeatures.at("peak_indices"); + const vector& burst_end_indices = intFeatures.at("burst_end_indices"); + int retVal = __interburst_min_indices( + v, + peak_indices, + burst_end_indices, + interburst_min_indices, + interburst_min_values + ); + if (retVal > 0) { + setVec(IntFeatureData, StringData, "interburst_min_indices", interburst_min_indices); + setVec(DoubleFeatureData, StringData, "interburst_min_values", interburst_min_values); } return retVal; } @@ -3202,10 +2542,10 @@ int LibV5::interburst_min_values(mapStr2intVec& IntFeatureData, } -static int __postburst_min_indices(vector& t, - vector& v, - vector& peak_indices, - vector& burst_end_indices, +static int __postburst_min_indices(const vector& t, + const vector& v, + const vector& peak_indices, + const vector& burst_end_indices, vector& postburst_min_indices, vector& postburst_min_values, const double stim_end) { @@ -3240,37 +2580,23 @@ static int __postburst_min_indices(vector& t, int LibV5::postburst_min_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - double stim_end; - vector peak_indices, burst_end_indices, postburst_min_indices; - vector postburst_min_values, t, v, stim_end_vec; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal <= 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal <= 0) return -1; - retVal = getVec(IntFeatureData, StringData, "peak_indices", - peak_indices); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "burst_end_indices", - burst_end_indices); - if (retVal < 0) return -1; - retVal = - getVec(DoubleFeatureData, StringData, "stim_end", stim_end_vec); - if (retVal <= 0) { - return -1; - } else { - stim_end = stim_end_vec[0]; - } - - retVal = __postburst_min_indices(t, v, peak_indices, burst_end_indices, - postburst_min_indices, - postburst_min_values, - stim_end); - if (retVal >= 0) { - setVec(IntFeatureData, StringData, "postburst_min_indices", - postburst_min_indices); - setVec(DoubleFeatureData, StringData, "postburst_min_values", - postburst_min_values); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "stim_end"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "burst_end_indices"}); + vector postburst_min_indices; + vector postburst_min_values; + double stim_end = doubleFeatures.at("stim_end").front(); + int retVal = __postburst_min_indices( + doubleFeatures.at("T"), + doubleFeatures.at("V"), + intFeatures.at("peak_indices"), + intFeatures.at("burst_end_indices"), + postburst_min_indices, + postburst_min_values, + stim_end + ); + if (retVal > 0) { + setVec(IntFeatureData, StringData, "postburst_min_indices", postburst_min_indices); + setVec(DoubleFeatureData, StringData, "postburst_min_values", postburst_min_values); } return retVal; } @@ -3285,33 +2611,27 @@ int LibV5::postburst_min_values(mapStr2intVec& IntFeatureData, int LibV5::time_to_interburst_min(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector time_to_interburst_min, peak_time, time; - vector interburst_min_indices, burst_end_indices; - retVal = getVec(DoubleFeatureData, StringData, "T", - time); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "peak_time", - peak_time); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "burst_end_indices", - burst_end_indices); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "interburst_min_indices", - interburst_min_indices); - if (retVal < 0) return -1; + // Retrieve all required double and int features at once + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "peak_time"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"burst_end_indices", "interburst_min_indices"}); + + vector time_to_interburst_min; + const vector& time = doubleFeatures.at("T"); + const vector& peak_time = doubleFeatures.at("peak_time"); + const vector& burst_end_indices = intFeatures.at("burst_end_indices"); + const vector& interburst_min_indices = intFeatures.at("interburst_min_indices"); if (burst_end_indices.size() < interburst_min_indices.size()){ GErrorStr += "\nburst_end_indices should not have less elements than interburst_min_indices\n"; return -1; - } +} for (size_t i = 0; i < interburst_min_indices.size(); i++) { time_to_interburst_min.push_back(time[interburst_min_indices[i]] - - peak_time[burst_end_indices[i]]); + peak_time[burst_end_indices[i]]); } - setVec(DoubleFeatureData, StringData, "time_to_interburst_min", - time_to_interburst_min); - return (time_to_interburst_min.size()); + + setVec(DoubleFeatureData, StringData, "time_to_interburst_min", time_to_interburst_min); + return time_to_interburst_min.size(); } diff --git a/efel/cppcore/Utils.cpp b/efel/cppcore/Utils.cpp index 781fb3e5..52738d58 100644 --- a/efel/cppcore/Utils.cpp +++ b/efel/cppcore/Utils.cpp @@ -175,7 +175,7 @@ slope_straight_line_fit(const vector& x, return result; } -std::pair get_time_index(std::vector &t, double startTime, +std::pair get_time_index(const std::vector &t, double startTime, double endTime, double precisionThreshold) { /* * Returns the start and end index of the time array diff --git a/efel/cppcore/Utils.h b/efel/cppcore/Utils.h index ad7784ed..3652c49c 100644 --- a/efel/cppcore/Utils.h +++ b/efel/cppcore/Utils.h @@ -57,7 +57,7 @@ double vec_median(vector v); template double vec_mean(const vector &v); -std::pair get_time_index(std::vector &t, double startTime, +std::pair get_time_index(const std::vector &t, double startTime, double endTime, double precisionThreshold); template diff --git a/efel/cppcore/mapoperations.cpp b/efel/cppcore/mapoperations.cpp index 84adf223..60a5ab6b 100644 --- a/efel/cppcore/mapoperations.cpp +++ b/efel/cppcore/mapoperations.cpp @@ -40,6 +40,19 @@ std::map> getFeatures( return selectedFeatures; } +template +std::vector getFeature( + const std::map>& allFeatures, + const std::string& requestedFeature) { + + // Use getFeatures to retrieve a map with the single requested feature + auto selectedFeatures = getFeatures(allFeatures, {requestedFeature}); + + // Since we requested only one feature, we can directly access the value + // The exception handling in getFeatures ensures we have a valid, non-empty vector + return selectedFeatures.at(requestedFeature); +} + /* * get(Int|Double|Str)Param provides access to the Int, Double, Str map @@ -124,3 +137,9 @@ template int getVec(std::map >& FeatureData, ma string strFeature, vector& v); template int getVec(std::map >& FeatureData, mapStr2Str& StringData, string strFeature, vector& v); +template std::vector getFeature( + const std::map>& allFeatures, + const std::string& requestedFeature); +template std::vector getFeature( + const std::map>& allFeatures, + const std::string& requestedFeature); diff --git a/efel/cppcore/mapoperations.h b/efel/cppcore/mapoperations.h index 7108412b..b1cad7e8 100644 --- a/efel/cppcore/mapoperations.h +++ b/efel/cppcore/mapoperations.h @@ -36,6 +36,10 @@ template map> getFeatures( const map>& allFeatures, const vector& requestedFeatures); +template +std::vector getFeature( + const std::map>& allFeatures, + const std::string& requestedFeature); template int getParam(map>& featureData, const string& param, vector& vec); diff --git a/tests/testdata/allfeatures/expectedresults.json b/tests/testdata/allfeatures/expectedresults.json index 491cdf23..e58a356b 100644 --- a/tests/testdata/allfeatures/expectedresults.json +++ b/tests/testdata/allfeatures/expectedresults.json @@ -60633,7 +60633,7 @@ "postburst_min_values": [ -41.52919675004766 ], - "time_to_interburst_min": [], + "time_to_interburst_min": null, "AHP_depth_slow": [ 28.81047723194662, 32.02907786238346, From 841f2b3f0636bb6554de84c233ddc0a2a29ef7f5 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 14 Nov 2023 15:42:28 -0500 Subject: [PATCH 33/85] remove unnecessary initializer_list --- efel/cppcore/LibV5.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 9879cd94..5631712d 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -201,7 +201,7 @@ int LibV5::inv_ISI_generic(mapStr2intVec& IntFeatureData, int LibV5::inv_last_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& all_isi_values_vec = getFeature(DoubleFeatureData, {"all_ISI_values"}); + const auto& all_isi_values_vec = getFeature(DoubleFeatureData, "all_ISI_values"); double inv_last_ISI = calculateInvISI(all_isi_values_vec, all_isi_values_vec.size() - 1); // Last ISI vector inv_last_ISI_vec = {inv_last_ISI}; From ffd9d03a50f48c27111017279aa837892b1c46a0 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 14 Nov 2023 16:00:44 -0500 Subject: [PATCH 34/85] min_AHP_indices to use getFeatures --- efel/cppcore/LibV5.cpp | 58 ++++++++++-------------------------------- 1 file changed, 13 insertions(+), 45 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 5631712d..bb1b76bf 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -268,29 +268,17 @@ int LibV5::min_AHP_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { int retVal; - double stim_start, stim_end; - vector min_ahp_indices, strict_stiminterval_vec, peak_indices; - vector v, t, stim_start_vec, stim_end_vec, min_ahp_values; - bool strict_stiminterval; - - // Get voltage - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal <= 0) return -1; - - // Get time - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal <= 0) return -1; - - // Get peak_indices - retVal = getVec(IntFeatureData, StringData, "peak_indices", peak_indices); - if (retVal < 1) { - GErrorStr += - "\n At least one spike required for calculation of " - "min_AHP_indices.\n"; - return -1; - } + // Retrieve all required double features at once + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); - // Get strict_stiminterval + vector min_ahp_indices; + vector min_ahp_values; + double stim_start = doubleFeatures.at("stim_start")[0]; + double stim_end = doubleFeatures.at("stim_end")[0]; + // Get strict_stiminterval + vector strict_stiminterval_vec; + bool strict_stiminterval; retVal = getParam(IntFeatureData, "strict_stiminterval", strict_stiminterval_vec); if (retVal <= 0) { @@ -299,34 +287,14 @@ int LibV5::min_AHP_indices(mapStr2intVec& IntFeatureData, strict_stiminterval = bool(strict_stiminterval_vec[0]); } - // Get stim_start - retVal = - getVec(DoubleFeatureData, StringData, "stim_start", stim_start_vec); - if (retVal <= 0) { - return -1; - } else { - stim_start = stim_start_vec[0]; - } - - /// Get stim_end - retVal = - getVec(DoubleFeatureData, StringData, "stim_end", stim_end_vec); - if (retVal <= 0) { - return -1; - } else { - stim_end = stim_end_vec[0]; - } - - retVal = - __min_AHP_indices(t, v, peak_indices, stim_start, stim_end, - strict_stiminterval, min_ahp_indices, min_ahp_values); + retVal = __min_AHP_indices(doubleFeatures.at("T"), doubleFeatures.at("V"), intFeatures.at("peak_indices"), + stim_start, stim_end, strict_stiminterval, min_ahp_indices, min_ahp_values); if (retVal == 0) return -1; if (retVal > 0) { setVec(IntFeatureData, StringData, "min_AHP_indices", min_ahp_indices); - setVec(DoubleFeatureData, StringData, "min_AHP_values", - min_ahp_values); + setVec(DoubleFeatureData, StringData, "min_AHP_values", min_ahp_values); } return retVal; } From 90a5dc6b41e4b996f5a55228e82c217baacf8c99 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 14 Nov 2023 16:05:49 -0500 Subject: [PATCH 35/85] AHP_depth_abs with getFeature --- efel/cppcore/LibV5.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index bb1b76bf..38212ba9 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -310,11 +310,7 @@ int LibV5::min_AHP_values(mapStr2intVec& IntFeatureData, int LibV5::AHP_depth_abs(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector vAHP; - retVal = getVec(DoubleFeatureData, StringData, "min_AHP_values", vAHP); - if (retVal < 0) return -1; + const auto& vAHP = getFeature(DoubleFeatureData, "min_AHP_values"); setVec(DoubleFeatureData, StringData, "AHP_depth_abs", vAHP); return vAHP.size(); } From 749e0028b0b4f3f13a68464f4c6df7844f37ed29 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 14 Nov 2023 16:09:57 -0500 Subject: [PATCH 36/85] spike_half_width to use getFeatures --- efel/cppcore/LibV5.cpp | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 38212ba9..895387a2 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -362,38 +362,22 @@ static int __spike_width1(const vector& t, const vector& v, int LibV5::spike_width1(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - - vector PeakIndex, minAHPIndex; - vector V, t, dv1, dv2, spike_width1; - vector stim_start; - retVal = getVec(DoubleFeatureData, StringData, "V", V); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = - getVec(DoubleFeatureData, StringData, "stim_start", stim_start); - if (retVal < 0) return -1; - retVal = - getVec(IntFeatureData, StringData, "min_AHP_indices", minAHPIndex); - if (retVal < 0) return -1; - retVal = getVec(IntFeatureData, StringData, "peak_indices", PeakIndex); - if (retVal < 0) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); - // if(PeakIndex.size()<1) {GErrorStr = GErrorStr + "\nError: One spike is - // needed for spikewidth calculation.\n"; return -1;} - if (PeakIndex.size() == 0 || minAHPIndex.size() == 0) { - setVec(DoubleFeatureData, StringData, "spike_half_width", - spike_width1); + vector spike_width1; + // Check if peak_indices and min_AHP_indices are empty + if (intFeatures.at("peak_indices").empty() || intFeatures.at("min_AHP_indices").empty()) { + setVec(DoubleFeatureData, StringData, "spike_half_width", spike_width1); return 0; } - // Take derivative of voltage from 1st AHPmin to the peak of the spike - // Using Central difference derivative vec1[i] = ((vec[i+1]+vec[i-1])/2)/dx - retVal = - __spike_width1(t, V, PeakIndex, minAHPIndex, stim_start[0], spike_width1); + + // Calculate spike width + int retVal = __spike_width1(doubleFeatures.at("T"), doubleFeatures.at("V"), intFeatures.at("peak_indices"), + intFeatures.at("min_AHP_indices"), doubleFeatures.at("stim_start")[0], spike_width1); + if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "spike_half_width", - spike_width1); + setVec(DoubleFeatureData, StringData, "spike_half_width", spike_width1); } return retVal; } From 932b1b11b061b35f5e988d8e5c52162e61f31393 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 14 Nov 2023 16:15:34 -0500 Subject: [PATCH 37/85] AP_begin_indices to use getFeatures --- efel/cppcore/LibV5.cpp | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 895387a2..f874d2fd 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -479,31 +479,15 @@ static int __AP_begin_indices(const vector& t, const vector& v, int LibV5::AP_begin_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - // Get input parameters - vector t; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - vector v; - retVal = getVec(DoubleFeatureData, StringData, "V", v); - if (retVal < 0) return -1; - vector stimstart; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimstart); - if (retVal < 0) return -1; - vector stimend; - retVal = getVec(DoubleFeatureData, StringData, "stim_end", stimend); - if (retVal < 0) return -1; - vector pi; - retVal = getVec(IntFeatureData, StringData, "peak_indices", pi); - if (retVal < 0) return -1; - vector ahpi; - retVal = getVec(IntFeatureData, StringData, "min_AHP_indices", ahpi); - if (retVal < 0) return -1; + // Retrieve all required double and int features at once + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "stim_start", "stim_end"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices"}); + vector apbi; // Get DerivativeThreshold vector dTh; - retVal = getParam(DoubleFeatureData, "DerivativeThreshold", dTh); + int retVal = getParam(DoubleFeatureData, "DerivativeThreshold", dTh); if (retVal <= 0) { // derivative at peak start according to eCode specification 10mV/ms // according to Shaul 12mV/ms @@ -519,9 +503,9 @@ int LibV5::AP_begin_indices(mapStr2intVec& IntFeatureData, } // Calculate feature - retVal = - __AP_begin_indices(t, v, stimstart[0], stimend[0], - pi, ahpi, apbi, dTh[0], derivative_window[0]); + retVal = __AP_begin_indices(doubleFeatures.at("T"), doubleFeatures.at("V"), doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], intFeatures.at("peak_indices"), + intFeatures.at("min_AHP_indices"), apbi, dTh[0], derivative_window[0]); // Save feature value if (retVal >= 0) { @@ -1407,8 +1391,7 @@ int LibV5::voltage_base(mapStr2intVec& IntFeatureData, int LibV5::current_base(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - - int retVal; + int retVal; vector i, t, stimStart, iRest, cb_start_perc_vec, cb_end_perc_vec; double startTime, endTime, cb_start_perc, cb_end_perc; retVal = getVec(DoubleFeatureData, StringData, "I", i); From 35a845025d04d15160aaa1590e87cd6bbd3663c1 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 14 Nov 2023 16:31:05 -0500 Subject: [PATCH 38/85] use getFeatures in current_base --- efel/cppcore/LibV5.cpp | 70 ++++++++++-------------------------------- 1 file changed, 17 insertions(+), 53 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index f874d2fd..2f8659c0 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -1391,78 +1391,42 @@ int LibV5::voltage_base(mapStr2intVec& IntFeatureData, int LibV5::current_base(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector i, t, stimStart, iRest, cb_start_perc_vec, cb_end_perc_vec; - double startTime, endTime, cb_start_perc, cb_end_perc; - retVal = getVec(DoubleFeatureData, StringData, "I", i); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", t); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "stim_start", stimStart); - if (retVal < 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, - "current_base_start_perc", cb_start_perc_vec); - if (retVal == 1) { - cb_start_perc = cb_start_perc_vec[0]; - } else { - cb_start_perc = 0.9; - } - retVal = getVec(DoubleFeatureData, StringData, "current_base_end_perc", - cb_end_perc_vec); - if (retVal == 1) { - cb_end_perc = cb_end_perc_vec[0]; - } else { - cb_end_perc = 1.0; - } + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"I", "T", "stim_start", "current_base_start_perc", "current_base_end_perc"}); + double cb_start_perc = doubleFeatures.at("current_base_start_perc").empty() ? 0.9 : doubleFeatures.at("current_base_start_perc")[0]; + double cb_end_perc = doubleFeatures.at("current_base_end_perc").empty() ? 1.0 : doubleFeatures.at("current_base_end_perc")[0]; - startTime = stimStart[0] * cb_start_perc; - endTime = stimStart[0] * cb_end_perc; + double startTime = doubleFeatures.at("stim_start")[0] * cb_start_perc; + double endTime = doubleFeatures.at("stim_start")[0] * cb_end_perc; if (startTime >= endTime) { GErrorStr += "\ncurrent_base: startTime >= endTime\n"; return -1; } - vector precisionThreshold; - retVal = getParam(DoubleFeatureData, "precision_threshold", - precisionThreshold); + int retVal = getParam(DoubleFeatureData, "precision_threshold", precisionThreshold); if (retVal < 0) return -1; + std::pair time_index = get_time_index(doubleFeatures.at("T"), startTime, endTime, precisionThreshold[0]); - std::pair time_index = get_time_index(t, startTime, endTime, - precisionThreshold[0]); - - - vector subVector(i.begin()+time_index.first, - i.begin()+time_index.second); + vector subVector(doubleFeatures.at("I").begin()+time_index.first, doubleFeatures.at("I").begin()+time_index.second); double iBase; std::string computation_mode; - retVal = getStrParam(StringData, "current_base_mode", computation_mode); if (retVal < 0) return -1; + if (computation_mode == "mean") + iBase = vec_mean(subVector); + else if (computation_mode == "median") + iBase = vec_median(subVector); + else { + GErrorStr += "\ncurrent_base error: Undefined computational mode. Only mean and median are enabled\n"; + return -1; +} - - try{ - if (computation_mode == "mean") - iBase = vec_mean(subVector); - else if (computation_mode == "median") - iBase = vec_median(subVector); - else - throw std::invalid_argument( - "Undefined computational mode. Only mean and median are enabled"); - } - catch(std::exception &e) { - GErrorStr += - "\ncurrent_base error:" + std::string(e.what()) + "\n"; - return -1; - } - - iRest.push_back(iBase); + vector iRest{iBase}; setVec(DoubleFeatureData, StringData, "current_base", iRest); return 1; - } size_t get_index(const vector& times, double t) { From 05108773cd3eac9cd0a160d24c55b3dbfc591817 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 14 Nov 2023 18:56:12 -0500 Subject: [PATCH 39/85] getfeatures in burst_begin_indices --- efel/cppcore/LibV5.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 2f8659c0..a108525e 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -2164,15 +2164,14 @@ static int __burst_indices(double burst_factor, int IgnoreFirstISI, } int LibV5::burst_begin_indices(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { int retVal; vector burst_begin_indices, burst_end_indices, retIgnore; vector ISI_values, tVec; int IgnoreFirstISI; double burst_factor = 0; - retVal = getVec(DoubleFeatureData, StringData, "all_ISI_values", ISI_values); - if (retVal < 0) return -1; + ISI_values = getFeature(DoubleFeatureData, "all_ISI_values"); if (ISI_values.size() < 2) { GErrorStr += "\nError: At least than 3 spikes are needed for burst calculation.\n"; return -1; @@ -2184,12 +2183,10 @@ int LibV5::burst_begin_indices(mapStr2intVec& IntFeatureData, burst_factor = tVec[0]; retVal = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); - if ((retVal == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { + if ((retVal == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) IgnoreFirstISI = 0; - } - else { + else IgnoreFirstISI = 1; - } retVal = __burst_indices( burst_factor, IgnoreFirstISI, ISI_values, burst_begin_indices, burst_end_indices From 378c27819386e5dbcd7f425d60596fa98411ee9d Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 14 Nov 2023 19:29:36 -0500 Subject: [PATCH 40/85] decay_time_constant_after_stim to use getFeatures --- efel/cppcore/LibV5.cpp | 59 ++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index a108525e..a80f1ca5 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -1477,56 +1477,37 @@ double __decay_time_constant_after_stim(const vector& times, int LibV5::decay_time_constant_after_stim(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector voltages; - retVal = getVec(DoubleFeatureData, StringData, "V", voltages); - if (retVal < 0) return -1; - - vector times; - retVal = getVec(DoubleFeatureData, StringData, "T", times); - if (retVal < 0) return -1; - - vector vect; - - retVal = getVec(DoubleFeatureData, StringData, "stim_end", vect); - if (retVal != 1) return -1; - const double stimEnd = vect[0]; - - retVal = getVec(DoubleFeatureData, StringData, "stim_start", vect); - if (retVal != 1) return -1; - const double stimStart = vect[0]; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); double decay_start_after_stim, decay_end_after_stim; - retVal = getVec(DoubleFeatureData, StringData, "decay_start_after_stim", - vect); - if (retVal == 1) { - decay_start_after_stim = vect[0]; - } else { - decay_start_after_stim = 1.0; - } - retVal = - getVec(DoubleFeatureData, StringData, "decay_end_after_stim", vect); - if (retVal == 1) { - decay_end_after_stim = vect[0]; - } else { - decay_end_after_stim = 10.0; + try { + const auto& decayStartFeatures = getFeatures(DoubleFeatureData, {"decay_start_after_stim"}); + decay_start_after_stim = decayStartFeatures.at("decay_start_after_stim")[0]; + } catch (const std::runtime_error&) { + decay_start_after_stim = 1.0; // Default value if not found } + try { + const auto& decayEndFeatures = getFeatures(DoubleFeatureData, {"decay_end_after_stim"}); + decay_end_after_stim = decayEndFeatures.at("decay_end_after_stim")[0]; + } catch (const std::runtime_error&) { + decay_end_after_stim = 10.0; // Default value if not found + } + // Validate decay times if (decay_start_after_stim >= decay_end_after_stim) { - GErrorStr += - "Error decay_start_after_stim small larger than decay_end_after_stim"; + GErrorStr += "Error decay_start_after_stim small larger than decay_end_after_stim"; return -1; } + // Perform calculation const double val = __decay_time_constant_after_stim( - times, voltages, decay_start_after_stim, decay_end_after_stim, stimStart, - stimEnd); + doubleFeatures.at("T"), doubleFeatures.at("V"), decay_start_after_stim, + decay_end_after_stim, doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0]); - vector dtcas; - dtcas.push_back(val); - setVec(DoubleFeatureData, StringData, "decay_time_constant_after_stim", - dtcas); + // Store the result + vector dtcas{val}; + setVec(DoubleFeatureData, StringData, "decay_time_constant_after_stim", dtcas); return 1; } From 8ded4637c0a4d2845e522c286b39f4479167e34b Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Wed, 15 Nov 2023 00:05:33 -0500 Subject: [PATCH 41/85] libv5 exception handling --- efel/cppcore/LibV5.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index a80f1ca5..5901a1ed 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -1391,9 +1391,17 @@ int LibV5::voltage_base(mapStr2intVec& IntFeatureData, int LibV5::current_base(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"I", "T", "stim_start", "current_base_start_perc", "current_base_end_perc"}); - double cb_start_perc = doubleFeatures.at("current_base_start_perc").empty() ? 0.9 : doubleFeatures.at("current_base_start_perc")[0]; - double cb_end_perc = doubleFeatures.at("current_base_end_perc").empty() ? 1.0 : doubleFeatures.at("current_base_end_perc")[0]; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"I", "T", "stim_start"}); + double cb_start_perc = 0.9; // Default value + double cb_end_perc = 1.0; // Default value + + try { + const double cb_start_perc = getFeature(DoubleFeatureData, "current_base_start_perc")[0]; + } catch (const std::runtime_error&) {} // Use default value if not found or an error occurs + + try { + const double cb_end_perc = getFeature(DoubleFeatureData, "current_base_end_perc")[0]; + } catch (const std::runtime_error&) {} // Use default value if not found or an error occurs double startTime = doubleFeatures.at("stim_start")[0] * cb_start_perc; double endTime = doubleFeatures.at("stim_start")[0] * cb_end_perc; @@ -1526,14 +1534,12 @@ int LibV5::multiple_decay_time_constant_after_stim(mapStr2intVec& IntFeatureData // Attempt to get decay parameters, using defaults if not found or if not exactly one element double decay_start_after_stim = 1.0; double decay_end_after_stim = 10.0; - vector decayStartVec, decayEndVec; - - if (getVec(DoubleFeatureData, StringData, "decay_start_after_stim", decayStartVec) == 1) { - decay_start_after_stim = decayStartVec[0]; - } - if (getVec(DoubleFeatureData, StringData, "decay_end_after_stim", decayEndVec) == 1) { - decay_end_after_stim = decayEndVec[0]; - } + try { + const double decay_start_after_stim = getFeature(DoubleFeatureData, "decay_start_after_stim")[0]; + } catch (const std::runtime_error&) {} // Use default value + try { + const double decay_end_after_stim = getFeature(DoubleFeatureData, "decay_end_after_stim")[0]; + } catch (const std::runtime_error&) {} // Use default value vector dtcas; for (size_t i = 0; i < stimsStart.size(); i++) { double ret_dtcas = __decay_time_constant_after_stim( From a21b653c877c0628bba9e0ca95f2bf5f34918d7f Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 16 Nov 2023 14:49:45 -0500 Subject: [PATCH 42/85] remove getVec completely --- .gitignore | 1 + efel/cppcore/LibV1.cpp | 43 ++++++++++++++++------------------ efel/cppcore/mapoperations.cpp | 23 ------------------ efel/cppcore/mapoperations.h | 3 --- 4 files changed, 21 insertions(+), 49 deletions(-) diff --git a/.gitignore b/.gitignore index 2d5b6ec6..3f1cf281 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ bin *.ipynb_checkpoints lib fllog.txt +.DS_STORE diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index bfec9f6e..440870b1 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -46,38 +46,35 @@ std::string to_string(const T& value) { int LibV1::interpolate(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - int retVal; - vector V, T, VIntrpol, TIntrpol, InterpStepVec; - vector intrpolte; - double InterpStep; - // getVec takes care of stimulus suffix - retVal = getVec(DoubleFeatureData, StringData, "V", V); - if (retVal <= 0) return -1; - retVal = getVec(DoubleFeatureData, StringData, "T", T); - if (retVal <= 0) return -1; + T = getFeature(DoubleFeatureData, "T"); // interp_step is a stimulus independent parameter - retVal = getParam(DoubleFeatureData, "interp_step", InterpStepVec); - if (retVal <= 0) - InterpStep = 0.1; - else - InterpStep = InterpStepVec[0]; - - LinearInterpolation(InterpStep, T, V, TIntrpol, VIntrpol); + int retVal = getParam(DoubleFeatureData, "interp_step", InterpStepVec); + double InterpStep = (retVal <= 0) ? 0.1 : InterpStepVec[0]; - setVec(DoubleFeatureData, StringData, "V", VIntrpol); - setVec(DoubleFeatureData, StringData, "T", TIntrpol); - setVec(IntFeatureData, StringData, "interpolate", intrpolte); + try // interpolate V if it's available + { + V = getFeature(DoubleFeatureData, "V"); + LinearInterpolation(InterpStep, T, V, TIntrpol, VIntrpol); + setVec(DoubleFeatureData, StringData, "V", VIntrpol); + setVec(DoubleFeatureData, StringData, "T", TIntrpol); + } + catch(...) + { + return -1; // interpolation failed + } // also interpolate current if present vector I, IIntrpol, TIntrpolI; - int retValI; - retValI = getVec(DoubleFeatureData, StringData, "I", I); - if (retValI > 0){ + try + { + I = getFeature(DoubleFeatureData, "I"); LinearInterpolation(InterpStep, T, I, TIntrpolI, IIntrpol); setVec(DoubleFeatureData, StringData, "I", IIntrpol); + setVec(DoubleFeatureData, StringData, "T", TIntrpol); } - return retVal; + catch(...) {} // pass, it is optional + return 1; } // *** Spikecount *** diff --git a/efel/cppcore/mapoperations.cpp b/efel/cppcore/mapoperations.cpp index 60a5ab6b..27fae68c 100644 --- a/efel/cppcore/mapoperations.cpp +++ b/efel/cppcore/mapoperations.cpp @@ -100,25 +100,6 @@ void setVec(std::map >& FeatureData, mapStr2Str& Str * features in that way. */ -template -int getVec(std::map >& FeatureData, mapStr2Str& StringData, - string strFeature, vector& v){ - string params; - getStrParam(StringData, "params", params); - strFeature += params; - - typename std::map >::iterator - mapstr2VecItr(FeatureData.find(strFeature)); - - if (mapstr2VecItr == FeatureData.end()) { - GErrorStr += "\nFeature [" + strFeature + "] is missing\n"; - return -1; - } - v = mapstr2VecItr->second; - - return (v.size()); -} - template std::map> getFeatures( const std::map>& allFeatures, const std::vector& requestedFeatures); @@ -133,10 +114,6 @@ template void setVec(std::map >& FeatureData, m string key, const vector& value); template void setVec(std::map >& FeatureData, mapStr2Str& StringData, string key, const vector& value); -template int getVec(std::map >& FeatureData, mapStr2Str& StringData, - string strFeature, vector& v); -template int getVec(std::map >& FeatureData, mapStr2Str& StringData, - string strFeature, vector& v); template std::vector getFeature( const std::map>& allFeatures, const std::string& requestedFeature); diff --git a/efel/cppcore/mapoperations.h b/efel/cppcore/mapoperations.h index b1cad7e8..e68b7310 100644 --- a/efel/cppcore/mapoperations.h +++ b/efel/cppcore/mapoperations.h @@ -47,7 +47,4 @@ int getStrParam(mapStr2Str& StringData, const string& param, string& value); template void setVec(map>& FeatureData, mapStr2Str& StringData, string key, const vector& value); -template -int getVec(map>& FeatureData, mapStr2Str& StringData, - string strFeature, vector& v); #endif From 4e6514be70519ae6a51c8163d509ee6c9642d851 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Wed, 29 Nov 2023 11:12:59 +0100 Subject: [PATCH 43/85] make format --- efel/cppcore/DependencyTree.cpp | 31 +- efel/cppcore/FillFptrTable.cpp | 36 +- efel/cppcore/LibV1.cpp | 991 +++++++++++++------------ efel/cppcore/LibV2.cpp | 265 +++---- efel/cppcore/LibV3.cpp | 36 +- efel/cppcore/LibV5.cpp | 1234 +++++++++++++++++-------------- efel/cppcore/Utils.cpp | 143 ++-- efel/cppcore/cfeature.cpp | 146 ++-- efel/cppcore/cppcore.cpp | 118 ++- efel/cppcore/mapoperations.cpp | 82 +- 10 files changed, 1600 insertions(+), 1482 deletions(-) diff --git a/efel/cppcore/DependencyTree.cpp b/efel/cppcore/DependencyTree.cpp index c7f5ad48..c11d1b70 100644 --- a/efel/cppcore/DependencyTree.cpp +++ b/efel/cppcore/DependencyTree.cpp @@ -18,8 +18,8 @@ #include "DependencyTree.h" -#include //remove -#include //isspace +#include //remove +#include //isspace #include static void removeAllWhiteSpace(string &str) { @@ -34,7 +34,7 @@ cTree::cTree(const char *strFileName) { return; } - for (string line; std::getline(input, line); ) { + for (string line; std::getline(input, line);) { removeAllWhiteSpace(line); if (!line.empty()) { strDependencyFile.push_back(std::move(line)); @@ -52,13 +52,13 @@ cTree::cTree(const char *strFileName) { * FptrTable : * FptrLookup | vector of pairs: * first | string: feature name - * second | vector of feature_function to represent list of dependent features + * second | vector of feature_function to represent list of + * dependent features * */ -int cTree::setFeaturePointers(map &mapFptrLib, - feature2function *FptrTable, - map > *FptrLookup) -{ +int cTree::setFeaturePointers( + map &mapFptrLib, feature2function *FptrTable, + map > *FptrLookup) { list::iterator lstItr; map::iterator mapLibItr; feature2function *fptrTbl; @@ -73,7 +73,6 @@ int cTree::setFeaturePointers(map &mapFptrLib, // vecFeature is a list with all the feature names in the first column // of the dependency file for (unsigned i = 0; i < vecFeature.size(); i++) { - FinalList.clear(); strLibFeature = vecFeature[i]; // fill FinalList with all the dependencies of feature vecFeature[i] @@ -112,7 +111,7 @@ int cTree::setFeaturePointers(map &mapFptrLib, vecfptr.push_back(mapFeatureItr->second); FptrTable->insert(std::pair( - strFeature, mapFeatureItr->second)); + strFeature, mapFeatureItr->second)); } // Add the vecfptr from above to a map with as key the base featurei FptrLookup->insert( @@ -130,7 +129,7 @@ int cTree::setFeaturePointers(map &mapFptrLib, */ int cTree::getAllParents(vector &lstFeature) { for (unsigned i = 0; i < strDependencyFile.size(); i++) { - const string& strLine = strDependencyFile[i]; + const string &strLine = strDependencyFile[i]; size_t nPos = strLine.find_first_of('#'); string FeatureName = strLine.substr(0, nPos); if (!FeatureName.empty()) { @@ -161,19 +160,19 @@ int cTree::getChilds(string str, list &childs) { return 1; } - -int cTree::getDependency(const string& strLine) { +int cTree::getDependency(const string &strLine) { std::list tmpChild; getChilds(strLine, tmpChild); - for (const auto& childFeature : tmpChild) { - getDependency(childFeature); // Recursively get dependencies of the child feature. + for (const auto &childFeature : tmpChild) { + getDependency( + childFeature); // Recursively get dependencies of the child feature. } AddUniqueItem(strLine); // Add the feature itself to the FinalList. return 0; } -void cTree::AddUniqueItem(const string& strFeature) { +void cTree::AddUniqueItem(const string &strFeature) { auto it = std::find(FinalList.begin(), FinalList.end(), strFeature); if (it == FinalList.end()) { FinalList.push_back(strFeature); diff --git a/efel/cppcore/FillFptrTable.cpp b/efel/cppcore/FillFptrTable.cpp index 9892f094..1889759c 100644 --- a/efel/cppcore/FillFptrTable.cpp +++ b/efel/cppcore/FillFptrTable.cpp @@ -103,19 +103,29 @@ int FillFptrTable() { FptrTableV5["ISI_log_slope_skip"] = &LibV5::ISI_log_slope_skip; FptrTableV5["time_to_second_spike"] = &LibV5::time_to_second_spike; FptrTableV5["time_to_last_spike"] = &LibV5::time_to_last_spike; - FptrTableV5["inv_first_ISI"] = [](mapStr2intVec& intData, mapStr2doubleVec& doubleData, mapStr2Str& strData) { - return LibV5::inv_ISI_generic(intData, doubleData, strData, 0); + FptrTableV5["inv_first_ISI"] = [](mapStr2intVec& intData, + mapStr2doubleVec& doubleData, + mapStr2Str& strData) { + return LibV5::inv_ISI_generic(intData, doubleData, strData, 0); }; - FptrTableV5["inv_second_ISI"] = [](mapStr2intVec& intData, mapStr2doubleVec& doubleData, mapStr2Str& strData) { - return LibV5::inv_ISI_generic(intData, doubleData, strData, 1); + FptrTableV5["inv_second_ISI"] = [](mapStr2intVec& intData, + mapStr2doubleVec& doubleData, + mapStr2Str& strData) { + return LibV5::inv_ISI_generic(intData, doubleData, strData, 1); }; - FptrTableV5["inv_third_ISI"] = [](mapStr2intVec& intData, mapStr2doubleVec& doubleData, mapStr2Str& strData) { + FptrTableV5["inv_third_ISI"] = [](mapStr2intVec& intData, + mapStr2doubleVec& doubleData, + mapStr2Str& strData) { return LibV5::inv_ISI_generic(intData, doubleData, strData, 2); }; - FptrTableV5["inv_fourth_ISI"] = [](mapStr2intVec& intData, mapStr2doubleVec& doubleData, mapStr2Str& strData) { - return LibV5::inv_ISI_generic(intData, doubleData, strData, 3); + FptrTableV5["inv_fourth_ISI"] = [](mapStr2intVec& intData, + mapStr2doubleVec& doubleData, + mapStr2Str& strData) { + return LibV5::inv_ISI_generic(intData, doubleData, strData, 3); }; - FptrTableV5["inv_fifth_ISI"] = [](mapStr2intVec& intData, mapStr2doubleVec& doubleData, mapStr2Str& strData) { + FptrTableV5["inv_fifth_ISI"] = [](mapStr2intVec& intData, + mapStr2doubleVec& doubleData, + mapStr2Str& strData) { return LibV5::inv_ISI_generic(intData, doubleData, strData, 4); }; FptrTableV5["inv_last_ISI"] = &LibV5::inv_last_ISI; @@ -178,8 +188,7 @@ int FillFptrTable() { &LibV5::decay_time_constant_after_stim; FptrTableV5["multiple_decay_time_constant_after_stim"] = &LibV5::multiple_decay_time_constant_after_stim; - FptrTableV5["sag_time_constant"] = - &LibV5::sag_time_constant; + FptrTableV5["sag_time_constant"] = &LibV5::sag_time_constant; FptrTableV5["ohmic_input_resistance_vb_ssse"] = &LibV5::ohmic_input_resistance_vb_ssse; @@ -188,7 +197,7 @@ int FillFptrTable() { FptrTableV5["maximum_voltage_from_voltagebase"] = &LibV5::maximum_voltage_from_voltagebase; FptrTableV5["Spikecount_stimint"] = &LibV5::Spikecount_stimint; - + FptrTableV5["peak_indices"] = &LibV5::peak_indices; FptrTableV5["sag_amplitude"] = &LibV5::sag_amplitude; FptrTableV5["sag_ratio1"] = &LibV5::sag_ratio1; @@ -197,7 +206,8 @@ int FillFptrTable() { FptrTableV5["AP_peak_downstroke"] = &LibV5::AP_peak_downstroke; FptrTableV5["min_between_peaks_indices"] = &LibV5::min_between_peaks_indices; FptrTableV5["min_between_peaks_values"] = &LibV5::min_between_peaks_values; - FptrTableV5["AP_width_between_threshold"] = &LibV5::AP_width_between_threshold; + FptrTableV5["AP_width_between_threshold"] = + &LibV5::AP_width_between_threshold; FptrTableV5["burst_begin_indices"] = &LibV5::burst_begin_indices; FptrTableV5["burst_end_indices"] = &LibV5::burst_end_indices; @@ -214,7 +224,7 @@ int FillFptrTable() { FptrTableV5["postburst_min_indices"] = &LibV5::postburst_min_indices; FptrTableV5["postburst_min_values"] = &LibV5::postburst_min_values; FptrTableV5["time_to_interburst_min"] = &LibV5::time_to_interburst_min; - + //****************** end of FptrTableV5 ***************************** return 1; diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index 440870b1..d6ca8c19 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -18,25 +18,27 @@ #include "LibV1.h" +#include + #include #include #include +#include #include #include #include -#include -#include #include -#include +#include + #include "EfelExceptions.h" using std::distance; using std::find_if; using std::list; -using std::min_element; using std::max_element; +using std::min_element; -template +template std::string to_string(const T& value) { std::ostringstream oss; oss << std::setprecision(17) << value; @@ -58,22 +60,19 @@ int LibV1::interpolate(mapStr2intVec& IntFeatureData, LinearInterpolation(InterpStep, T, V, TIntrpol, VIntrpol); setVec(DoubleFeatureData, StringData, "V", VIntrpol); setVec(DoubleFeatureData, StringData, "T", TIntrpol); - } - catch(...) - { + } catch (...) { return -1; // interpolation failed } // also interpolate current if present vector I, IIntrpol, TIntrpolI; - try - { + try { I = getFeature(DoubleFeatureData, "I"); LinearInterpolation(InterpStep, T, I, TIntrpolI, IIntrpol); setVec(DoubleFeatureData, StringData, "I", IIntrpol); setVec(DoubleFeatureData, StringData, "T", TIntrpol); - } - catch(...) {} // pass, it is optional + } catch (...) { + } // pass, it is optional return 1; } @@ -83,37 +82,40 @@ int LibV1::Spikecount(mapStr2intVec& IntFeatureData, mapStr2Str& StringData) { size_t spikecount_value; try { // handle empty peak_indices - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); - spikecount_value = intFeatures.at("peak_indices").size(); - } catch(const EmptyFeatureError& e) { - spikecount_value = 0; + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); + spikecount_value = intFeatures.at("peak_indices").size(); + } catch (const EmptyFeatureError& e) { + spikecount_value = 0; } vector spikecount(1, spikecount_value); setVec(IntFeatureData, StringData, "Spikecount", spikecount); - return spikecount_value; + return spikecount_value; } // end of Spikecount int LibV1::ISI_values(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); - if (doubleFeatures.at("peak_time").size() < 3) { - GErrorStr += "\n Three spikes required for calculation of ISI_values.\n"; - return -1; - } + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); + if (doubleFeatures.at("peak_time").size() < 3) { + GErrorStr += "\n Three spikes required for calculation of ISI_values.\n"; + return -1; + } - const auto& intFeatures = getFeatures(IntFeatureData, {"ignore_first_ISI"}); - int IgnoreFirstISI = 1; - if (intFeatures.at("ignore_first_ISI").size() > 0 && intFeatures.at("ignore_first_ISI")[0] == 0) { - IgnoreFirstISI = 0; - } + const auto& intFeatures = getFeatures(IntFeatureData, {"ignore_first_ISI"}); + int IgnoreFirstISI = 1; + if (intFeatures.at("ignore_first_ISI").size() > 0 && + intFeatures.at("ignore_first_ISI")[0] == 0) { + IgnoreFirstISI = 0; + } - vector VecISI; - for (size_t i = IgnoreFirstISI + 1; i < doubleFeatures.at("peak_time").size(); i++) - VecISI.push_back(doubleFeatures.at("peak_time")[i] - doubleFeatures.at("peak_time")[i - 1]); - setVec(DoubleFeatureData, StringData, "ISI_values", VecISI); - return VecISI.size(); + vector VecISI; + for (size_t i = IgnoreFirstISI + 1; i < doubleFeatures.at("peak_time").size(); + i++) + VecISI.push_back(doubleFeatures.at("peak_time")[i] - + doubleFeatures.at("peak_time")[i - 1]); + setVec(DoubleFeatureData, StringData, "ISI_values", VecISI); + return VecISI.size(); } // *** ISI_CV *** @@ -138,119 +140,137 @@ static int __ISI_CV(const vector& isivalues, vector& isicv) { } int LibV1::ISI_CV(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); - if (doubleFeatures.at("ISI_values").size() < 2) return -1; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); + if (doubleFeatures.at("ISI_values").size() < 2) return -1; - vector isicv; - int retval = __ISI_CV(doubleFeatures.at("ISI_values"), isicv); - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "ISI_CV", isicv); - } - return retval; + vector isicv; + int retval = __ISI_CV(doubleFeatures.at("ISI_values"), isicv); + if (retval >= 0) { + setVec(DoubleFeatureData, StringData, "ISI_CV", isicv); + } + return retval; } int LibV1::peak_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); - vector peakV; - for (const auto& index : intFeatures.at("peak_indices")) { - peakV.push_back(doubleFeatures.at("V")[index]); - } - setVec(DoubleFeatureData, StringData, "peak_voltage", peakV); - return peakV.size(); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); + vector peakV; + for (const auto& index : intFeatures.at("peak_indices")) { + peakV.push_back(doubleFeatures.at("V")[index]); + } + setVec(DoubleFeatureData, StringData, "peak_voltage", peakV); + return peakV.size(); } int LibV1::firing_rate(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end"}); - double lastAPTime = 0.; - int nCount = 0; - for (const auto& time : doubleFeatures.at("peak_time")) { - if ((time >= doubleFeatures.at("stim_start")[0]) && (time <= doubleFeatures.at("stim_end")[0])) { - lastAPTime = time; - nCount++; - } - } - if (lastAPTime == doubleFeatures.at("stim_start")[0]) { - GErrorStr += "\nPrevent divide by zero.\n"; - return -1; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end"}); + double lastAPTime = 0.; + int nCount = 0; + for (const auto& time : doubleFeatures.at("peak_time")) { + if ((time >= doubleFeatures.at("stim_start")[0]) && + (time <= doubleFeatures.at("stim_end")[0])) { + lastAPTime = time; + nCount++; } - vector firing_rate; - firing_rate.push_back(nCount * 1000 / (lastAPTime - doubleFeatures.at("stim_start")[0])); - setVec(DoubleFeatureData, StringData, "mean_frequency", firing_rate); - return firing_rate.size(); + } + if (lastAPTime == doubleFeatures.at("stim_start")[0]) { + GErrorStr += "\nPrevent divide by zero.\n"; + return -1; + } + vector firing_rate; + firing_rate.push_back(nCount * 1000 / + (lastAPTime - doubleFeatures.at("stim_start")[0])); + setVec(DoubleFeatureData, StringData, "mean_frequency", firing_rate); + return firing_rate.size(); } int LibV1::peak_time(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); - vector pvTime; - for (const auto& index : intFeatures.at("peak_indices")) { - pvTime.push_back(doubleFeatures.at("T")[index]); - } - setVec(DoubleFeatureData, StringData, "peak_time", pvTime); - return pvTime.size(); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); + vector pvTime; + for (const auto& index : intFeatures.at("peak_indices")) { + pvTime.push_back(doubleFeatures.at("T")[index]); + } + setVec(DoubleFeatureData, StringData, "peak_time", pvTime); + return pvTime.size(); } // time from stimulus start to first threshold crossing int LibV1::first_spike_time(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); - if (doubleFeatures.at("peak_time").size() < 1) { - GErrorStr += "\n One spike required for time_to_first_spike.\n"; - return -1; - } - vector first_spike; - first_spike.push_back(doubleFeatures.at("peak_time")[0] - doubleFeatures.at("stim_start")[0]); - setVec(DoubleFeatureData, StringData, "time_to_first_spike", first_spike); - return first_spike.size(); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); + if (doubleFeatures.at("peak_time").size() < 1) { + GErrorStr += "\n One spike required for time_to_first_spike.\n"; + return -1; + } + vector first_spike; + first_spike.push_back(doubleFeatures.at("peak_time")[0] - + doubleFeatures.at("stim_start")[0]); + setVec(DoubleFeatureData, StringData, "time_to_first_spike", first_spike); + return first_spike.size(); } int LibV1::AP_height(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_voltage"}); - setVec(DoubleFeatureData, StringData, "AP_height", doubleFeatures.at("peak_voltage")); - return doubleFeatures.at("peak_voltage").size(); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_voltage"}); + setVec(DoubleFeatureData, StringData, "AP_height", + doubleFeatures.at("peak_voltage")); + return doubleFeatures.at("peak_voltage").size(); } // spike amplitude: peak_voltage - v[AP_begin_indices] int LibV1::AP_amplitude(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "stim_start", "stim_end", "peak_voltage", "peak_time"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices"}); - if (doubleFeatures.at("peak_voltage").size() != doubleFeatures.at("peak_time").size()) { - GErrorStr += "AP_amplitude: Not the same amount of peak_time and peak_voltage entries"; - return -1; - } - vector peakvoltage_duringstim; - for (size_t i = 0; i < doubleFeatures.at("peak_time").size(); i++) { - if (doubleFeatures.at("peak_time")[i] >= doubleFeatures.at("stim_start")[0] && doubleFeatures.at("peak_time")[i] <= doubleFeatures.at("stim_end")[0]) { - peakvoltage_duringstim.push_back(doubleFeatures.at("peak_voltage")[i]); - } - } - if (peakvoltage_duringstim.size() > intFeatures.at("AP_begin_indices").size()) { - GErrorStr += "AP_amplitude: More peak_voltage entries during the stimulus than AP_begin_indices entries"; - return -1; - } - vector apamplitude; - apamplitude.resize(peakvoltage_duringstim.size()); - for (size_t i = 0; i < apamplitude.size(); i++) { - apamplitude[i] = peakvoltage_duringstim[i] - doubleFeatures.at("V")[intFeatures.at("AP_begin_indices")[i]]; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, + {"V", "stim_start", "stim_end", "peak_voltage", "peak_time"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices"}); + if (doubleFeatures.at("peak_voltage").size() != + doubleFeatures.at("peak_time").size()) { + GErrorStr += + "AP_amplitude: Not the same amount of peak_time and peak_voltage " + "entries"; + return -1; + } + vector peakvoltage_duringstim; + for (size_t i = 0; i < doubleFeatures.at("peak_time").size(); i++) { + if (doubleFeatures.at("peak_time")[i] >= + doubleFeatures.at("stim_start")[0] && + doubleFeatures.at("peak_time")[i] <= doubleFeatures.at("stim_end")[0]) { + peakvoltage_duringstim.push_back(doubleFeatures.at("peak_voltage")[i]); } - setVec(DoubleFeatureData, StringData, "AP_amplitude", apamplitude); - return apamplitude.size(); + } + if (peakvoltage_duringstim.size() > + intFeatures.at("AP_begin_indices").size()) { + GErrorStr += + "AP_amplitude: More peak_voltage entries during the stimulus than " + "AP_begin_indices entries"; + return -1; + } + vector apamplitude; + apamplitude.resize(peakvoltage_duringstim.size()); + for (size_t i = 0; i < apamplitude.size(); i++) { + apamplitude[i] = + peakvoltage_duringstim[i] - + doubleFeatures.at("V")[intFeatures.at("AP_begin_indices")[i]]; + } + setVec(DoubleFeatureData, StringData, "AP_amplitude", apamplitude); + return apamplitude.size(); } // *** AHP_depth_abs_slow *** -// same as AHP_depth_abs but the minimum search starts +// same as AHP_depth_abs but the minimum search starts // 5 ms (or custom duration) after the spike, // first ISI is ignored static int __AHP_depth_abs_slow_indices(const vector& t, @@ -264,13 +284,13 @@ static int __AHP_depth_abs_slow_indices(const vector& t, double t_start = t[peakindices[i + 1]] + sahp_start; adas_indices[i] = distance( v.begin(), - min_element( - v.begin() + - distance(t.begin(), - find_if(t.begin() + peakindices[i + 1], - t.begin() + peakindices[i + 2], - [t_start](double val) { return val >= t_start; })), - v.begin() + peakindices[i + 2])); + min_element(v.begin() + distance(t.begin(), + find_if(t.begin() + peakindices[i + 1], + t.begin() + peakindices[i + 2], + [t_start](double val) { + return val >= t_start; + })), + v.begin() + peakindices[i + 2])); } return adas_indices.size(); } @@ -278,33 +298,38 @@ static int __AHP_depth_abs_slow_indices(const vector& t, int LibV1::AHP_depth_abs_slow(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "sahp_start"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); - if (intFeatures.at("peak_indices").size() < 3) { - GErrorStr += "\n At least 3 spikes needed for AHP_depth_abs_slow and AHP_slow_time.\n"; - return -1; - } - double sahp_start = (doubleFeatures.at("sahp_start").empty()) ? 5 : doubleFeatures.at("sahp_start")[0]; - vector adas_indices; - int retval = __AHP_depth_abs_slow_indices( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - intFeatures.at("peak_indices"), - sahp_start, - adas_indices - ); - vector ahpdepthabsslow(adas_indices.size()); - vector ahpslowtime(adas_indices.size()); - for (size_t i = 0; i < adas_indices.size(); i++) { - ahpdepthabsslow[i] = doubleFeatures.at("V")[adas_indices[i]]; - ahpslowtime[i] = (doubleFeatures.at("T")[adas_indices[i]] - doubleFeatures.at("T")[intFeatures.at("peak_indices")[i + 1]]) / - (doubleFeatures.at("T")[intFeatures.at("peak_indices")[i + 2]] - doubleFeatures.at("T")[intFeatures.at("peak_indices")[i + 1]]); - } - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "AHP_depth_abs_slow", ahpdepthabsslow); - setVec(DoubleFeatureData, StringData, "AHP_slow_time", ahpslowtime); - } - return retval; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"T", "V", "sahp_start"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); + if (intFeatures.at("peak_indices").size() < 3) { + GErrorStr += + "\n At least 3 spikes needed for AHP_depth_abs_slow and " + "AHP_slow_time.\n"; + return -1; + } + double sahp_start = (doubleFeatures.at("sahp_start").empty()) + ? 5 + : doubleFeatures.at("sahp_start")[0]; + vector adas_indices; + int retval = __AHP_depth_abs_slow_indices( + doubleFeatures.at("T"), doubleFeatures.at("V"), + intFeatures.at("peak_indices"), sahp_start, adas_indices); + vector ahpdepthabsslow(adas_indices.size()); + vector ahpslowtime(adas_indices.size()); + for (size_t i = 0; i < adas_indices.size(); i++) { + ahpdepthabsslow[i] = doubleFeatures.at("V")[adas_indices[i]]; + ahpslowtime[i] = + (doubleFeatures.at("T")[adas_indices[i]] - + doubleFeatures.at("T")[intFeatures.at("peak_indices")[i + 1]]) / + (doubleFeatures.at("T")[intFeatures.at("peak_indices")[i + 2]] - + doubleFeatures.at("T")[intFeatures.at("peak_indices")[i + 1]]); + } + if (retval >= 0) { + setVec(DoubleFeatureData, StringData, "AHP_depth_abs_slow", + ahpdepthabsslow); + setVec(DoubleFeatureData, StringData, "AHP_slow_time", ahpslowtime); + } + return retval; } // end of AHP_depth_abs_slow @@ -344,30 +369,30 @@ static int __burst_ISI_indices(double BurstFactor, const vector& PeakIndex, int LibV1::burst_ISI_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values", "burst_factor"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); - if (intFeatures.at("peak_indices").size() < 5) { - GErrorStr += "\nError: More than 5 spike is needed for burst calculation.\n"; - return -1; - } - double BurstFactor = (doubleFeatures.at("burst_factor").empty()) ? 2 : doubleFeatures.at("burst_factor")[0]; - vector BurstIndex; - int retVal = __burst_ISI_indices( - BurstFactor, - intFeatures.at("peak_indices"), - doubleFeatures.at("ISI_values"), - BurstIndex - ); - if (retVal >= 0) { - setVec(IntFeatureData, StringData, "burst_ISI_indices", BurstIndex); - } - return retVal; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"ISI_values", "burst_factor"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); + if (intFeatures.at("peak_indices").size() < 5) { + GErrorStr += + "\nError: More than 5 spike is needed for burst calculation.\n"; + return -1; + } + double BurstFactor = (doubleFeatures.at("burst_factor").empty()) + ? 2 + : doubleFeatures.at("burst_factor")[0]; + vector BurstIndex; + int retVal = __burst_ISI_indices(BurstFactor, intFeatures.at("peak_indices"), + doubleFeatures.at("ISI_values"), BurstIndex); + if (retVal >= 0) { + setVec(IntFeatureData, StringData, "burst_ISI_indices", BurstIndex); + } + return retVal; } // discrepancy betwen PVTime indices and BurstIndex indices because // first ISI value is ignored -static int __burst_mean_freq(const vector& PVTime, const vector& BurstIndex, - int IgnoreFirstISI, +static int __burst_mean_freq(const vector& PVTime, + const vector& BurstIndex, int IgnoreFirstISI, vector& BurstMeanFreq) { // if no burst detected, do not consider all peaks in a single burst if (BurstIndex.size() == 0) return BurstMeanFreq.size(); @@ -380,16 +405,19 @@ static int __burst_mean_freq(const vector& PVTime, const vector& Bu for (i = 0; i < BurstIndex.size() - 1; i++) { if (BurstIndex[i + 1] - BurstIndex[i] > 1) { - span = PVTime[BurstIndex[i + 1] - 1 + IgnoreFirstISI] - PVTime[BurstIndex[i] + IgnoreFirstISI]; - BurstMeanFreq.push_back((BurstIndex[i + 1] - BurstIndex[i]) * 1000 / span); + span = PVTime[BurstIndex[i + 1] - 1 + IgnoreFirstISI] - + PVTime[BurstIndex[i] + IgnoreFirstISI]; + BurstMeanFreq.push_back((BurstIndex[i + 1] - BurstIndex[i]) * 1000 / + span); } } // last burst if (PVTime.size() - IgnoreFirstISI - BurstIndex[i] > 1) { - span = PVTime[PVTime.size() - 1] - PVTime[BurstIndex[i] + IgnoreFirstISI]; - BurstMeanFreq.push_back((PVTime.size() - IgnoreFirstISI - BurstIndex[i]) * 1000 / span); - } + span = PVTime[PVTime.size() - 1] - PVTime[BurstIndex[i] + IgnoreFirstISI]; + BurstMeanFreq.push_back((PVTime.size() - IgnoreFirstISI - BurstIndex[i]) * + 1000 / span); + } return BurstMeanFreq.size(); } @@ -397,45 +425,44 @@ static int __burst_mean_freq(const vector& PVTime, const vector& Bu int LibV1::burst_mean_freq(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"burst_ISI_indices", "ignore_first_ISI"}); - int IgnoreFirstISI = 1; - int retValIgnore; - vector retIgnore; - retValIgnore = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); - if ((retValIgnore == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { - IgnoreFirstISI = 0; - } - else { - IgnoreFirstISI = 1; - } - vector BurstMeanFreq; - int retVal = __burst_mean_freq( - doubleFeatures.at("peak_time"), - intFeatures.at("burst_ISI_indices"), - IgnoreFirstISI, - BurstMeanFreq - ); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "burst_mean_freq", BurstMeanFreq); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"burst_ISI_indices", "ignore_first_ISI"}); + int IgnoreFirstISI = 1; + int retValIgnore; + vector retIgnore; + retValIgnore = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); + if ((retValIgnore == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { + IgnoreFirstISI = 0; + } else { + IgnoreFirstISI = 1; + } + vector BurstMeanFreq; + int retVal = __burst_mean_freq(doubleFeatures.at("peak_time"), + intFeatures.at("burst_ISI_indices"), + IgnoreFirstISI, BurstMeanFreq); + if (retVal >= 0) { + setVec(DoubleFeatureData, StringData, "burst_mean_freq", BurstMeanFreq); + } + return retVal; } int LibV1::burst_number(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"burst_mean_freq"}); - vector BurstNum; - BurstNum.push_back(doubleFeatures.at("burst_mean_freq").size()); - setVec(IntFeatureData, StringData, "burst_number", BurstNum); - return BurstNum.size(); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"burst_mean_freq"}); + vector BurstNum; + BurstNum.push_back(doubleFeatures.at("burst_mean_freq").size()); + setVec(IntFeatureData, StringData, "burst_number", BurstNum); + return BurstNum.size(); } // reminder: first ISI value is ignored in burst_ISI_indices if IgnoreFirstISI=1 -static int __interburst_voltage(const vector& BurstIndex, const vector& PeakIndex, - const vector& T, const vector& V, - int IgnoreFirstISI, +static int __interburst_voltage(const vector& BurstIndex, + const vector& PeakIndex, + const vector& T, + const vector& V, int IgnoreFirstISI, vector& IBV) { if (BurstIndex.size() < 1) return 0; int j, pIndex, tsIndex, teIndex, cnt; @@ -468,31 +495,26 @@ static int __interburst_voltage(const vector& BurstIndex, const vector int LibV1::interburst_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "burst_ISI_indices"}); - int IgnoreFirstISI; - int retValIgnore; - vector retIgnore; - retValIgnore = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); - if ((retValIgnore == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { - IgnoreFirstISI = 0; - } - else { - IgnoreFirstISI = 1; - } - vector IBV; - int retVal = __interburst_voltage( - intFeatures.at("burst_ISI_indices"), - intFeatures.at("peak_indices"), - doubleFeatures.at("T"), - doubleFeatures.at("V"), - IgnoreFirstISI, - IBV - ); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "interburst_voltage", IBV); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"peak_indices", "burst_ISI_indices"}); + int IgnoreFirstISI; + int retValIgnore; + vector retIgnore; + retValIgnore = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); + if ((retValIgnore == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { + IgnoreFirstISI = 0; + } else { + IgnoreFirstISI = 1; + } + vector IBV; + int retVal = __interburst_voltage( + intFeatures.at("burst_ISI_indices"), intFeatures.at("peak_indices"), + doubleFeatures.at("T"), doubleFeatures.at("V"), IgnoreFirstISI, IBV); + if (retVal >= 0) { + setVec(DoubleFeatureData, StringData, "interburst_voltage", IBV); + } + return retVal; } static int __adaptation_index(double spikeSkipf, int maxnSpike, @@ -552,36 +574,34 @@ static int __adaptation_index(double spikeSkipf, int maxnSpike, int LibV1::adaptation_index(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end", "spike_skipf"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"max_spike_skip"}); - - if (doubleFeatures.at("spike_skipf")[0] < 0 || doubleFeatures.at("spike_skipf")[0] >= 1) { - GErrorStr += "\nspike_skipf should lie between [0 1).\n"; - return -1; - } - vector OffSetVec; - double Offset; - int retval = getParam(DoubleFeatureData, "offset", OffSetVec); - if (retval < 0) { - Offset = 0; // Keep old behavior, set Offset to 0 if offset is not found - } else { - Offset = OffSetVec[0]; // Use the first element of OffSetVec if found - } + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, + {"peak_time", "stim_start", "stim_end", "spike_skipf"}); + const auto& intFeatures = getFeatures(IntFeatureData, {"max_spike_skip"}); + + if (doubleFeatures.at("spike_skipf")[0] < 0 || + doubleFeatures.at("spike_skipf")[0] >= 1) { + GErrorStr += "\nspike_skipf should lie between [0 1).\n"; + return -1; + } + vector OffSetVec; + double Offset; + int retval = getParam(DoubleFeatureData, "offset", OffSetVec); + if (retval < 0) { + Offset = 0; // Keep old behavior, set Offset to 0 if offset is not found + } else { + Offset = OffSetVec[0]; // Use the first element of OffSetVec if found + } - vector adaptation_index; - int retVal = __adaptation_index( - doubleFeatures.at("spike_skipf")[0], - intFeatures.at("max_spike_skip")[0], - doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0], - Offset, - doubleFeatures.at("peak_time"), - adaptation_index - ); - if (retVal > 0) { - setVec(DoubleFeatureData, StringData, "adaptation_index", adaptation_index); - } - return retVal; + vector adaptation_index; + int retVal = __adaptation_index( + doubleFeatures.at("spike_skipf")[0], intFeatures.at("max_spike_skip")[0], + doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0], + Offset, doubleFeatures.at("peak_time"), adaptation_index); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "adaptation_index", adaptation_index); + } + return retVal; } // *** adaptation_index2 *** @@ -635,33 +655,31 @@ static int __adaptation_index2(double StimStart, double StimEnd, double Offset, int LibV1::adaptation_index2(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end"}); - vector OffSetVec; - double Offset; - int retval = getParam(DoubleFeatureData, "offset", OffSetVec); - if (retval < 0) - Offset = 0; - else - Offset = OffSetVec[0]; - - if (doubleFeatures.at("peak_time").size() < 4) { - GErrorStr += "\n At least 4 spikes needed for adaptation_index2.\n"; - return -1; - } + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end"}); + vector OffSetVec; + double Offset; + int retval = getParam(DoubleFeatureData, "offset", OffSetVec); + if (retval < 0) + Offset = 0; + else + Offset = OffSetVec[0]; + + if (doubleFeatures.at("peak_time").size() < 4) { + GErrorStr += "\n At least 4 spikes needed for adaptation_index2.\n"; + return -1; + } - vector adaptationindex2; - retval = __adaptation_index2( - doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0], - Offset, - doubleFeatures.at("peak_time"), - adaptationindex2 - ); - - if (retval >= 0) { - setVec(DoubleFeatureData, StringData, "adaptation_index2", adaptationindex2); - } - return retval; + vector adaptationindex2; + retval = __adaptation_index2( + doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0], + Offset, doubleFeatures.at("peak_time"), adaptationindex2); + + if (retval >= 0) { + setVec(DoubleFeatureData, StringData, "adaptation_index2", + adaptationindex2); + } + return retval; } // end of adaptation_index2 @@ -669,29 +687,34 @@ int LibV1::adaptation_index2(mapStr2intVec& IntFeatureData, int LibV1::trace_check(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end"}); - bool sane = true; - for (const auto& peak : doubleFeatures.at("peak_time")) { - if (peak < doubleFeatures.at("stim_start")[0] || peak > doubleFeatures.at("stim_end")[0] * 1.05) { - sane = false; - break; - } - } - if (sane) { - vector tc = {0}; - setVec(IntFeatureData, StringData, "trace_check", tc); - return tc.size(); - } else { - GErrorStr += "Trace sanity check failed, there were spike outside the stimulus interval.\n"; - return -1; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end"}); + bool sane = true; + for (const auto& peak : doubleFeatures.at("peak_time")) { + if (peak < doubleFeatures.at("stim_start")[0] || + peak > doubleFeatures.at("stim_end")[0] * 1.05) { + sane = false; + break; } + } + if (sane) { + vector tc = {0}; + setVec(IntFeatureData, StringData, "trace_check", tc); + return tc.size(); + } else { + GErrorStr += + "Trace sanity check failed, there were spike outside the stimulus " + "interval.\n"; + return -1; + } } // To find spike width using Central difference derivative vec1[i] = // ((vec[i+1]+vec[i-1])/2)/dx and half width is between // MinAHP and APThreshold static int __spike_width2(const vector& t, const vector& V, - const vector& PeakIndex, const vector& minAHPIndex, + const vector& PeakIndex, + const vector& minAHPIndex, vector& spike_width2) { vector v, dv1, dv2; double dx = t[1] - t[0]; @@ -773,24 +796,22 @@ static int __spike_width2(const vector& t, const vector& V, int LibV1::spike_width2(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); - if (intFeatures.at("peak_indices").size() <= 1) { - GErrorStr += "\nError: More than one spike is needed for spikewidth calculation.\n"; - return -1; - } - vector spike_width2; - int retVal = __spike_width2( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - intFeatures.at("peak_indices"), - intFeatures.at("min_AHP_indices"), - spike_width2 - ); - if (retVal > 0) { - setVec(DoubleFeatureData, StringData, "spike_width2", spike_width2); - } - return retVal; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); + if (intFeatures.at("peak_indices").size() <= 1) { + GErrorStr += + "\nError: More than one spike is needed for spikewidth calculation.\n"; + return -1; + } + vector spike_width2; + int retVal = __spike_width2(doubleFeatures.at("T"), doubleFeatures.at("V"), + intFeatures.at("peak_indices"), + intFeatures.at("min_AHP_indices"), spike_width2); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "spike_width2", spike_width2); + } + return retVal; } // passive properties implementation @@ -818,8 +839,9 @@ static int __time_constant(const vector& v, const vector& t, // for(stimendindex = 0; t[stimendindex] < stimEnd; stimendindex++) ; // int stimmiddleindex = (stimstartindex + stimendindex) / 2; double mid_stim = (stimStart + stimEnd) / 2.; - auto it_mid_stim = find_if(t.begin() + stimstartindex, t.end(), - [mid_stim](double val) { return val >= mid_stim; }); + auto it_mid_stim = + find_if(t.begin() + stimstartindex, t.end(), + [mid_stim](double val) { return val >= mid_stim; }); int stimmiddleindex = distance(t.begin(), it_mid_stim); if (stimstartindex >= v.size() || stimmiddleindex < 0 || @@ -837,12 +859,14 @@ static int __time_constant(const vector& v, const vector& t, // getCentralDifferenceDerivative(1.,part_t,dt); getfivepointstencilderivative(part_v, dv); getfivepointstencilderivative(part_t, dt); - transform(dv.begin(), dv.end(), dt.begin(), dvdt.begin(), std::divides()); + transform(dv.begin(), dv.end(), dt.begin(), dvdt.begin(), + std::divides()); // find start of the decay int i_start = 0; while (find_if(dvdt.begin() + i_start, dvdt.begin() + i_start + 5, - [min_derivative](double val) { return val > -min_derivative; }) != dvdt.begin() + i_start + 5) - { + [min_derivative](double val) { + return val > -min_derivative; + }) != dvdt.begin() + i_start + 5) { if (dvdt.begin() + i_start + 5 == dvdt.end()) { GErrorStr += "Could not find the decay.\n"; return -1; @@ -859,7 +883,7 @@ static int __time_constant(const vector& v, const vector& t, int length = 0; for (int i_mean = 0; t[i_flat + i_mean + stimstartindex] - t[i_flat + stimstartindex] < - t_length; + t_length; i_mean++) { sum += dvdt[i_flat + i_mean]; length++; @@ -941,19 +965,16 @@ static int __time_constant(const vector& v, const vector& t, int LibV1::time_constant(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); - vector tc; - int retVal = __time_constant( - doubleFeatures.at("V"), - doubleFeatures.at("T"), - doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0], - tc - ); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "time_constant", tc); - } - return retVal; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + vector tc; + int retVal = __time_constant(doubleFeatures.at("V"), doubleFeatures.at("T"), + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], tc); + if (retVal >= 0) { + setVec(DoubleFeatureData, StringData, "time_constant", tc); + } + return retVal; } // *** voltage deflection *** @@ -995,19 +1016,16 @@ static int __voltage_deflection(const vector& v, int LibV1::voltage_deflection(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); - vector vd; - int retVal = __voltage_deflection( - doubleFeatures.at("V"), - doubleFeatures.at("T"), - doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0], - vd - ); - if (retVal > 0) { - setVec(DoubleFeatureData, StringData, "voltage_deflection", vd); - } - return retVal; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + vector vd; + int retVal = __voltage_deflection( + doubleFeatures.at("V"), doubleFeatures.at("T"), + doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0], vd); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "voltage_deflection", vd); + } + return retVal; } // *** ohmic input resistance *** @@ -1022,17 +1040,16 @@ static int __ohmic_input_resistance(double voltage_deflection, int LibV1::ohmic_input_resistance(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_deflection", "stimulus_current"}); - vector oir; - int retVal = __ohmic_input_resistance( - doubleFeatures.at("voltage_deflection")[0], - doubleFeatures.at("stimulus_current")[0], - oir - ); - if (retVal > 0) { - setVec(DoubleFeatureData, StringData, "ohmic_input_resistance", oir); - } - return retVal; + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, {"voltage_deflection", "stimulus_current"}); + vector oir; + int retVal = + __ohmic_input_resistance(doubleFeatures.at("voltage_deflection")[0], + doubleFeatures.at("stimulus_current")[0], oir); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "ohmic_input_resistance", oir); + } + return retVal; } static int __maxmin_voltage(const vector& v, const vector& t, @@ -1043,12 +1060,11 @@ static int __maxmin_voltage(const vector& v, const vector& t, return -1; } - if (stimEnd > t[t.size() - 1]) - stimEnd = t.back(); + if (stimEnd > t[t.size() - 1]) stimEnd = t.back(); size_t stimstartindex = 0; - while(t[stimstartindex] < stimStart && stimstartindex <= t.size()) - stimstartindex++; + while (t[stimstartindex] < stimStart && stimstartindex <= t.size()) + stimstartindex++; if (stimstartindex >= t.size()) { GErrorStr += "\nStimulus start index not found\n"; @@ -1056,8 +1072,8 @@ static int __maxmin_voltage(const vector& v, const vector& t, } size_t stimendindex = 0; - while(t[stimendindex] < stimEnd && stimstartindex <= t.size()) - stimendindex++; + while (t[stimendindex] < stimEnd && stimstartindex <= t.size()) + stimendindex++; if (stimendindex >= t.size()) { GErrorStr += "\nStimulus end index not found\n"; @@ -1073,20 +1089,16 @@ static int __maxmin_voltage(const vector& v, const vector& t, int LibV1::maximum_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); - vector maxV, minV; - int retVal = __maxmin_voltage( - doubleFeatures.at("V"), - doubleFeatures.at("T"), - doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0], - maxV, - minV - ); - if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "maximum_voltage", maxV); - } - return retVal; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + vector maxV, minV; + int retVal = __maxmin_voltage(doubleFeatures.at("V"), doubleFeatures.at("T"), + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], maxV, minV); + if (retVal >= 0) { + setVec(DoubleFeatureData, StringData, "maximum_voltage", maxV); + } + return retVal; } // *** maximum voltage *** @@ -1094,20 +1106,16 @@ int LibV1::maximum_voltage(mapStr2intVec& IntFeatureData, int LibV1::minimum_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); - vector maxV, minV; - int retVal = __maxmin_voltage( - doubleFeatures.at("V"), - doubleFeatures.at("T"), - doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0], - maxV, - minV - ); - if (retVal > 0) { - setVec(DoubleFeatureData, StringData, "minimum_voltage", minV); - } - return retVal; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + vector maxV, minV; + int retVal = __maxmin_voltage(doubleFeatures.at("V"), doubleFeatures.at("T"), + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], maxV, minV); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "minimum_voltage", minV); + } + return retVal; } // *** steady state voltage *** @@ -1128,20 +1136,18 @@ static int __steady_state_voltage(const vector& v, int LibV1::steady_state_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_end"}); - if (doubleFeatures.at("stim_end").size() != 1) return -1; - - vector ssv; - int retVal = __steady_state_voltage( - doubleFeatures.at("V"), - doubleFeatures.at("T"), - doubleFeatures.at("stim_end")[0], - ssv - ); - if (retVal > 0) { - setVec(DoubleFeatureData, StringData, "steady_state_voltage", ssv); - } - return retVal; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"V", "T", "stim_end"}); + if (doubleFeatures.at("stim_end").size() != 1) return -1; + + vector ssv; + int retVal = + __steady_state_voltage(doubleFeatures.at("V"), doubleFeatures.at("T"), + doubleFeatures.at("stim_end")[0], ssv); + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "steady_state_voltage", ssv); + } + return retVal; } // *** single_burst_ratio *** @@ -1165,16 +1171,15 @@ static int __single_burst_ratio(const vector& isivalues, int LibV1::single_burst_ratio(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); - vector singleburstratio; - int retval = __single_burst_ratio( - doubleFeatures.at("ISI_values"), - singleburstratio - ); - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "single_burst_ratio", singleburstratio); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values"}); + vector singleburstratio; + int retval = + __single_burst_ratio(doubleFeatures.at("ISI_values"), singleburstratio); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "single_burst_ratio", + singleburstratio); + } + return retval; } // *** AP_width *** @@ -1186,17 +1191,17 @@ static int __AP_width(const vector& t, const vector& v, double stimstart, double stimend, double threshold, const vector& peakindices, const vector& minahpindices, - const bool strict_stiminterval, - vector& apwidth) { + const bool strict_stiminterval, vector& apwidth) { // printf("\n Inside AP_width...\n"); // printf("\nStimStart = %f , thereshold = %f ", stimstart, threshold); vector indices; - if (strict_stiminterval){ + if (strict_stiminterval) { int start_index = distance( - t.begin(), - find_if(t.begin(), t.end(), [stimstart](double x){ return x >= stimstart; })); - int end_index = distance(t.begin(), find_if(t.begin(), t.end(), - [stimend](double x){ return x >= stimend; })); + t.begin(), find_if(t.begin(), t.end(), + [stimstart](double x) { return x >= stimstart; })); + int end_index = distance( + t.begin(), find_if(t.begin(), t.end(), + [stimend](double x) { return x >= stimend; })); indices.push_back(start_index); for (size_t i = 0; i < minahpindices.size(); i++) { if (start_index < minahpindices[i] && minahpindices[i] < end_index) { @@ -1222,13 +1227,13 @@ static int __AP_width(const vector& t, const vector& v, apwidth.push_back(t[hm_index2] - t[hm_index1]); */ auto onset_index = distance( - v.begin(), find_if(v.begin() + indices[i], v.begin() + indices[i + 1], - [threshold](double x){ return x >= threshold; })); + v.begin(), find_if(v.begin() + indices[i], v.begin() + indices[i + 1], + [threshold](double x) { return x >= threshold; })); // int end_index = distance(v.begin(), find_if(v.begin() + peakindices[i], // v.begin() + indices[i + 1], bind2nd(less_equal(), threshold))); auto end_index = distance( - v.begin(), find_if(v.begin() + onset_index, v.begin() + indices[i + 1], - [threshold](double x){ return x <= threshold; })); + v.begin(), find_if(v.begin() + onset_index, v.begin() + indices[i + 1], + [threshold](double x) { return x <= threshold; })); apwidth.push_back(t[end_index] - t[onset_index]); } return apwidth.size(); @@ -1237,25 +1242,25 @@ static int __AP_width(const vector& t, const vector& v, int LibV1::AP_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "Threshold", "stim_start", "stim_end"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices", "strict_stiminterval"}); - bool strict_stiminterval = intFeatures.at("strict_stiminterval").size() > 0 ? bool(intFeatures.at("strict_stiminterval")[0]) : false; - vector apwidth; - int retval = __AP_width( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0], - doubleFeatures.at("Threshold")[0], - intFeatures.at("peak_indices"), - intFeatures.at("min_AHP_indices"), - strict_stiminterval, - apwidth - ); - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AP_width", apwidth); - } - return retval; + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, {"T", "V", "Threshold", "stim_start", "stim_end"}); + const auto& intFeatures = + getFeatures(IntFeatureData, + {"peak_indices", "min_AHP_indices", "strict_stiminterval"}); + bool strict_stiminterval = + intFeatures.at("strict_stiminterval").size() > 0 + ? bool(intFeatures.at("strict_stiminterval")[0]) + : false; + vector apwidth; + int retval = __AP_width( + doubleFeatures.at("T"), doubleFeatures.at("V"), + doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0], + doubleFeatures.at("Threshold")[0], intFeatures.at("peak_indices"), + intFeatures.at("min_AHP_indices"), strict_stiminterval, apwidth); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_width", apwidth); + } + return retval; } // end of AP_width @@ -1264,20 +1269,21 @@ int LibV1::AP_width(mapStr2intVec& IntFeatureData, int LibV1::doublet_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); - if (doubleFeatures.at("peak_time").size() < 2) { - GErrorStr += "\nNeed at least two spikes for doublet_ISI.\n"; - return -1; - } - vector doubletisi(1, doubleFeatures.at("peak_time")[1] - doubleFeatures.at("peak_time")[0]); - setVec(DoubleFeatureData, StringData, "doublet_ISI", doubletisi); - return doubleFeatures.at("peak_time").size(); + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); + if (doubleFeatures.at("peak_time").size() < 2) { + GErrorStr += "\nNeed at least two spikes for doublet_ISI.\n"; + return -1; + } + vector doubletisi( + 1, doubleFeatures.at("peak_time")[1] - doubleFeatures.at("peak_time")[0]); + setVec(DoubleFeatureData, StringData, "doublet_ISI", doubletisi); + return doubleFeatures.at("peak_time").size(); } // *** AHP_depth_slow *** static int __AHP_depth_slow(const vector& voltagebase, - const vector& minahpvalues, - vector& ahpdepth) { + const vector& minahpvalues, + vector& ahpdepth) { for (size_t i = 0; i < minahpvalues.size(); i++) { ahpdepth.push_back(minahpvalues[i] - voltagebase[0]); } @@ -1285,22 +1291,20 @@ static int __AHP_depth_slow(const vector& voltagebase, } int LibV1::AHP_depth_slow(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_base", "AHP_depth_abs_slow"}); - vector ahpdepthslow; - int retval = __AHP_depth_slow( - doubleFeatures.at("voltage_base"), - doubleFeatures.at("AHP_depth_abs_slow"), - ahpdepthslow - ); - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AHP_depth_slow", ahpdepthslow); - } - return retval; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"voltage_base", "AHP_depth_abs_slow"}); + vector ahpdepthslow; + int retval = + __AHP_depth_slow(doubleFeatures.at("voltage_base"), + doubleFeatures.at("AHP_depth_abs_slow"), ahpdepthslow); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AHP_depth_slow", ahpdepthslow); + } + return retval; } - // *** AHP_depth *** static int __AHP_depth(const vector& voltagebase, const vector& minahpvalues, @@ -1313,17 +1317,15 @@ static int __AHP_depth(const vector& voltagebase, int LibV1::AHP_depth(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_base", "min_AHP_values"}); - vector ahpdepth; - int retval = __AHP_depth( - doubleFeatures.at("voltage_base"), - doubleFeatures.at("min_AHP_values"), - ahpdepth - ); - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AHP_depth", ahpdepth); - } - return retval; + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"voltage_base", "min_AHP_values"}); + vector ahpdepth; + int retval = __AHP_depth(doubleFeatures.at("voltage_base"), + doubleFeatures.at("min_AHP_values"), ahpdepth); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AHP_depth", ahpdepth); + } + return retval; } // *** AP_amplitude_diff based on AP_amplitude_change but not normalized *** @@ -1340,16 +1342,14 @@ static int __AP_amplitude_diff(const vector& apamplitude, int LibV1::AP_amplitude_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"AP_amplitude"}); - vector apamplitudediff; - int retval = __AP_amplitude_diff( - doubleFeatures.at("AP_amplitude"), - apamplitudediff - ); - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AP_amplitude_diff", apamplitudediff); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"AP_amplitude"}); + vector apamplitudediff; + int retval = + __AP_amplitude_diff(doubleFeatures.at("AP_amplitude"), apamplitudediff); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_amplitude_diff", apamplitudediff); + } + return retval; } // *** AHP_depth_diff, returns AHP_depth[i+1] - AHP_depth[i] *** @@ -1365,15 +1365,12 @@ static int __AHP_depth_diff(const vector& ahpdepth, int LibV1::AHP_depth_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"AHP_depth"}); - vector ahpdepthdiff; - int retval = __AHP_depth_diff( - doubleFeatures.at("AHP_depth"), - ahpdepthdiff - ); - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AHP_depth_diff", ahpdepthdiff); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"AHP_depth"}); + vector ahpdepthdiff; + int retval = __AHP_depth_diff(doubleFeatures.at("AHP_depth"), ahpdepthdiff); + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AHP_depth_diff", ahpdepthdiff); + } + return retval; } // end of feature definition diff --git a/efel/cppcore/LibV2.cpp b/efel/cppcore/LibV2.cpp index 23d54d53..216c9d7e 100644 --- a/efel/cppcore/LibV2.cpp +++ b/efel/cppcore/LibV2.cpp @@ -18,15 +18,16 @@ #include "LibV2.h" +#include + #include #include #include #include -#include using std::find_if; -using std::min_element; using std::max_element; +using std::min_element; using std::transform; // AP parameters @@ -55,19 +56,17 @@ static int __AP_rise_indices(const vector& v, const vector& apbi, int LibV2::AP_rise_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "peak_indices"}); - vector apriseindices; - int retval = __AP_rise_indices( - doubleFeatures.at("V"), - intFeatures.at("AP_begin_indices"), - intFeatures.at("peak_indices"), - apriseindices - ); - if (retval > 0) { - setVec(IntFeatureData, StringData, "AP_rise_indices", apriseindices); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"AP_begin_indices", "peak_indices"}); + vector apriseindices; + int retval = __AP_rise_indices(doubleFeatures.at("V"), + intFeatures.at("AP_begin_indices"), + intFeatures.at("peak_indices"), apriseindices); + if (retval > 0) { + setVec(IntFeatureData, StringData, "AP_rise_indices", apriseindices); + } + return retval; } // *** AP fall indices *** @@ -89,20 +88,18 @@ static int __AP_fall_indices(const vector& v, const vector& apbi, int LibV2::AP_fall_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "AP_end_indices", "peak_indices"}); - vector apfallindices; - int retval = __AP_fall_indices( - doubleFeatures.at("V"), - intFeatures.at("AP_begin_indices"), - intFeatures.at("AP_end_indices"), - intFeatures.at("peak_indices"), - apfallindices - ); - if (retval > 0) { - setVec(IntFeatureData, StringData, "AP_fall_indices", apfallindices); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); + const auto& intFeatures = getFeatures( + IntFeatureData, {"AP_begin_indices", "AP_end_indices", "peak_indices"}); + vector apfallindices; + int retval = __AP_fall_indices(doubleFeatures.at("V"), + intFeatures.at("AP_begin_indices"), + intFeatures.at("AP_end_indices"), + intFeatures.at("peak_indices"), apfallindices); + if (retval > 0) { + setVec(IntFeatureData, StringData, "AP_fall_indices", apfallindices); + } + return retval; } // eFeatures @@ -122,21 +119,19 @@ static int __AP_duration(const vector& t, int LibV2::AP_duration(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "AP_end_indices"}); - - vector apduration; - int retval = __AP_duration( - doubleFeatures.at("T"), - intFeatures.at("AP_begin_indices"), - intFeatures.at("AP_end_indices"), - apduration - ); - - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AP_duration", apduration); - } - return retval; + const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"AP_begin_indices", "AP_end_indices"}); + + vector apduration; + int retval = + __AP_duration(doubleFeatures.at("T"), intFeatures.at("AP_begin_indices"), + intFeatures.at("AP_end_indices"), apduration); + + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "AP_duration", apduration); + } + return retval; } // *** AP_duration_half_width according to E8 and E16 *** @@ -155,30 +150,26 @@ int LibV2::AP_duration_half_width(mapStr2intVec& IntFeatureData, mapStr2Str& StringData) { // Fetching all required features in one go. const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"AP_rise_indices", "AP_fall_indices"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"AP_rise_indices", "AP_fall_indices"}); vector apdurationhalfwidth; int retval = __AP_duration_half_width( - doubleFeatures.at("T"), - intFeatures.at("AP_rise_indices"), - intFeatures.at("AP_fall_indices"), - apdurationhalfwidth - ); + doubleFeatures.at("T"), intFeatures.at("AP_rise_indices"), + intFeatures.at("AP_fall_indices"), apdurationhalfwidth); if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AP_duration_half_width", apdurationhalfwidth); + setVec(DoubleFeatureData, StringData, "AP_duration_half_width", + apdurationhalfwidth); } return retval; } // *** AP_rise_time according to E9 and E17 *** -static int __AP_rise_time(const vector& t, - const vector& v, +static int __AP_rise_time(const vector& t, const vector& v, const vector& apbeginindices, const vector& peakindices, - const vector& apamplitude, - double beginperc, - double endperc, - vector& aprisetime) { + const vector& apamplitude, double beginperc, + double endperc, vector& aprisetime) { aprisetime.resize(std::min(apbeginindices.size(), peakindices.size())); double begin_v; double end_v; @@ -189,23 +180,23 @@ static int __AP_rise_time(const vector& t, end_v = v[apbeginindices[i]] + endperc * apamplitude[i]; // Get begin indice - size_t j=apbeginindices[i]; + size_t j = apbeginindices[i]; // change slightly begin_v for almost equal case // truncature error can change begin_v even when beginperc == 0.0 - while (japbeginindices[i] && v[j] > end_v + 0.0000000000001){ + while (j > apbeginindices[i] && v[j] > end_v + 0.0000000000001) { j--; } end_indice = j; - + aprisetime[i] = t[end_indice] - t[begin_indice]; } return aprisetime.size(); @@ -214,21 +205,23 @@ int LibV2::AP_rise_time(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { // Fetching all required features in one go. - const auto& doubleFeatures = getFeatures(DoubleFeatureData, - {"T", "V", "AP_amplitude", "rise_start_perc", "rise_end_perc"}); - const auto& intFeatures = getFeatures(IntFeatureData, - {"AP_begin_indices", "peak_indices"}); + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, + {"T", "V", "AP_amplitude", "rise_start_perc", "rise_end_perc"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"AP_begin_indices", "peak_indices"}); vector aprisetime; int retval = __AP_rise_time( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - intFeatures.at("AP_begin_indices"), - intFeatures.at("peak_indices"), + doubleFeatures.at("T"), doubleFeatures.at("V"), + intFeatures.at("AP_begin_indices"), intFeatures.at("peak_indices"), doubleFeatures.at("AP_amplitude"), - doubleFeatures.at("rise_start_perc").empty() ? 0.0 : doubleFeatures.at("rise_start_perc").front(), - doubleFeatures.at("rise_end_perc").empty() ? 1.0 : doubleFeatures.at("rise_end_perc").front(), - aprisetime - ); + doubleFeatures.at("rise_start_perc").empty() + ? 0.0 + : doubleFeatures.at("rise_start_perc").front(), + doubleFeatures.at("rise_end_perc").empty() + ? 1.0 + : doubleFeatures.at("rise_end_perc").front(), + aprisetime); if (retval > 0) { setVec(DoubleFeatureData, StringData, "AP_rise_time", aprisetime); } @@ -250,7 +243,8 @@ int LibV2::AP_fall_time(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "AP_end_indices"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"peak_indices", "AP_end_indices"}); const vector& t = doubleFeatures.at("T"); const vector& peakindices = intFeatures.at("peak_indices"); @@ -261,7 +255,7 @@ int LibV2::AP_fall_time(mapStr2intVec& IntFeatureData, if (retval > 0) { setVec(DoubleFeatureData, StringData, "AP_fall_time", apfalltime); - } + } return retval; } @@ -281,8 +275,9 @@ int LibV2::AP_rise_rate(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "peak_indices"}); - + const auto& intFeatures = + getFeatures(IntFeatureData, {"AP_begin_indices", "peak_indices"}); + const vector& t = doubleFeatures.at("T"); const vector& v = doubleFeatures.at("V"); const vector& apbeginindices = intFeatures.at("AP_begin_indices"); @@ -292,7 +287,7 @@ int LibV2::AP_rise_rate(mapStr2intVec& IntFeatureData, int retval = __AP_rise_rate(t, v, apbeginindices, peakindices, apriserate); if (retval > 0) { setVec(DoubleFeatureData, StringData, "AP_rise_rate", apriserate); - } + } return retval; } // end of AP_rise_rate @@ -313,13 +308,14 @@ int LibV2::AP_fall_rate(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "AP_end_indices"}); - + const auto& intFeatures = + getFeatures(IntFeatureData, {"peak_indices", "AP_end_indices"}); + const vector& t = doubleFeatures.at("T"); const vector& v = doubleFeatures.at("V"); const vector& peakindices = intFeatures.at("peak_indices"); const vector& apendindices = intFeatures.at("AP_end_indices"); - + vector apfallrate; int retval = __AP_fall_rate(t, v, peakindices, apendindices, apfallrate); @@ -347,12 +343,13 @@ int LibV2::fast_AHP(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "min_AHP_indices"}); - + const auto& intFeatures = + getFeatures(IntFeatureData, {"AP_begin_indices", "min_AHP_indices"}); + const vector& v = doubleFeatures.at("V"); const vector& apbeginindices = intFeatures.at("AP_begin_indices"); const vector& minahpindices = intFeatures.at("min_AHP_indices"); - + vector fastahp; int retval = __fast_AHP(v, apbeginindices, minahpindices, fastahp); @@ -385,7 +382,8 @@ int LibV2::AP_amplitude_change(mapStr2intVec& IntFeatureData, int retval = __AP_amplitude_change(apamplitude, apamplitudechange); if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AP_amplitude_change", apamplitudechange); + setVec(DoubleFeatureData, StringData, "AP_amplitude_change", + apamplitudechange); } return retval; } @@ -411,7 +409,8 @@ int LibV2::AP_duration_change(mapStr2intVec& IntFeatureData, vector apdurationchange; int retval = __AP_duration_change(apduration, apdurationchange); if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AP_duration_change", apdurationchange); + setVec(DoubleFeatureData, StringData, "AP_duration_change", + apdurationchange); } return retval; } @@ -435,12 +434,16 @@ static int __AP_duration_half_width_change( int LibV2::AP_duration_half_width_change(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& features = getFeatures(DoubleFeatureData, {"AP_duration_half_width"}); - const vector& apdurationhalfwidth = features.at("AP_duration_half_width"); + const auto& features = + getFeatures(DoubleFeatureData, {"AP_duration_half_width"}); + const vector& apdurationhalfwidth = + features.at("AP_duration_half_width"); vector apdurationhalfwidthchange; - int retval = __AP_duration_half_width_change(apdurationhalfwidth, apdurationhalfwidthchange); + int retval = __AP_duration_half_width_change(apdurationhalfwidth, + apdurationhalfwidthchange); if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AP_duration_half_width_change", apdurationhalfwidthchange); + setVec(DoubleFeatureData, StringData, "AP_duration_half_width_change", + apdurationhalfwidthchange); } return retval; } @@ -453,7 +456,7 @@ static int __AP_rise_rate_change(const vector& apriserate, return -1; } apriseratechange.resize(apriserate.size() - 1); - + for (size_t i = 0; i < apriseratechange.size(); i++) { apriseratechange[i] = (apriserate[i + 1] - apriserate[0]) / apriserate[0]; } @@ -467,7 +470,8 @@ int LibV2::AP_rise_rate_change(mapStr2intVec& IntFeatureData, vector apriseratechange; int retval = __AP_rise_rate_change(apriserate, apriseratechange); if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AP_rise_rate_change", apriseratechange); + setVec(DoubleFeatureData, StringData, "AP_rise_rate_change", + apriseratechange); } return retval; } @@ -493,7 +497,8 @@ int LibV2::AP_fall_rate_change(mapStr2intVec& IntFeatureData, vector apfallratechange; int retval = __AP_fall_rate_change(apfallrate, apfallratechange); if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AP_fall_rate_change", apfallratechange); + setVec(DoubleFeatureData, StringData, "AP_fall_rate_change", + apfallratechange); } return retval; } @@ -537,13 +542,15 @@ int LibV2::amp_drop_first_second(mapStr2intVec& IntFeatureData, const vector peakvoltage = features.at("peak_voltage"); if (peakvoltage.size() < 2) { - GErrorStr += "At least 2 spikes needed for calculation of amp_drop_first_second.\n"; + GErrorStr += + "At least 2 spikes needed for calculation of amp_drop_first_second.\n"; return -1; } vector ampdropfirstsecond; int retval = __amp_drop_first_second(peakvoltage, ampdropfirstsecond); if (retval > 0) { - setVec(DoubleFeatureData, StringData, "amp_drop_first_second", ampdropfirstsecond); + setVec(DoubleFeatureData, StringData, "amp_drop_first_second", + ampdropfirstsecond); } return retval; } @@ -557,17 +564,20 @@ static int __amp_drop_first_last(const vector& peakvoltage, int LibV2::amp_drop_first_last(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& peakVoltageFeature = getFeatures(DoubleFeatureData, {"peak_voltage"}); + const auto& peakVoltageFeature = + getFeatures(DoubleFeatureData, {"peak_voltage"}); const vector peakvoltage = peakVoltageFeature.at("peak_voltage"); if (peakvoltage.size() < 2) { - GErrorStr += "At least 2 spikes needed for calculation of amp_drop_first_last.\n"; + GErrorStr += + "At least 2 spikes needed for calculation of amp_drop_first_last.\n"; return -1; } vector ampdropfirstlast; int retval = __amp_drop_first_last(peakvoltage, ampdropfirstlast); if (retval > 0) { - setVec(DoubleFeatureData, StringData, "amp_drop_first_last", ampdropfirstlast); + setVec(DoubleFeatureData, StringData, "amp_drop_first_last", + ampdropfirstlast); } return retval; } @@ -582,17 +592,20 @@ static int __amp_drop_second_last(const vector& peakvoltage, int LibV2::amp_drop_second_last(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& peakVoltageFeatures = getFeatures(DoubleFeatureData, {"peak_voltage"}); + const auto& peakVoltageFeatures = + getFeatures(DoubleFeatureData, {"peak_voltage"}); const vector& peakvoltage = peakVoltageFeatures.at("peak_voltage"); // Ensure there are at least 3 spikes for calculation if (peakvoltage.size() < 3) { - GErrorStr += "At least 3 spikes needed for calculation of amp_drop_second_last.\n"; + GErrorStr += + "At least 3 spikes needed for calculation of amp_drop_second_last.\n"; return -1; } vector ampdropsecondlast; int retval = __amp_drop_second_last(peakvoltage, ampdropsecondlast); if (retval > 0) { - setVec(DoubleFeatureData, StringData, "amp_drop_second_last", ampdropsecondlast); + setVec(DoubleFeatureData, StringData, "amp_drop_second_last", + ampdropsecondlast); } return retval; } @@ -620,14 +633,17 @@ int LibV2::max_amp_difference(mapStr2intVec& IntFeatureData, // Ensure there are at least 2 spikes for calculation if (features.at("peak_voltage").size() < 2) { - GErrorStr += "At least 2 spikes needed for calculation of max_amp_difference.\n"; - return -1; + GErrorStr += + "At least 2 spikes needed for calculation of max_amp_difference.\n"; + return -1; } vector maxampdifference; - int retval = __max_amp_difference(features.at("peak_voltage"), maxampdifference); + int retval = + __max_amp_difference(features.at("peak_voltage"), maxampdifference); if (retval > 0) { - setVec(DoubleFeatureData, StringData, "max_amp_difference", maxampdifference); + setVec(DoubleFeatureData, StringData, "max_amp_difference", + maxampdifference); } return retval; } @@ -638,14 +654,14 @@ int LibV2::max_amp_difference(mapStr2intVec& IntFeatureData, static int __steady_state_hyper(const vector& v, const vector& t, double stimend, vector& steady_state_hyper) { - // Find the iterator pointing to the first time value greater than or equal to stimend - auto it_stimend = find_if(t.begin(), t.end(), - [stimend](double t_val) { return t_val >= stimend; }); + // Find the iterator pointing to the first time value greater than or equal to + // stimend + auto it_stimend = find_if( + t.begin(), t.end(), [stimend](double t_val) { return t_val >= stimend; }); // Calculate the index, ensuring you account for the offset of -5 int i_end = distance(t.begin(), it_stimend) - 5; - const int offset = 30; if (i_end < 0 || i_end < offset) { return -1; @@ -667,23 +683,20 @@ static int __steady_state_hyper(const vector& v, int LibV2::steady_state_hyper(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - // Retrieve all required features at once - const auto& features = getFeatures(DoubleFeatureData, {"V", "T", "stim_end"}); - - vector steady_state_hyper; - int retval = __steady_state_hyper( - features.at("V"), - features.at("T"), - features.at("stim_end").front(), - steady_state_hyper - ); - - if (retval > 0) { - setVec(DoubleFeatureData, StringData, "steady_state_hyper", steady_state_hyper); - } - return retval; -} + // Retrieve all required features at once + const auto& features = getFeatures(DoubleFeatureData, {"V", "T", "stim_end"}); + vector steady_state_hyper; + int retval = + __steady_state_hyper(features.at("V"), features.at("T"), + features.at("stim_end").front(), steady_state_hyper); + + if (retval > 0) { + setVec(DoubleFeatureData, StringData, "steady_state_hyper", + steady_state_hyper); + } + return retval; +} // // end of feature definition diff --git a/efel/cppcore/LibV3.cpp b/efel/cppcore/LibV3.cpp index 5076fd1f..2a8ec0fd 100644 --- a/efel/cppcore/LibV3.cpp +++ b/efel/cppcore/LibV3.cpp @@ -18,16 +18,16 @@ #include "LibV3.h" +#include + #include #include #include -#include using std::find_if; using std::list; using std::min_element; - static int __depolarized_base(const vector& t, const vector& v, double stimstart, double stimend, const vector& apbi, @@ -65,23 +65,21 @@ static int __depolarized_base(const vector& t, const vector& v, int LibV3::depolarized_base(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - // Retrieve all required double and int features at once - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "stim_start", "stim_end"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"AP_end_indices", "AP_begin_indices"}); + // Retrieve all required double and int features at once + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"T", "V", "stim_start", "stim_end"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"AP_end_indices", "AP_begin_indices"}); - vector dep_base; - int retVal = __depolarized_base( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - doubleFeatures.at("stim_start").front(), - doubleFeatures.at("stim_end").front(), - intFeatures.at("AP_begin_indices"), - intFeatures.at("AP_end_indices"), - dep_base - ); + vector dep_base; + int retVal = __depolarized_base( + doubleFeatures.at("T"), doubleFeatures.at("V"), + doubleFeatures.at("stim_start").front(), + doubleFeatures.at("stim_end").front(), intFeatures.at("AP_begin_indices"), + intFeatures.at("AP_end_indices"), dep_base); - if (retVal > 0) { - setVec(DoubleFeatureData, StringData, "depolarized_base", dep_base); - } - return retVal; + if (retVal > 0) { + setVec(DoubleFeatureData, StringData, "depolarized_base", dep_base); + } + return retVal; } diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 5901a1ed..98ad820f 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -19,18 +19,19 @@ #include "LibV5.h" #include + #include #include #include #include #include #include + #include "EfelExceptions.h" using std::distance; using std::find_if; - // slope of loglog of ISI curve static int __ISI_log_slope(const vector& isiValues, vector& slope, bool skip, double spikeSkipf, @@ -46,8 +47,7 @@ static int __ISI_log_slope(const vector& isiValues, if (skip) { // Remove n spikes given by spike_skipf or max_spike_skip - size_t isisToRemove = - (size_t)((isiValues.size() + 1) * spikeSkipf + .5); + size_t isisToRemove = (size_t)((isiValues.size() + 1) * spikeSkipf + .5); isisToRemove = std::min(maxnSpike, isisToRemove); @@ -112,7 +112,8 @@ int LibV5::ISI_log_slope_skip(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& isivalues = getFeature(DoubleFeatureData, {"ISI_values"}); - const auto spikeSkipf = getFeature(DoubleFeatureData, {"spike_skipf"}).front(); + const auto spikeSkipf = + getFeature(DoubleFeatureData, {"spike_skipf"}).front(); const auto maxnSpike = getFeature(IntFeatureData, {"max_spike_skip"}).front(); // Check the validity of spikeSkipf value @@ -123,7 +124,8 @@ int LibV5::ISI_log_slope_skip(mapStr2intVec& IntFeatureData, vector slope; bool semilog = false; - int retVal = __ISI_log_slope(isivalues, slope, true, spikeSkipf, maxnSpike, semilog); + int retVal = + __ISI_log_slope(isivalues, slope, true, spikeSkipf, maxnSpike, semilog); if (retVal >= 0) { setVec(DoubleFeatureData, StringData, "ISI_log_slope_skip", slope); return static_cast(slope.size()); @@ -136,12 +138,13 @@ int LibV5::ISI_log_slope_skip(mapStr2intVec& IntFeatureData, int LibV5::time_to_second_spike(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); + const auto doubleFeatures = + getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); const auto& peaktime = doubleFeatures.at("peak_time"); const auto& stimstart = doubleFeatures.at("stim_start"); if (peaktime.size() < 2) { - GErrorStr += "\n Two spikes required for time_to_second_spike.\n"; - return -1; + GErrorStr += "\n Two spikes required for time_to_second_spike.\n"; + return -1; } vector second_spike = {peaktime[1] - stimstart[0]}; setVec(DoubleFeatureData, StringData, "time_to_second_spike", second_spike); @@ -152,7 +155,8 @@ int LibV5::time_to_second_spike(mapStr2intVec& IntFeatureData, int LibV5::time_to_last_spike(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); + const auto doubleFeatures = + getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); const auto& peaktime = doubleFeatures.at("peak_time"); const auto& stimstart = doubleFeatures.at("stim_start"); @@ -162,7 +166,8 @@ int LibV5::time_to_last_spike(mapStr2intVec& IntFeatureData, return 1; } -double calculateInvISI(const std::vector& all_isi_values_vec, size_t index) { +double calculateInvISI(const std::vector& all_isi_values_vec, + size_t index) { if (index < all_isi_values_vec.size()) { return 1000.0 / all_isi_values_vec[index]; } @@ -171,18 +176,28 @@ double calculateInvISI(const std::vector& all_isi_values_vec, size_t ind int LibV5::inv_ISI_generic(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData, - size_t index) { - const auto& all_isi_values_vec = getFeature(DoubleFeatureData, {"all_ISI_values"}); + mapStr2Str& StringData, size_t index) { + const auto& all_isi_values_vec = + getFeature(DoubleFeatureData, {"all_ISI_values"}); double inv_ISI = calculateInvISI(all_isi_values_vec, index); std::string featureName; switch (index) { - case 0: featureName = "inv_first_ISI"; break; - case 1: featureName = "inv_second_ISI"; break; - case 2: featureName = "inv_third_ISI"; break; - case 3: featureName = "inv_fourth_ISI"; break; - case 4: featureName = "inv_fifth_ISI"; break; + case 0: + featureName = "inv_first_ISI"; + break; + case 1: + featureName = "inv_second_ISI"; + break; + case 2: + featureName = "inv_third_ISI"; + break; + case 3: + featureName = "inv_fourth_ISI"; + break; + case 4: + featureName = "inv_fifth_ISI"; + break; default: if (index == all_isi_values_vec.size() - 1) { featureName = "inv_last_ISI"; @@ -201,9 +216,11 @@ int LibV5::inv_ISI_generic(mapStr2intVec& IntFeatureData, int LibV5::inv_last_ISI(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& all_isi_values_vec = getFeature(DoubleFeatureData, "all_ISI_values"); - - double inv_last_ISI = calculateInvISI(all_isi_values_vec, all_isi_values_vec.size() - 1); // Last ISI + const auto& all_isi_values_vec = + getFeature(DoubleFeatureData, "all_ISI_values"); + + double inv_last_ISI = calculateInvISI( + all_isi_values_vec, all_isi_values_vec.size() - 1); // Last ISI vector inv_last_ISI_vec = {inv_last_ISI}; setVec(DoubleFeatureData, StringData, "inv_last_ISI", inv_last_ISI_vec); return 1; @@ -213,13 +230,15 @@ int LibV5::inv_last_ISI(mapStr2intVec& IntFeatureData, int LibV5::inv_time_to_first_spike(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - vector time_to_first_spike_vec = getFeature(DoubleFeatureData, "time_to_first_spike"); + vector time_to_first_spike_vec = + getFeature(DoubleFeatureData, "time_to_first_spike"); vector inv_time_to_first_spike_vec; double inv_time_to_first_spike = 1000.0 / time_to_first_spike_vec[0]; inv_time_to_first_spike_vec.push_back(inv_time_to_first_spike); - setVec(DoubleFeatureData, StringData, "inv_time_to_first_spike", inv_time_to_first_spike_vec); + setVec(DoubleFeatureData, StringData, "inv_time_to_first_spike", + inv_time_to_first_spike_vec); return 1; } @@ -233,9 +252,10 @@ static int __min_AHP_indices(const vector& t, const vector& v, unsigned end_index = 0; if (strict_stiminterval) { - end_index = distance(t.begin(), find_if(t.begin(), t.end(), [stim_end](double t_val) { - return t_val >= stim_end; - })); + end_index = distance(t.begin(), + find_if(t.begin(), t.end(), [stim_end](double t_val) { + return t_val >= stim_end; + })); } else { end_index = distance(t.begin(), t.end()); } @@ -269,29 +289,31 @@ int LibV5::min_AHP_indices(mapStr2intVec& IntFeatureData, mapStr2Str& StringData) { int retVal; // Retrieve all required double features at once - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); vector min_ahp_indices; vector min_ahp_values; double stim_start = doubleFeatures.at("stim_start")[0]; double stim_end = doubleFeatures.at("stim_end")[0]; - // Get strict_stiminterval + // Get strict_stiminterval vector strict_stiminterval_vec; bool strict_stiminterval; - retVal = getParam(IntFeatureData, "strict_stiminterval", - strict_stiminterval_vec); + retVal = + getParam(IntFeatureData, "strict_stiminterval", strict_stiminterval_vec); if (retVal <= 0) { strict_stiminterval = false; } else { strict_stiminterval = bool(strict_stiminterval_vec[0]); } - retVal = __min_AHP_indices(doubleFeatures.at("T"), doubleFeatures.at("V"), intFeatures.at("peak_indices"), - stim_start, stim_end, strict_stiminterval, min_ahp_indices, min_ahp_values); + retVal = + __min_AHP_indices(doubleFeatures.at("T"), doubleFeatures.at("V"), + intFeatures.at("peak_indices"), stim_start, stim_end, + strict_stiminterval, min_ahp_indices, min_ahp_values); - if (retVal == 0) - return -1; + if (retVal == 0) return -1; if (retVal > 0) { setVec(IntFeatureData, StringData, "min_AHP_indices", min_ahp_indices); setVec(DoubleFeatureData, StringData, "min_AHP_values", min_ahp_values); @@ -321,10 +343,10 @@ static int __spike_width1(const vector& t, const vector& v, const vector& peak_indices, const vector& min_ahp_indices, double stim_start, vector& spike_width1) { - int start_index = - distance(t.begin(), - find_if(t.begin(), t.end(), - [stim_start](double t_val){ return t_val >= stim_start; })); + int start_index = distance( + t.begin(), find_if(t.begin(), t.end(), [stim_start](double t_val) { + return t_val >= stim_start; + })); vector min_ahp_indices_plus(min_ahp_indices.size() + 1, start_index); copy(min_ahp_indices.begin(), min_ahp_indices.end(), min_ahp_indices_plus.begin() + 1); @@ -340,7 +362,7 @@ static int __spike_width1(const vector& t, const vector& v, int rise_index = distance( v.begin(), find_if(v.begin() + min_ahp_indices_plus[i - 1], v.begin() + peak_indices[i - 1], - [v_half](double v_val){ return v_val >= v_half; })); + [v_half](double v_val) { return v_val >= v_half; })); v_dev = v_half - v[rise_index]; delta_v = v[rise_index] - v[rise_index - 1]; delta_t = t[rise_index] - t[rise_index - 1]; @@ -348,7 +370,7 @@ static int __spike_width1(const vector& t, const vector& v, int fall_index = distance( v.begin(), find_if(v.begin() + peak_indices[i - 1], v.begin() + min_ahp_indices_plus[i], - [v_half](double v_val){ return v_val <= v_half; })); + [v_half](double v_val) { return v_val <= v_half; })); v_dev = v_half - v[fall_index]; delta_v = v[fall_index] - v[fall_index - 1]; delta_t = t[fall_index] - t[fall_index - 1]; @@ -362,19 +384,24 @@ static int __spike_width1(const vector& t, const vector& v, int LibV5::spike_width1(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"V", "T", "stim_start"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); vector spike_width1; // Check if peak_indices and min_AHP_indices are empty - if (intFeatures.at("peak_indices").empty() || intFeatures.at("min_AHP_indices").empty()) { + if (intFeatures.at("peak_indices").empty() || + intFeatures.at("min_AHP_indices").empty()) { setVec(DoubleFeatureData, StringData, "spike_half_width", spike_width1); return 0; } // Calculate spike width - int retVal = __spike_width1(doubleFeatures.at("T"), doubleFeatures.at("V"), intFeatures.at("peak_indices"), - intFeatures.at("min_AHP_indices"), doubleFeatures.at("stim_start")[0], spike_width1); + int retVal = __spike_width1(doubleFeatures.at("T"), doubleFeatures.at("V"), + intFeatures.at("peak_indices"), + intFeatures.at("min_AHP_indices"), + doubleFeatures.at("stim_start")[0], spike_width1); if (retVal >= 0) { setVec(DoubleFeatureData, StringData, "spike_half_width", spike_width1); @@ -387,9 +414,9 @@ int LibV5::spike_width1(mapStr2intVec& IntFeatureData, // static int __AP_begin_indices(const vector& t, const vector& v, double stimstart, double stimend, - const vector& pi, - const vector& ahpi, vector& apbi, - double dTh, int derivative_window) { + const vector& pi, const vector& ahpi, + vector& apbi, double dTh, + int derivative_window) { const double derivativethreshold = dTh; vector dvdt(v.size()); vector dv; @@ -401,16 +428,17 @@ static int __AP_begin_indices(const vector& t, const vector& v, // restrict to time interval where stimulus is applied vector minima, peak_indices; - auto stimbeginindex = distance(t.begin(), - find_if(t.begin(), t.end(), - [stimstart](double time){ return time >= stimstart; })); - - if (stimbeginindex > 1){ + auto stimbeginindex = + distance(t.begin(), find_if(t.begin(), t.end(), [stimstart](double time) { + return time >= stimstart; + })); + + if (stimbeginindex > 1) { // to avoid skipping AP_begin when it is exactly at stimbeginindex - // also because of float precision and interpolation, sometimes stimbeginindex - // can be slightly above 'real' stim begin index + // also because of float precision and interpolation, sometimes + // stimbeginindex can be slightly above 'real' stim begin index minima.push_back(stimbeginindex - 2); - } else if (stimbeginindex == 1){ + } else if (stimbeginindex == 1) { minima.push_back(stimbeginindex - 1); } else { minima.push_back(stimbeginindex); @@ -423,13 +451,13 @@ static int __AP_begin_indices(const vector& t, const vector& v, // break; //} } - for (size_t i = 0; i < pi.size(); i++) { + for (size_t i = 0; i < pi.size(); i++) { if (pi[i] > stimbeginindex) { peak_indices.push_back(pi[i]); } } int endindex = distance(t.begin(), t.end()); - if (minima.size() < peak_indices.size()){ + if (minima.size() < peak_indices.size()) { GErrorStr += "\nMore peaks than min_AHP in AP_begin_indices\n"; return -1; } @@ -445,29 +473,32 @@ static int __AP_begin_indices(const vector& t, const vector& v, // Detect where the derivate crosses derivativethreshold, and make sure // this happens in a window of 'width' sampling point do { - begin = distance( - dvdt.begin(), - find_if( - // use reverse iterator to get last occurence - // and avoid false positive long before the spike - dvdt.rbegin() + v.size() - newbegin, - dvdt.rbegin() + v.size() - minima[i], - [derivativethreshold](double val) { return val <= derivativethreshold; }).base()); - // cover edge case to avoid going out of index in the while condition - if (begin > endindex - width){ - begin = endindex - width; - } - // printf("%d %d\n", newbegin, minima[i+1]); - if (begin == minima[i]) { - // printf("Skipping %d %d\n", newbegin, minima[i+1]); - // could not find a spike in between these minima - skip = true; - break; - } - newbegin = begin - 1; - } while (find_if(dvdt.begin() + begin, dvdt.begin() + begin + width, - [derivativethreshold](double val) { return val < derivativethreshold; }) != - dvdt.begin() + begin + width); + begin = distance(dvdt.begin(), + find_if( + // use reverse iterator to get last occurence + // and avoid false positive long before the spike + dvdt.rbegin() + v.size() - newbegin, + dvdt.rbegin() + v.size() - minima[i], + [derivativethreshold](double val) { + return val <= derivativethreshold; + }) + .base()); + // cover edge case to avoid going out of index in the while condition + if (begin > endindex - width) { + begin = endindex - width; + } + // printf("%d %d\n", newbegin, minima[i+1]); + if (begin == minima[i]) { + // printf("Skipping %d %d\n", newbegin, minima[i+1]); + // could not find a spike in between these minima + skip = true; + break; + } + newbegin = begin - 1; + } while (find_if(dvdt.begin() + begin, dvdt.begin() + begin + width, + [derivativethreshold](double val) { + return val < derivativethreshold; + }) != dvdt.begin() + begin + width); if (skip) { continue; } @@ -480,8 +511,10 @@ int LibV5::AP_begin_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { // Retrieve all required double and int features at once - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "stim_start", "stim_end"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"T", "V", "stim_start", "stim_end"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices"}); vector apbi; @@ -501,11 +534,13 @@ int LibV5::AP_begin_indices(mapStr2intVec& IntFeatureData, GErrorStr += "\nDerivativeWindow not set\n"; return -1; } - + // Calculate feature - retVal = __AP_begin_indices(doubleFeatures.at("T"), doubleFeatures.at("V"), doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0], intFeatures.at("peak_indices"), - intFeatures.at("min_AHP_indices"), apbi, dTh[0], derivative_window[0]); + retVal = __AP_begin_indices( + doubleFeatures.at("T"), doubleFeatures.at("V"), + doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0], + intFeatures.at("peak_indices"), intFeatures.at("min_AHP_indices"), apbi, + dTh[0], derivative_window[0]); // Save feature value if (retVal >= 0) { @@ -517,7 +552,6 @@ int LibV5::AP_begin_indices(mapStr2intVec& IntFeatureData, static int __AP_end_indices(const vector& t, const vector& v, const vector& pi, vector& apei, double derivativethreshold) { - vector dvdt(v.size()); vector dv; vector dt; @@ -532,19 +566,19 @@ static int __AP_end_indices(const vector& t, const vector& v, picopy.push_back(v.size() - 1); for (size_t i = 0; i < apei.size(); i++) { - max_slope = distance( - dvdt.begin(), - std::min_element(dvdt.begin() + picopy[i] + 1, dvdt.begin() + picopy[i + 1])); + max_slope = + distance(dvdt.begin(), std::min_element(dvdt.begin() + picopy[i] + 1, + dvdt.begin() + picopy[i + 1])); // assure that the width of the slope is bigger than 4 - apei[i] = distance( - dvdt.begin(), - find_if(dvdt.begin() + max_slope, dvdt.begin() + picopy[i + 1], - [derivativethreshold](double x){ return x >= derivativethreshold; })); + apei[i] = distance(dvdt.begin(), find_if(dvdt.begin() + max_slope, + dvdt.begin() + picopy[i + 1], + [derivativethreshold](double x) { + return x >= derivativethreshold; + })); } return apei.size(); } - int LibV5::AP_end_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { @@ -557,15 +591,14 @@ int LibV5::AP_end_indices(mapStr2intVec& IntFeatureData, double downDerivativeThreshold = (retVal <= 0) ? -12.0 : dTh[0]; vector AP_end_indices; - retVal = __AP_end_indices(T, V, peak_indices, AP_end_indices, downDerivativeThreshold); + retVal = __AP_end_indices(T, V, peak_indices, AP_end_indices, + downDerivativeThreshold); if (retVal >= 0) { setVec(IntFeatureData, StringData, "AP_end_indices", AP_end_indices); } return retVal; } - - static int __irregularity_index(const vector& isiValues, vector& irregularity_index) { double ISISub, iRI; @@ -589,25 +622,27 @@ int LibV5::irregularity_index(mapStr2intVec& IntFeatureData, vector irregularity_index; int retVal = __irregularity_index(isiValues, irregularity_index); if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "irregularity_index", irregularity_index); + setVec(DoubleFeatureData, StringData, "irregularity_index", + irregularity_index); } return retVal; } -static int __number_initial_spikes(const vector& peak_times, double stimstart, - double stimend, double initial_perc, - vector& number_initial_spikes) { +static int __number_initial_spikes(const vector& peak_times, + double stimstart, double stimend, + double initial_perc, + vector& number_initial_spikes) { double initialLength = (stimend - stimstart) * initial_perc; int startIndex = - distance(peak_times.begin(), - find_if(peak_times.begin(), peak_times.end(), - [stimstart](double t){ return t >= stimstart; })); + distance(peak_times.begin(), + find_if(peak_times.begin(), peak_times.end(), + [stimstart](double t) { return t >= stimstart; })); int endIndex = distance(peak_times.begin(), - find_if(peak_times.begin(), peak_times.end(), - [stimstart, initialLength](double t){ - return t >= stimstart + initialLength; - })); + find_if(peak_times.begin(), peak_times.end(), + [stimstart, initialLength](double t) { + return t >= stimstart + initialLength; + })); number_initial_spikes.push_back(endIndex - startIndex); @@ -618,7 +653,9 @@ static int __number_initial_spikes(const vector& peak_times, double stim int LibV5::number_initial_spikes(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "initial_perc", "stim_start", "stim_end"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, + {"peak_time", "initial_perc", "stim_start", "stim_end"}); vector number_initial_spikes; const vector& peak_times = doubleFeatures.at("peak_time"); @@ -633,7 +670,8 @@ int LibV5::number_initial_spikes(mapStr2intVec& IntFeatureData, int retVal = __number_initial_spikes(peak_times, stimstart[0], stimend[0], initial_perc[0], number_initial_spikes); if (retVal >= 0) { - setVec(IntFeatureData, StringData, "number_initial_spikes", number_initial_spikes); + setVec(IntFeatureData, StringData, "number_initial_spikes", + number_initial_spikes); } return retVal; } @@ -642,7 +680,8 @@ int LibV5::number_initial_spikes(mapStr2intVec& IntFeatureData, int LibV5::AP1_amp(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& AP_amplitudes = getFeature(DoubleFeatureData, "AP_amplitude"); + const vector& AP_amplitudes = + getFeature(DoubleFeatureData, "AP_amplitude"); vector AP1_amp; AP1_amp.push_back(AP_amplitudes[0]); setVec(DoubleFeatureData, StringData, "AP1_amp", AP1_amp); @@ -653,19 +692,20 @@ int LibV5::AP1_amp(mapStr2intVec& IntFeatureData, int LibV5::APlast_amp(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& AP_amplitudes = getFeature(DoubleFeatureData, "AP_amplitude"); + const vector& AP_amplitudes = + getFeature(DoubleFeatureData, "AP_amplitude"); vector APlast_amp; APlast_amp.push_back(AP_amplitudes[AP_amplitudes.size() - 1]); setVec(DoubleFeatureData, StringData, "APlast_amp", APlast_amp); return 1; } - // Peak voltage of the first spike int LibV5::AP1_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& peak_voltage = getFeature(DoubleFeatureData, "peak_voltage"); + const vector& peak_voltage = + getFeature(DoubleFeatureData, "peak_voltage"); vector AP1_peak; AP1_peak.push_back(peak_voltage[0]); setVec(DoubleFeatureData, StringData, "AP1_peak", AP1_peak); @@ -676,10 +716,12 @@ int LibV5::AP1_peak(mapStr2intVec& IntFeatureData, int LibV5::AP2_amp(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& AP_amplitudes = getFeature(DoubleFeatureData, "AP_amplitude"); + const vector& AP_amplitudes = + getFeature(DoubleFeatureData, "AP_amplitude"); vector AP2_amp; if (AP_amplitudes.size() < 2) { - throw FeatureComputationError("Size of AP_amplitude should be >= 2 for AP2_amp"); + throw FeatureComputationError( + "Size of AP_amplitude should be >= 2 for AP2_amp"); } else { AP2_amp.push_back(AP_amplitudes[1]); setVec(DoubleFeatureData, StringData, "AP2_amp", AP2_amp); @@ -691,10 +733,12 @@ int LibV5::AP2_amp(mapStr2intVec& IntFeatureData, int LibV5::AP2_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& peak_voltage = getFeature(DoubleFeatureData, "peak_voltage"); + const vector& peak_voltage = + getFeature(DoubleFeatureData, "peak_voltage"); vector AP2_peak; if (peak_voltage.size() < 2) { - throw FeatureComputationError("Size of peak_voltage should be >= 2 for AP2_peak"); + throw FeatureComputationError( + "Size of peak_voltage should be >= 2 for AP2_peak"); } else { AP2_peak.push_back(peak_voltage[1]); setVec(DoubleFeatureData, StringData, "AP2_peak", AP2_peak); @@ -706,10 +750,12 @@ int LibV5::AP2_peak(mapStr2intVec& IntFeatureData, int LibV5::AP2_AP1_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& AP_amplitudes = getFeature(DoubleFeatureData, "AP_amplitude"); + const vector& AP_amplitudes = + getFeature(DoubleFeatureData, "AP_amplitude"); vector AP2_AP1_diff; if (AP_amplitudes.size() < 2) { - throw FeatureComputationError("Size of AP_amplitude should be >= 2 for AP2_AP1_diff"); + throw FeatureComputationError( + "Size of AP_amplitude should be >= 2 for AP2_AP1_diff"); } else { AP2_AP1_diff.push_back(AP_amplitudes[1] - AP_amplitudes[0]); setVec(DoubleFeatureData, StringData, "AP2_AP1_diff", AP2_AP1_diff); @@ -721,13 +767,16 @@ int LibV5::AP2_AP1_diff(mapStr2intVec& IntFeatureData, int LibV5::AP2_AP1_peak_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& peak_voltage = getFeature(DoubleFeatureData, "peak_voltage"); + const vector& peak_voltage = + getFeature(DoubleFeatureData, "peak_voltage"); vector AP2_AP1_peak_diff; if (peak_voltage.size() < 2) { - throw FeatureComputationError("Size of peak_voltage should be >= 2 for AP2_AP1_peak_diff"); + throw FeatureComputationError( + "Size of peak_voltage should be >= 2 for AP2_AP1_peak_diff"); } else { AP2_AP1_peak_diff.push_back(peak_voltage[1] - peak_voltage[0]); - setVec(DoubleFeatureData, StringData, "AP2_AP1_peak_diff", AP2_AP1_peak_diff); + setVec(DoubleFeatureData, StringData, "AP2_AP1_peak_diff", + AP2_AP1_peak_diff); return 1; } } @@ -736,7 +785,8 @@ int LibV5::AP2_AP1_peak_diff(mapStr2intVec& IntFeatureData, int LibV5::AP1_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& spike_half_width = getFeature(DoubleFeatureData, "spike_half_width"); + const vector& spike_half_width = + getFeature(DoubleFeatureData, "spike_half_width"); vector AP1_width; AP1_width.push_back(spike_half_width[0]); setVec(DoubleFeatureData, StringData, "AP1_width", AP1_width); @@ -747,10 +797,12 @@ int LibV5::AP1_width(mapStr2intVec& IntFeatureData, int LibV5::AP2_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& spike_half_width = getFeature(DoubleFeatureData, "spike_half_width"); + const vector& spike_half_width = + getFeature(DoubleFeatureData, "spike_half_width"); vector AP2_width; if (spike_half_width.size() < 2) { - throw FeatureComputationError("Size of spike_half_width should be >= 2 for AP2_width"); + throw FeatureComputationError( + "Size of spike_half_width should be >= 2 for AP2_width"); } else { AP2_width.push_back(spike_half_width[1]); setVec(DoubleFeatureData, StringData, "AP2_width", AP2_width); @@ -762,20 +814,19 @@ int LibV5::AP2_width(mapStr2intVec& IntFeatureData, int LibV5::APlast_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& spike_half_width = getFeature(DoubleFeatureData, "spike_half_width"); + const vector& spike_half_width = + getFeature(DoubleFeatureData, "spike_half_width"); vector APlast_width; APlast_width.push_back(spike_half_width[spike_half_width.size() - 1]); setVec(DoubleFeatureData, StringData, "APlast_width", APlast_width); return 1; } - static int __AHP_time_from_peak(const vector& t, const vector& peakIndices, const vector& minAHPIndices, vector& ahpTimeFromPeak) { - for (size_t i = 0; i < peakIndices.size() && i < minAHPIndices.size(); - i++) { + for (size_t i = 0; i < peakIndices.size() && i < minAHPIndices.size(); i++) { ahpTimeFromPeak.push_back(t[minAHPIndices[i]] - t[peakIndices[i]]); } return ahpTimeFromPeak.size(); @@ -785,14 +836,17 @@ int LibV5::AHP_time_from_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices"}); vector ahpTimeFromPeak; const vector& T = doubleFeatures.at("T"); const vector& peakIndices = intFeatures.at("peak_indices"); const vector& minAHPIndices = intFeatures.at("min_AHP_indices"); - int retVal = __AHP_time_from_peak(T, peakIndices, minAHPIndices, ahpTimeFromPeak); + int retVal = + __AHP_time_from_peak(T, peakIndices, minAHPIndices, ahpTimeFromPeak); if (retVal > 0) { - setVec(DoubleFeatureData, StringData, "AHP_time_from_peak", ahpTimeFromPeak); + setVec(DoubleFeatureData, StringData, "AHP_time_from_peak", + ahpTimeFromPeak); } return retVal; } @@ -812,14 +866,17 @@ int LibV5::AHP_depth_from_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"peak_indices", "min_AHP_indices"}); vector ahpDepthFromPeak; const vector& V = doubleFeatures.at("V"); const vector& peakIndices = intFeatures.at("peak_indices"); const vector& minAHPIndices = intFeatures.at("min_AHP_indices"); - int retVal = __AHP_depth_from_peak(V, peakIndices, minAHPIndices, ahpDepthFromPeak); + int retVal = + __AHP_depth_from_peak(V, peakIndices, minAHPIndices, ahpDepthFromPeak); if (retVal > 0) { - setVec(DoubleFeatureData, StringData, "AHP_depth_from_peak", ahpDepthFromPeak); + setVec(DoubleFeatureData, StringData, "AHP_depth_from_peak", + ahpDepthFromPeak); } return retVal; } @@ -828,10 +885,12 @@ int LibV5::AHP_depth_from_peak(mapStr2intVec& IntFeatureData, int LibV5::AHP1_depth_from_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& ahpDepthFromPeak = getFeature(DoubleFeatureData, "AHP_depth_from_peak"); + const vector& ahpDepthFromPeak = + getFeature(DoubleFeatureData, "AHP_depth_from_peak"); vector ahp1DepthFromPeak; ahp1DepthFromPeak.push_back(ahpDepthFromPeak[0]); - setVec(DoubleFeatureData, StringData, "AHP1_depth_from_peak", ahp1DepthFromPeak); + setVec(DoubleFeatureData, StringData, "AHP1_depth_from_peak", + ahp1DepthFromPeak); return 1; } @@ -839,14 +898,17 @@ int LibV5::AHP1_depth_from_peak(mapStr2intVec& IntFeatureData, int LibV5::AHP2_depth_from_peak(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& ahpDepthFromPeak = getFeature(DoubleFeatureData, "AHP_depth_from_peak"); + const vector& ahpDepthFromPeak = + getFeature(DoubleFeatureData, "AHP_depth_from_peak"); vector ahp2DepthFromPeak; if (ahpDepthFromPeak.size() < 2) { - throw FeatureComputationError("Size of AHP_depth_from_peak should be >= 2 for AHP2_depth_from_peak"); + throw FeatureComputationError( + "Size of AHP_depth_from_peak should be >= 2 for AHP2_depth_from_peak"); } else { ahp2DepthFromPeak.push_back(ahpDepthFromPeak[1]); } - setVec(DoubleFeatureData, StringData, "AHP2_depth_from_peak", ahp2DepthFromPeak); + setVec(DoubleFeatureData, StringData, "AHP2_depth_from_peak", + ahp2DepthFromPeak); return 1; } @@ -864,11 +926,10 @@ static int __AP_begin_width(const vector& t, const vector& v, // keep only min_ahp_indices values that are after stim start // because AP_begin_indices are all after stim start - // if not done, could cause cases where AP_begin_indices[i] > min_ahp_indices[i] - // leading to segmentation faults - auto it = find_if(t.begin(), t.end(), [stimstart](double val) { - return val >= stimstart; - }); + // if not done, could cause cases where AP_begin_indices[i] > + // min_ahp_indices[i] leading to segmentation faults + auto it = find_if(t.begin(), t.end(), + [stimstart](double val) { return val >= stimstart; }); int stimbeginindex = distance(t.begin(), it); vector strict_min_ahp_indices; for (size_t i = 0; i < min_ahp_indices.size(); i++) { @@ -884,9 +945,10 @@ static int __AP_begin_width(const vector& t, const vector& v, // the falling edge int rise_index = AP_begin_indices[i]; int fall_index = distance( - v.begin(), - find_if(v.begin() + rise_index + 1, v.begin() + strict_min_ahp_indices[i], - [v_start](const auto& val){ return val <= v_start; })); + v.begin(), + find_if(v.begin() + rise_index + 1, + v.begin() + strict_min_ahp_indices[i], + [v_start](const auto& val) { return val <= v_start; })); // v_dev = v_start - v[fall_index]; // delta_v = v[fall_index] - v[fall_index - 1]; // delta_t = t[fall_index] - t[fall_index - 1]; @@ -900,15 +962,18 @@ static int __AP_begin_width(const vector& t, const vector& v, int LibV5::AP_begin_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "AP_begin_indices"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"V", "T", "stim_start"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"min_AHP_indices", "AP_begin_indices"}); vector AP_begin_width; const vector& V = doubleFeatures.at("V"); const vector& t = doubleFeatures.at("T"); const vector& stim_start = doubleFeatures.at("stim_start"); const vector& min_AHP_indices = intFeatures.at("min_AHP_indices"); const vector& AP_begin_indices = intFeatures.at("AP_begin_indices"); - int retVal = __AP_begin_width(t, V, stim_start[0], AP_begin_indices, min_AHP_indices, AP_begin_width); + int retVal = __AP_begin_width(t, V, stim_start[0], AP_begin_indices, + min_AHP_indices, AP_begin_width); if (retVal > 0) { setVec(DoubleFeatureData, StringData, "AP_begin_width", AP_begin_width); } @@ -968,7 +1033,8 @@ int LibV5::AP_begin_voltage(mapStr2intVec& IntFeatureData, int LibV5::AP1_begin_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& AP_begin_voltage = getFeature(DoubleFeatureData, "AP_begin_voltage"); + const vector& AP_begin_voltage = + getFeature(DoubleFeatureData, "AP_begin_voltage"); vector AP1_begin_voltage; AP1_begin_voltage.push_back(AP_begin_voltage[0]); setVec(DoubleFeatureData, StringData, "AP1_begin_voltage", AP1_begin_voltage); @@ -978,7 +1044,8 @@ int LibV5::AP1_begin_voltage(mapStr2intVec& IntFeatureData, int LibV5::AP2_begin_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& AP_begin_voltage = getFeature(DoubleFeatureData, "AP_begin_voltage"); + const vector& AP_begin_voltage = + getFeature(DoubleFeatureData, "AP_begin_voltage"); vector AP2_begin_voltage; if (AP_begin_voltage.size() < 2) { @@ -994,7 +1061,8 @@ int LibV5::AP2_begin_voltage(mapStr2intVec& IntFeatureData, int LibV5::AP1_begin_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& AP_begin_width = getFeature(DoubleFeatureData, "AP_begin_width"); + const vector& AP_begin_width = + getFeature(DoubleFeatureData, "AP_begin_width"); vector AP1_begin_width; AP1_begin_width.push_back(AP_begin_width[0]); setVec(DoubleFeatureData, StringData, "AP1_begin_width", AP1_begin_width); @@ -1004,7 +1072,8 @@ int LibV5::AP1_begin_width(mapStr2intVec& IntFeatureData, int LibV5::AP2_begin_width(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& AP_begin_width = getFeature(DoubleFeatureData, "AP_begin_width"); + const vector& AP_begin_width = + getFeature(DoubleFeatureData, "AP_begin_width"); vector AP2_begin_width; if (AP_begin_width.size() < 2) { throw FeatureComputationError("There are less than 2 spikes in the trace."); @@ -1019,14 +1088,16 @@ int LibV5::AP2_begin_width(mapStr2intVec& IntFeatureData, int LibV5::AP2_AP1_begin_width_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& AP_begin_widths = getFeature(DoubleFeatureData, "AP_begin_width"); + const vector& AP_begin_widths = + getFeature(DoubleFeatureData, "AP_begin_width"); vector AP2_AP1_begin_width_diff; if (AP_begin_widths.size() < 2) { throw FeatureComputationError("There are less than 2 spikes in the trace."); } else { AP2_AP1_begin_width_diff.push_back(AP_begin_widths[1] - AP_begin_widths[0]); } - setVec(DoubleFeatureData, StringData, "AP2_AP1_begin_width_diff", AP2_AP1_begin_width_diff); + setVec(DoubleFeatureData, StringData, "AP2_AP1_begin_width_diff", + AP2_AP1_begin_width_diff); return 1; } @@ -1089,7 +1160,8 @@ int LibV5::is_not_stuck(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const vector& peak_time = getFeature(DoubleFeatureData, "peak_time"); - const vector& stim_start = getFeature(DoubleFeatureData, "stim_start"); + const vector& stim_start = + getFeature(DoubleFeatureData, "stim_start"); const vector& stim_end = getFeature(DoubleFeatureData, "stim_end"); bool stuck = true; for (const auto& pt : peak_time) { @@ -1110,8 +1182,8 @@ int LibV5::is_not_stuck(mapStr2intVec& IntFeatureData, // The mean voltage after the stimulus in (stim_end + 25%*end_period, stim_end + // 75%*end_period) int LibV5::voltage_after_stim(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { const vector& v = getFeature(DoubleFeatureData, "V"); const vector& t = getFeature(DoubleFeatureData, "T"); const vector& stimEnd = getFeature(DoubleFeatureData, "stim_end"); @@ -1139,7 +1211,8 @@ int LibV5::voltage_after_stim(mapStr2intVec& IntFeatureData, int LibV5::mean_AP_amplitude(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& AP_amplitude = getFeature(DoubleFeatureData, "AP_amplitude"); + const vector& AP_amplitude = + getFeature(DoubleFeatureData, "AP_amplitude"); double mean_amp = 0.0; for (const auto& amplitude : AP_amplitude) { mean_amp += amplitude; @@ -1153,7 +1226,6 @@ int LibV5::mean_AP_amplitude(mapStr2intVec& IntFeatureData, return mean_AP_amplitude.size(); } - static int __AP_phaseslope(const vector& v, const vector& t, double stimStart, double stimEnd, vector& ap_phaseslopes, vector apbi, @@ -1192,18 +1264,16 @@ static int __AP_phaseslope(const vector& v, const vector& t, int LibV5::AP_phaseslope(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end", "AP_phaseslope_range"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, + {"V", "T", "stim_start", "stim_end", "AP_phaseslope_range"}); const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices"}); vector ap_phaseslopes; - int retVal = __AP_phaseslope( - doubleFeatures.at("V"), - doubleFeatures.at("T"), - doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0], - ap_phaseslopes, - intFeatures.at("AP_begin_indices"), - doubleFeatures.at("AP_phaseslope_range")[0] - ); + int retVal = __AP_phaseslope(doubleFeatures.at("V"), doubleFeatures.at("T"), + doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], ap_phaseslopes, + intFeatures.at("AP_begin_indices"), + doubleFeatures.at("AP_phaseslope_range")[0]); if (retVal > 0) { setVec(DoubleFeatureData, StringData, "AP_phaseslope", ap_phaseslopes); @@ -1232,12 +1302,14 @@ int LibV5::all_ISI_values(mapStr2intVec& IntFeatureData, int LibV5::AP_amplitude_from_voltagebase(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_base", "peak_voltage"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"voltage_base", "peak_voltage"}); vector apamplitude; for (const auto& peak : doubleFeatures.at("peak_voltage")) { apamplitude.push_back(peak - doubleFeatures.at("voltage_base")[0]); } - setVec(DoubleFeatureData, StringData, "AP_amplitude_from_voltagebase", apamplitude); + setVec(DoubleFeatureData, StringData, "AP_amplitude_from_voltagebase", + apamplitude); return apamplitude.size(); } @@ -1249,18 +1321,21 @@ int LibV5::min_voltage_between_spikes(mapStr2intVec& IntFeatureData, const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); if (intFeatures.at("peak_indices").size() < 2) { - setVec(DoubleFeatureData, StringData, "min_voltage_between_spikes", vector()); + setVec(DoubleFeatureData, StringData, "min_voltage_between_spikes", + vector()); return 0; } vector min_voltage_between_spikes; for (size_t i = 0; i < intFeatures.at("peak_indices").size() - 1; i++) { min_voltage_between_spikes.push_back(*min_element( - doubleFeatures.at("V").begin() + intFeatures.at("peak_indices")[i], - doubleFeatures.at("V").begin() + intFeatures.at("peak_indices")[i + 1])); + doubleFeatures.at("V").begin() + intFeatures.at("peak_indices")[i], + doubleFeatures.at("V").begin() + + intFeatures.at("peak_indices")[i + 1])); } - setVec(DoubleFeatureData, StringData, "min_voltage_between_spikes", min_voltage_between_spikes); + setVec(DoubleFeatureData, StringData, "min_voltage_between_spikes", + min_voltage_between_spikes); return min_voltage_between_spikes.size(); } @@ -1268,34 +1343,34 @@ int LibV5::min_voltage_between_spikes(mapStr2intVec& IntFeatureData, int LibV5::voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& v = getFeature(DoubleFeatureData, "V"); - setVec(DoubleFeatureData, StringData, "voltage", v); - return v.size(); + const vector& v = getFeature(DoubleFeatureData, "V"); + setVec(DoubleFeatureData, StringData, "voltage", v); + return v.size(); } // return (possibly interpolate) current trace int LibV5::current(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const vector& i = getFeature(DoubleFeatureData, "I"); - setVec(DoubleFeatureData, StringData, "current", i); - return i.size(); + const vector& i = getFeature(DoubleFeatureData, "I"); + setVec(DoubleFeatureData, StringData, "current", i); + return i.size(); } // return (possibly interpolate) time trace int LibV5::time(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const vector& t = getFeature(DoubleFeatureData, "T"); - setVec(DoubleFeatureData, StringData, "time", t); - return t.size(); + mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { + const vector& t = getFeature(DoubleFeatureData, "T"); + setVec(DoubleFeatureData, StringData, "time", t); + return t.size(); } // *** The average voltage during the last 90% of the stimulus duration. *** int LibV5::steady_state_voltage_stimend(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_end", "stim_start"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"V", "T", "stim_end", "stim_start"}); const vector& voltages = doubleFeatures.at("V"); const vector& times = doubleFeatures.at("T"); @@ -1303,13 +1378,16 @@ int LibV5::steady_state_voltage_stimend(mapStr2intVec& IntFeatureData, const double stimEnd = doubleFeatures.at("stim_end")[0]; double start_time = stimEnd - 0.1 * (stimEnd - stimStart); - auto start_it = find_if(times.begin(), times.end(), [start_time](double x) { return x >= start_time; }); - auto stop_it = find_if(times.begin(), times.end(), [stimEnd](double x) { return x >= stimEnd; }); + auto start_it = find_if(times.begin(), times.end(), + [start_time](double x) { return x >= start_time; }); + auto stop_it = find_if(times.begin(), times.end(), + [stimEnd](double x) { return x >= stimEnd; }); size_t start_index = distance(times.begin(), start_it); size_t stop_index = distance(times.begin(), stop_it); - double mean = accumulate(voltages.begin() + start_index, voltages.begin() + stop_index, 0.0); + double mean = accumulate(voltages.begin() + start_index, + voltages.begin() + stop_index, 0.0); size_t mean_size = stop_index - start_index; vector ssv; @@ -1330,20 +1408,20 @@ int LibV5::voltage_base(mapStr2intVec& IntFeatureData, const vector& stimStart = getFeature(DoubleFeatureData, "stim_start"); // Retrieve percentage values or use defaults. - double vb_start_perc = 0.9; // Default value - double vb_end_perc = 1.0; // Default value + double vb_start_perc = 0.9; // Default value + double vb_end_perc = 1.0; // Default value try { - auto vb_start_perc_vec = getFeature(DoubleFeatureData, "voltage_base_start_perc"); - if (vb_start_perc_vec.size() == 1) - vb_start_perc = vb_start_perc_vec[0]; + auto vb_start_perc_vec = + getFeature(DoubleFeatureData, "voltage_base_start_perc"); + if (vb_start_perc_vec.size() == 1) vb_start_perc = vb_start_perc_vec[0]; } catch (const EmptyFeatureError&) { // If there's an error, use the default value. } try { - auto vb_end_perc_vec = getFeature(DoubleFeatureData, "voltage_base_end_perc"); - if (vb_end_perc_vec.size() == 1) - vb_end_perc = vb_end_perc_vec[0]; + auto vb_end_perc_vec = + getFeature(DoubleFeatureData, "voltage_base_end_perc"); + if (vb_end_perc_vec.size() == 1) vb_end_perc = vb_end_perc_vec[0]; } catch (const EmptyFeatureError&) { // If there's an error, use the default value. } @@ -1358,13 +1436,17 @@ int LibV5::voltage_base(mapStr2intVec& IntFeatureData, return -1; } - const auto& precisionThreshold = getFeature(DoubleFeatureData, "precision_threshold"); + const auto& precisionThreshold = + getFeature(DoubleFeatureData, "precision_threshold"); - // Find index range for the time vector within the specified start and end times. - std::pair time_index = get_time_index(t, startTime, endTime, precisionThreshold[0]); + // Find index range for the time vector within the specified start and end + // times. + std::pair time_index = + get_time_index(t, startTime, endTime, precisionThreshold[0]); // Extract sub-vector of voltages based on calculated indices. - vector subVector(v.begin() + time_index.first, v.begin() + time_index.second); + vector subVector(v.begin() + time_index.first, + v.begin() + time_index.second); // Determine computation mode and calculate voltage base. std::string computation_mode; @@ -1379,7 +1461,8 @@ int LibV5::voltage_base(mapStr2intVec& IntFeatureData, else if (computation_mode == "median") vBase = vec_median(subVector); else { - GErrorStr += "\nUndefined computational mode. Only mean and median are enabled\n"; + GErrorStr += + "\nUndefined computational mode. Only mean and median are enabled\n"; return -1; } @@ -1391,17 +1474,22 @@ int LibV5::voltage_base(mapStr2intVec& IntFeatureData, int LibV5::current_base(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"I", "T", "stim_start"}); - double cb_start_perc = 0.9; // Default value - double cb_end_perc = 1.0; // Default value + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"I", "T", "stim_start"}); + double cb_start_perc = 0.9; // Default value + double cb_end_perc = 1.0; // Default value try { - const double cb_start_perc = getFeature(DoubleFeatureData, "current_base_start_perc")[0]; - } catch (const std::runtime_error&) {} // Use default value if not found or an error occurs + const double cb_start_perc = + getFeature(DoubleFeatureData, "current_base_start_perc")[0]; + } catch (const std::runtime_error&) { + } // Use default value if not found or an error occurs try { - const double cb_end_perc = getFeature(DoubleFeatureData, "current_base_end_perc")[0]; - } catch (const std::runtime_error&) {} // Use default value if not found or an error occurs + const double cb_end_perc = + getFeature(DoubleFeatureData, "current_base_end_perc")[0]; + } catch (const std::runtime_error&) { + } // Use default value if not found or an error occurs double startTime = doubleFeatures.at("stim_start")[0] * cb_start_perc; double endTime = doubleFeatures.at("stim_start")[0] * cb_end_perc; @@ -1412,12 +1500,15 @@ int LibV5::current_base(mapStr2intVec& IntFeatureData, } vector precisionThreshold; - int retVal = getParam(DoubleFeatureData, "precision_threshold", precisionThreshold); + int retVal = + getParam(DoubleFeatureData, "precision_threshold", precisionThreshold); if (retVal < 0) return -1; - std::pair time_index = get_time_index(doubleFeatures.at("T"), startTime, endTime, precisionThreshold[0]); + std::pair time_index = get_time_index( + doubleFeatures.at("T"), startTime, endTime, precisionThreshold[0]); - vector subVector(doubleFeatures.at("I").begin()+time_index.first, doubleFeatures.at("I").begin()+time_index.second); + vector subVector(doubleFeatures.at("I").begin() + time_index.first, + doubleFeatures.at("I").begin() + time_index.second); double iBase; std::string computation_mode; @@ -1428,9 +1519,11 @@ int LibV5::current_base(mapStr2intVec& IntFeatureData, else if (computation_mode == "median") iBase = vec_median(subVector); else { - GErrorStr += "\ncurrent_base error: Undefined computational mode. Only mean and median are enabled\n"; - return -1; -} + GErrorStr += + "\ncurrent_base error: Undefined computational mode. Only mean and " + "median are enabled\n"; + return -1; + } vector iRest{iBase}; setVec(DoubleFeatureData, StringData, "current_base", iRest); @@ -1438,9 +1531,8 @@ int LibV5::current_base(mapStr2intVec& IntFeatureData, } size_t get_index(const vector& times, double t) { - return distance(times.begin(), - find_if(times.begin(), times.end(), - [t](double x){ return x >= t; })); + return distance(times.begin(), find_if(times.begin(), times.end(), + [t](double x) { return x >= t; })); } double __decay_time_constant_after_stim(const vector& times, @@ -1468,16 +1560,16 @@ double __decay_time_constant_after_stim(const vector& times, } if (decayTimes.size() < 1 || decayValues.size() < 1) { - GErrorStr += - "\ndecay_time_constant_after_stim: no data points to calculate this feature\n"; - return -1; - } - else { - linear_fit_result fit; - fit = slope_straight_line_fit(decayTimes, decayValues); + GErrorStr += + "\ndecay_time_constant_after_stim: no data points to calculate this " + "feature\n"; + return -1; + } else { + linear_fit_result fit; + fit = slope_straight_line_fit(decayTimes, decayValues); - const double tau = -1.0 / fit.slope; - return std::abs(tau); + const double tau = -1.0 / fit.slope; + return std::abs(tau); } } @@ -1485,74 +1577,82 @@ double __decay_time_constant_after_stim(const vector& times, int LibV5::decay_time_constant_after_stim(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"V", "T", "stim_start", "stim_end"}); double decay_start_after_stim, decay_end_after_stim; try { - const auto& decayStartFeatures = getFeatures(DoubleFeatureData, {"decay_start_after_stim"}); + const auto& decayStartFeatures = + getFeatures(DoubleFeatureData, {"decay_start_after_stim"}); decay_start_after_stim = decayStartFeatures.at("decay_start_after_stim")[0]; } catch (const std::runtime_error&) { decay_start_after_stim = 1.0; // Default value if not found } try { - const auto& decayEndFeatures = getFeatures(DoubleFeatureData, {"decay_end_after_stim"}); + const auto& decayEndFeatures = + getFeatures(DoubleFeatureData, {"decay_end_after_stim"}); decay_end_after_stim = decayEndFeatures.at("decay_end_after_stim")[0]; } catch (const std::runtime_error&) { decay_end_after_stim = 10.0; // Default value if not found } // Validate decay times if (decay_start_after_stim >= decay_end_after_stim) { - GErrorStr += "Error decay_start_after_stim small larger than decay_end_after_stim"; + GErrorStr += + "Error decay_start_after_stim small larger than decay_end_after_stim"; return -1; } // Perform calculation const double val = __decay_time_constant_after_stim( - doubleFeatures.at("T"), doubleFeatures.at("V"), decay_start_after_stim, - decay_end_after_stim, doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0]); + doubleFeatures.at("T"), doubleFeatures.at("V"), decay_start_after_stim, + decay_end_after_stim, doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0]); // Store the result vector dtcas{val}; - setVec(DoubleFeatureData, StringData, "decay_time_constant_after_stim", dtcas); + setVec(DoubleFeatureData, StringData, "decay_time_constant_after_stim", + dtcas); return 1; } // Calculate the time constants after each step for a stimuli containing several // steps, as for example SpikeRec protocols -int LibV5::multiple_decay_time_constant_after_stim(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "multi_stim_start", "multi_stim_end"}); +int LibV5::multiple_decay_time_constant_after_stim( + mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, {"V", "T", "multi_stim_start", "multi_stim_end"}); vector stimsEnd, stimsStart; stimsEnd = doubleFeatures.at("multi_stim_end"); stimsStart = doubleFeatures.at("multi_stim_start"); - // Attempt to get decay parameters, using defaults if not found or if not exactly one element + // Attempt to get decay parameters, using defaults if not found or if not + // exactly one element double decay_start_after_stim = 1.0; double decay_end_after_stim = 10.0; try { - const double decay_start_after_stim = getFeature(DoubleFeatureData, "decay_start_after_stim")[0]; - } catch (const std::runtime_error&) {} // Use default value + const double decay_start_after_stim = + getFeature(DoubleFeatureData, "decay_start_after_stim")[0]; + } catch (const std::runtime_error&) { + } // Use default value try { - const double decay_end_after_stim = getFeature(DoubleFeatureData, "decay_end_after_stim")[0]; - } catch (const std::runtime_error&) {} // Use default value + const double decay_end_after_stim = + getFeature(DoubleFeatureData, "decay_end_after_stim")[0]; + } catch (const std::runtime_error&) { + } // Use default value vector dtcas; for (size_t i = 0; i < stimsStart.size(); i++) { - double ret_dtcas = __decay_time_constant_after_stim( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - decay_start_after_stim, - decay_end_after_stim, - stimsStart[i], - stimsEnd[i] - ); - dtcas.push_back(ret_dtcas); - } - setVec(DoubleFeatureData, StringData, "multiple_decay_time_constant_after_stim", dtcas); + double ret_dtcas = __decay_time_constant_after_stim( + doubleFeatures.at("T"), doubleFeatures.at("V"), decay_start_after_stim, + decay_end_after_stim, stimsStart[i], stimsEnd[i]); + dtcas.push_back(ret_dtcas); + } + setVec(DoubleFeatureData, StringData, + "multiple_decay_time_constant_after_stim", dtcas); return 1; } @@ -1560,34 +1660,32 @@ int LibV5::multiple_decay_time_constant_after_stim(mapStr2intVec& IntFeatureData // noisy data is expected, so no golden section search is used // because with noisy data, x>0 often gives a worse logarithmic fit static int __sag_time_constant(const vector& times, - const vector& voltage, - const double minimum_voltage, - const double steady_state_v, - const double sag_amplitude, - const double stimStart, - const double stimEnd, - vector& sagtc) { + const vector& voltage, + const double minimum_voltage, + const double steady_state_v, + const double sag_amplitude, + const double stimStart, const double stimEnd, + vector& sagtc) { // minimal required length of each decay (indices) size_t min_length = 10; - // get start index - const size_t decayStartIdx = - distance(voltage.begin(), - find_if(voltage.begin(), voltage.end(), - [minimum_voltage](double v){ return v <= minimum_voltage; })); + // get start index + const size_t decayStartIdx = distance( + voltage.begin(), + find_if(voltage.begin(), voltage.end(), + [minimum_voltage](double v) { return v <= minimum_voltage; })); - - // voltage at which 90% of the sag amplitude has decayed - double steady_state_90 = steady_state_v - sag_amplitude * 0.1; - // get end index - const size_t decayEndIdx = - distance(voltage.begin(), - find_if(voltage.begin() + decayStartIdx, voltage.end(), - [steady_state_90](double v){ return v >= steady_state_90; })); + // voltage at which 90% of the sag amplitude has decayed + double steady_state_90 = steady_state_v - sag_amplitude * 0.1; + // get end index + const size_t decayEndIdx = distance( + voltage.begin(), + find_if(voltage.begin() + decayStartIdx, voltage.end(), + [steady_state_90](double v) { return v >= steady_state_90; })); // voltage reference by which the voltage (i the decay interval) // is going to be substracted - // there should be no '0' in (decay_v - v_reference), + // there should be no '0' in (decay_v - v_reference), // so no problem when the log is taken double v_reference = voltage[decayEndIdx]; @@ -1597,13 +1695,14 @@ static int __sag_time_constant(const vector& times, // compute time constant vector decayValues(decayEndIdx - decayStartIdx); - for (size_t i=0; i < VInterval.size(); ++i){ + for (size_t i = 0; i < VInterval.size(); ++i) { const double u0 = std::abs(VInterval[i] - v_reference); decayValues[i] = log(u0); } - if (decayValues.size() < min_length){ + if (decayValues.size() < min_length) { GErrorStr += - "\nsag time constant: Not enough data points to compute time constant.\n"; + "\nsag time constant: Not enough data points to compute time " + "constant.\n"; return -1; } linear_fit_result fit; @@ -1615,22 +1714,21 @@ static int __sag_time_constant(const vector& times, return 1; } -// *** Decay time constant measured from minimum voltage to steady-state voltage*** +// *** Decay time constant measured from minimum voltage to steady-state +// voltage*** int LibV5::sag_time_constant(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "stim_end", "stim_start", "minimum_voltage", "steady_state_voltage_stimend", "sag_amplitude"}); + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, {"V", "T", "stim_end", "stim_start", "minimum_voltage", + "steady_state_voltage_stimend", "sag_amplitude"}); vector sagtc; int retVal = __sag_time_constant( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - doubleFeatures.at("minimum_voltage")[0], - doubleFeatures.at("steady_state_voltage_stimend")[0], - doubleFeatures.at("sag_amplitude")[0], - doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0], - sagtc - ); + doubleFeatures.at("T"), doubleFeatures.at("V"), + doubleFeatures.at("minimum_voltage")[0], + doubleFeatures.at("steady_state_voltage_stimend")[0], + doubleFeatures.at("sag_amplitude")[0], doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0], sagtc); if (retVal > 0) { setVec(DoubleFeatureData, StringData, "sag_time_constant", sagtc); @@ -1642,12 +1740,15 @@ int LibV5::sag_time_constant(mapStr2intVec& IntFeatureData, int LibV5::voltage_deflection_vb_ssse(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_base", "steady_state_voltage_stimend"}); + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, {"voltage_base", "steady_state_voltage_stimend"}); vector voltage_deflection_vb_ssse; - voltage_deflection_vb_ssse.push_back(doubleFeatures.at("steady_state_voltage_stimend")[0] - - doubleFeatures.at("voltage_base")[0]); - setVec(DoubleFeatureData, StringData, "voltage_deflection_vb_ssse", voltage_deflection_vb_ssse); + voltage_deflection_vb_ssse.push_back( + doubleFeatures.at("steady_state_voltage_stimend")[0] - + doubleFeatures.at("voltage_base")[0]); + setVec(DoubleFeatureData, StringData, "voltage_deflection_vb_ssse", + voltage_deflection_vb_ssse); return 1; } @@ -1656,11 +1757,14 @@ int LibV5::voltage_deflection_vb_ssse(mapStr2intVec& IntFeatureData, int LibV5::ohmic_input_resistance_vb_ssse(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_deflection_vb_ssse", "stimulus_current"}); + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, {"voltage_deflection_vb_ssse", "stimulus_current"}); vector ohmic_input_resistance_vb_ssse; - ohmic_input_resistance_vb_ssse.push_back(doubleFeatures.at("voltage_deflection_vb_ssse")[0] / - doubleFeatures.at("stimulus_current")[0]); - setVec(DoubleFeatureData, StringData, "ohmic_input_resistance_vb_ssse", ohmic_input_resistance_vb_ssse); + ohmic_input_resistance_vb_ssse.push_back( + doubleFeatures.at("voltage_deflection_vb_ssse")[0] / + doubleFeatures.at("stimulus_current")[0]); + setVec(DoubleFeatureData, StringData, "ohmic_input_resistance_vb_ssse", + ohmic_input_resistance_vb_ssse); return 1; } @@ -1669,12 +1773,15 @@ int LibV5::ohmic_input_resistance_vb_ssse(mapStr2intVec& IntFeatureData, int LibV5::maximum_voltage_from_voltagebase(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"maximum_voltage", "voltage_base"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"maximum_voltage", "voltage_base"}); vector maximum_voltage_from_voltagebase; - maximum_voltage_from_voltagebase.push_back(doubleFeatures.at("maximum_voltage")[0] - - doubleFeatures.at("voltage_base")[0]); - setVec(DoubleFeatureData, StringData, "maximum_voltage_from_voltagebase", maximum_voltage_from_voltagebase); + maximum_voltage_from_voltagebase.push_back( + doubleFeatures.at("maximum_voltage")[0] - + doubleFeatures.at("voltage_base")[0]); + setVec(DoubleFeatureData, StringData, "maximum_voltage_from_voltagebase", + maximum_voltage_from_voltagebase); return 1; } @@ -1691,11 +1798,15 @@ struct InInterval { int LibV5::Spikecount_stimint(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"stim_start", "stim_end", "peak_time"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"stim_start", "stim_end", "peak_time"}); // Get the number of peaks between stim start and end - int spikecount_stimint_value = count_if(doubleFeatures.at("peak_time").begin(), doubleFeatures.at("peak_time").end(), - InInterval(doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0])); + int spikecount_stimint_value = + count_if(doubleFeatures.at("peak_time").begin(), + doubleFeatures.at("peak_time").end(), + InInterval(doubleFeatures.at("stim_start")[0], + doubleFeatures.at("stim_end")[0])); vector spikecount_stimint(1, spikecount_stimint_value); setVec(IntFeatureData, StringData, "Spikecount_stimint", spikecount_stimint); @@ -1725,8 +1836,7 @@ static int __peak_indices(double threshold, const vector& V, return 0; } if (upVec.size() == 0) { - GErrorStr += - "\nVoltage never goes above threshold in spike detection.\n"; + GErrorStr += "\nVoltage never goes above threshold in spike detection.\n"; return 0; } @@ -1734,7 +1844,7 @@ static int __peak_indices(double threshold, const vector& V, while (dnVec.size() > 0 && dnVec[0] < upVec[0]) { dnVec.erase(dnVec.begin()); } - + if (upVec.size() > dnVec.size()) { size_t size_diff = upVec.size() - dnVec.size(); for (size_t i = 0; i < size_diff; i++) { @@ -1774,25 +1884,21 @@ static int __peak_indices(double threshold, const vector& V, int LibV5::peak_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V", "T", "Threshold", "stim_start", "stim_end"}); + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, {"V", "T", "Threshold", "stim_start", "stim_end"}); bool strict_stiminterval; - try{ - const auto& intFeatures = getFeatures(IntFeatureData, {"strict_stiminterval"}); + try { + const auto& intFeatures = + getFeatures(IntFeatureData, {"strict_stiminterval"}); strict_stiminterval = bool(intFeatures.at("strict_stiminterval")[0]); - } - catch (const std::runtime_error& e) { + } catch (const std::runtime_error& e) { strict_stiminterval = false; } vector PeakIndex; int retVal = __peak_indices( - doubleFeatures.at("Threshold")[0], - doubleFeatures.at("V"), - doubleFeatures.at("T"), - PeakIndex, - strict_stiminterval, - doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0] - ); + doubleFeatures.at("Threshold")[0], doubleFeatures.at("V"), + doubleFeatures.at("T"), PeakIndex, strict_stiminterval, + doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0]); if (retVal >= 0) { setVec(IntFeatureData, StringData, "peak_indices", PeakIndex); @@ -1803,13 +1909,17 @@ int LibV5::peak_indices(mapStr2intVec& IntFeatureData, int LibV5::sag_amplitude(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"steady_state_voltage_stimend", "voltage_deflection_vb_ssse", "minimum_voltage"}); + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, {"steady_state_voltage_stimend", + "voltage_deflection_vb_ssse", "minimum_voltage"}); vector sag_amplitude; if (doubleFeatures.at("voltage_deflection_vb_ssse")[0] <= 0) { - sag_amplitude.push_back(doubleFeatures.at("steady_state_voltage_stimend")[0] - doubleFeatures.at("minimum_voltage")[0]); + sag_amplitude.push_back( + doubleFeatures.at("steady_state_voltage_stimend")[0] - + doubleFeatures.at("minimum_voltage")[0]); } else { - //In case of positive voltage deflection, return an error + // In case of positive voltage deflection, return an error GErrorStr += "\nsag_amplitude: voltage_deflection is positive\n"; return -1; } @@ -1824,16 +1934,19 @@ int LibV5::sag_ratio1(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { // Retrieve all required double features at once - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"sag_amplitude", "voltage_base", "minimum_voltage"}); + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, {"sag_amplitude", "voltage_base", "minimum_voltage"}); vector sag_ratio1; - if (doubleFeatures.at("minimum_voltage")[0] == doubleFeatures.at("voltage_base")[0]) { + if (doubleFeatures.at("minimum_voltage")[0] == + doubleFeatures.at("voltage_base")[0]) { GErrorStr += "\nsag_ratio1: voltage_base equals minimum_voltage\n"; - //In case of possible division by zero return error + // In case of possible division by zero return error return -1; } else { - sag_ratio1.push_back(doubleFeatures.at("sag_amplitude")[0] / - (doubleFeatures.at("voltage_base")[0] - doubleFeatures.at("minimum_voltage")[0])); + sag_ratio1.push_back(doubleFeatures.at("sag_amplitude")[0] / + (doubleFeatures.at("voltage_base")[0] - + doubleFeatures.at("minimum_voltage")[0])); } if (!sag_ratio1.empty()) { @@ -1846,16 +1959,22 @@ int LibV5::sag_ratio2(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { // Retrieve all required double features at once - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"voltage_base", "minimum_voltage", "steady_state_voltage_stimend"}); + const auto& doubleFeatures = getFeatures( + DoubleFeatureData, + {"voltage_base", "minimum_voltage", "steady_state_voltage_stimend"}); vector sag_ratio2; - if (doubleFeatures.at("minimum_voltage")[0] == doubleFeatures.at("voltage_base")[0]) { + if (doubleFeatures.at("minimum_voltage")[0] == + doubleFeatures.at("voltage_base")[0]) { GErrorStr += "\nsag_ratio2: voltage_base equals minimum_voltage\n"; - //In case of possible division by zero return error + // In case of possible division by zero return error return -1; } else { - sag_ratio2.push_back((doubleFeatures.at("voltage_base")[0] - doubleFeatures.at("steady_state_voltage_stimend")[0]) / - (doubleFeatures.at("voltage_base")[0] - doubleFeatures.at("minimum_voltage")[0])); + sag_ratio2.push_back( + (doubleFeatures.at("voltage_base")[0] - + doubleFeatures.at("steady_state_voltage_stimend")[0]) / + (doubleFeatures.at("voltage_base")[0] - + doubleFeatures.at("minimum_voltage")[0])); } if (!sag_ratio2.empty()) { @@ -1864,14 +1983,13 @@ int LibV5::sag_ratio2(mapStr2intVec& IntFeatureData, return sag_ratio2.empty() ? -1 : 1; } - // // *** Action potential peak upstroke *** // static int __AP_peak_upstroke(const vector& t, const vector& v, - const vector& pi, // peak indices - const vector& apbi, // AP begin indices - vector& pus) { // AP peak upstroke + const vector& pi, // peak indices + const vector& apbi, // AP begin indices + vector& pus) { // AP peak upstroke vector dvdt(v.size()); vector dv; vector dt; @@ -1882,20 +2000,21 @@ static int __AP_peak_upstroke(const vector& t, const vector& v, // Make sure that each value of pi is greater than its apbi counterpart vector new_pi; - size_t j=0; - for (size_t i=0; i < apbi.size(); i++){ - while (j < pi.size() && pi[j] < apbi[i]){ + size_t j = 0; + for (size_t i = 0; i < apbi.size(); i++) { + while (j < pi.size() && pi[j] < apbi[i]) { j++; } - if (j < pi.size() && pi[j] >= apbi[i]){ + if (j < pi.size() && pi[j] >= apbi[i]) { new_pi.push_back(pi[j]); j++; } } - for (size_t i=0; i < std::min(apbi.size(), new_pi.size()); i++){ - pus.push_back(*std::max_element(dvdt.begin()+apbi[i], dvdt.begin()+new_pi[i])); + for (size_t i = 0; i < std::min(apbi.size(), new_pi.size()); i++) { + pus.push_back( + *std::max_element(dvdt.begin() + apbi[i], dvdt.begin() + new_pi[i])); } return pus.size(); @@ -1906,16 +2025,13 @@ int LibV5::AP_peak_upstroke(mapStr2intVec& IntFeatureData, mapStr2Str& StringData) { // Retrieve all required double and int features at once const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices", "peak_indices"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"AP_begin_indices", "peak_indices"}); vector pus; int retVal = __AP_peak_upstroke( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - intFeatures.at("peak_indices"), - intFeatures.at("AP_begin_indices"), - pus - ); + doubleFeatures.at("T"), doubleFeatures.at("V"), + intFeatures.at("peak_indices"), intFeatures.at("AP_begin_indices"), pus); if (retVal >= 0) { setVec(DoubleFeatureData, StringData, "AP_peak_upstroke", pus); @@ -1923,14 +2039,14 @@ int LibV5::AP_peak_upstroke(mapStr2intVec& IntFeatureData, return retVal; } - // // *** Action potential peak downstroke *** // -static int __AP_peak_downstroke(const vector& t, const vector& v, - const vector& pi, // peak indices - const vector& ahpi, // min AHP indices - vector& pds) { // AP peak downstroke +static int __AP_peak_downstroke(const vector& t, + const vector& v, + const vector& pi, // peak indices + const vector& ahpi, // min AHP indices + vector& pds) { // AP peak downstroke vector dvdt(v.size()); vector dv; vector dt; @@ -1939,8 +2055,9 @@ static int __AP_peak_downstroke(const vector& t, const vector& v transform(dv.begin(), dv.end(), dt.begin(), dvdt.begin(), std::divides()); - for (size_t i=0; i < std::min(ahpi.size(), pi.size()); i++){ - pds.push_back(*std::min_element(dvdt.begin()+pi[i], dvdt.begin()+ahpi[i])); + for (size_t i = 0; i < std::min(ahpi.size(), pi.size()); i++) { + pds.push_back( + *std::min_element(dvdt.begin() + pi[i], dvdt.begin() + ahpi[i])); } return pds.size(); @@ -1950,16 +2067,13 @@ int LibV5::AP_peak_downstroke(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); vector pds; int retVal = __AP_peak_downstroke( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - intFeatures.at("peak_indices"), - intFeatures.at("min_AHP_indices"), - pds - ); + doubleFeatures.at("T"), doubleFeatures.at("V"), + intFeatures.at("peak_indices"), intFeatures.at("min_AHP_indices"), pds); if (retVal >= 0) { setVec(DoubleFeatureData, StringData, "AP_peak_downstroke", pds); @@ -1967,18 +2081,19 @@ int LibV5::AP_peak_downstroke(mapStr2intVec& IntFeatureData, return retVal; } -static int __min_between_peaks_indices(const vector& t, const vector& v, - const vector& peak_indices, - const double stim_start, const double stim_end, - const bool strict_stiminterval, - vector& min_btw_peaks_indices, - vector& min_btw_peaks_values) { +static int __min_between_peaks_indices( + const vector& t, const vector& v, + const vector& peak_indices, const double stim_start, + const double stim_end, const bool strict_stiminterval, + vector& min_btw_peaks_indices, vector& min_btw_peaks_values) { vector peak_indices_plus = peak_indices; unsigned end_index = 0; if (strict_stiminterval) { - end_index = distance(t.begin(), find_if(t.begin(), t.end(), - [stim_end](double t_val) { return t_val >= stim_end; })); + end_index = distance(t.begin(), + find_if(t.begin(), t.end(), [stim_end](double t_val) { + return t_val >= stim_end; + })); } else { end_index = distance(t.begin(), t.end()); } @@ -1988,9 +2103,9 @@ static int __min_between_peaks_indices(const vector& t, const vector min_btw_peaks_indices; vector min_btw_peaks_values; int retVal = __min_between_peaks_indices( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - intFeatures.at("peak_indices"), - doubleFeatures.at("stim_start").front(), - doubleFeatures.at("stim_end").front(), - intFeatures.at("strict_stiminterval").empty() ? false : intFeatures.at("strict_stiminterval").front(), - min_btw_peaks_indices, - min_btw_peaks_values - ); + doubleFeatures.at("T"), doubleFeatures.at("V"), + intFeatures.at("peak_indices"), doubleFeatures.at("stim_start").front(), + doubleFeatures.at("stim_end").front(), + intFeatures.at("strict_stiminterval").empty() + ? false + : intFeatures.at("strict_stiminterval").front(), + min_btw_peaks_indices, min_btw_peaks_values); if (retVal > 0) { - setVec(IntFeatureData, StringData, "min_between_peaks_indices", min_btw_peaks_indices); - setVec(DoubleFeatureData, StringData, "min_between_peaks_values", min_btw_peaks_values); + setVec(IntFeatureData, StringData, "min_between_peaks_indices", + min_btw_peaks_indices); + setVec(DoubleFeatureData, StringData, "min_between_peaks_values", + min_btw_peaks_values); } return retVal; } - int LibV5::min_between_peaks_values(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { return 1; } - // AP_width_between_threshold // spike width calculation according to threshold value. // min_between_peaks_indices are used to split the different APs // do not add width if threshold crossing has not been found -static int __AP_width_between_threshold(const vector& t, const vector& v, - double stimstart, double threshold, - const vector& min_between_peaks_indices, - vector& ap_width_threshold) { +static int __AP_width_between_threshold( + const vector& t, const vector& v, double stimstart, + double threshold, const vector& min_between_peaks_indices, + vector& ap_width_threshold) { vector indices(min_between_peaks_indices.size() + 1); int start_index = distance( - t.begin(), - find_if(t.begin(), t.end(), [stimstart](double x){return x >= stimstart;})); + t.begin(), find_if(t.begin(), t.end(), + [stimstart](double x) { return x >= stimstart; })); indices[0] = start_index; - copy(min_between_peaks_indices.begin(), min_between_peaks_indices.end(), indices.begin() + 1); + copy(min_between_peaks_indices.begin(), min_between_peaks_indices.end(), + indices.begin() + 1); for (size_t i = 0; i < indices.size() - 1; i++) { int onset_index = distance( v.begin(), find_if(v.begin() + indices[i], v.begin() + indices[i + 1], - [threshold](double x){return x >= threshold;})); + [threshold](double x) { return x >= threshold; })); int end_index = distance( v.begin(), find_if(v.begin() + onset_index, v.begin() + indices[i + 1], - [threshold](double x){return x <= threshold;})); - if (end_index != indices[i + 1]){ + [threshold](double x) { return x <= threshold; })); + if (end_index != indices[i + 1]) { ap_width_threshold.push_back(t[end_index] - t[onset_index]); } } @@ -2076,22 +2192,22 @@ int LibV5::AP_width_between_threshold(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { // Retrieve all required double and int features at once - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "Threshold", "stim_start"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"min_between_peaks_indices"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"T", "V", "Threshold", "stim_start"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"min_between_peaks_indices"}); vector ap_width_threshold; int retval = __AP_width_between_threshold( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - doubleFeatures.at("stim_start").front(), - doubleFeatures.at("Threshold").front(), - intFeatures.at("min_between_peaks_indices"), - ap_width_threshold - ); + doubleFeatures.at("T"), doubleFeatures.at("V"), + doubleFeatures.at("stim_start").front(), + doubleFeatures.at("Threshold").front(), + intFeatures.at("min_between_peaks_indices"), ap_width_threshold); if (retval == 0) throw EmptyFeatureError("AP_width_between_threshold is empty"); else if (retval > 0) { - setVec(DoubleFeatureData, StringData, "AP_width_between_threshold", ap_width_threshold); + setVec(DoubleFeatureData, StringData, "AP_width_between_threshold", + ap_width_threshold); } return retval; } @@ -2099,9 +2215,9 @@ int LibV5::AP_width_between_threshold(mapStr2intVec& IntFeatureData, // the recorded indices correspond to the peak indices // does not skip the first ISI by default static int __burst_indices(double burst_factor, int IgnoreFirstISI, - const vector ISI_values, - vector& burst_begin_indices, - vector& burst_end_indices) { + const vector ISI_values, + vector& burst_begin_indices, + vector& burst_end_indices) { vector ISIpcopy; vector::iterator it1, it2; int n; @@ -2124,16 +2240,17 @@ static int __burst_indices(double burst_factor, int IgnoreFirstISI, dMedian = ISIpcopy[int(n / 2)]; } - in_burst = (burst_end_indices.size() == 0 || burst_begin_indices.back() > burst_end_indices.back()); + in_burst = (burst_end_indices.size() == 0 || + burst_begin_indices.back() > burst_end_indices.back()); // look for end burst - if (in_burst && ISI_values[i] > (burst_factor * dMedian)){ + if (in_burst && ISI_values[i] > (burst_factor * dMedian)) { burst_end_indices.push_back(i); count = i; } - if (ISI_values[i] < ISI_values[i - 1] / burst_factor){ - if (in_burst){ + if (ISI_values[i] < ISI_values[i - 1] / burst_factor) { + if (in_burst) { burst_begin_indices.back() = i; } else { burst_begin_indices.push_back(i); @@ -2142,8 +2259,9 @@ static int __burst_indices(double burst_factor, int IgnoreFirstISI, } } - in_burst = (burst_end_indices.size() == 0 || burst_begin_indices.back() > burst_end_indices.back()); - if (in_burst){ + in_burst = (burst_end_indices.size() == 0 || + burst_begin_indices.back() > burst_end_indices.back()); + if (in_burst) { burst_end_indices.push_back(ISI_values.size()); } @@ -2160,7 +2278,8 @@ int LibV5::burst_begin_indices(mapStr2intVec& IntFeatureData, double burst_factor = 0; ISI_values = getFeature(DoubleFeatureData, "all_ISI_values"); if (ISI_values.size() < 2) { - GErrorStr += "\nError: At least than 3 spikes are needed for burst calculation.\n"; + GErrorStr += + "\nError: At least than 3 spikes are needed for burst calculation.\n"; return -1; } retVal = getParam(DoubleFeatureData, "strict_burst_factor", tVec); @@ -2175,27 +2294,26 @@ int LibV5::burst_begin_indices(mapStr2intVec& IntFeatureData, else IgnoreFirstISI = 1; - retVal = __burst_indices( - burst_factor, IgnoreFirstISI, ISI_values, burst_begin_indices, burst_end_indices - ); + retVal = __burst_indices(burst_factor, IgnoreFirstISI, ISI_values, + burst_begin_indices, burst_end_indices); if (retVal >= 0) { - setVec(IntFeatureData, StringData, "burst_begin_indices", burst_begin_indices); + setVec(IntFeatureData, StringData, "burst_begin_indices", + burst_begin_indices); setVec(IntFeatureData, StringData, "burst_end_indices", burst_end_indices); } return retVal; } int LibV5::burst_end_indices(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { return 1; } - static int __strict_burst_mean_freq(const vector& PVTime, - const vector& burst_begin_indices, - const vector& burst_end_indices, - vector& BurstMeanFreq) { + const vector& burst_begin_indices, + const vector& burst_end_indices, + vector& BurstMeanFreq) { if (burst_begin_indices.size() == 0) return BurstMeanFreq.size(); double span; size_t i; @@ -2203,7 +2321,8 @@ static int __strict_burst_mean_freq(const vector& PVTime, for (i = 0; i < burst_begin_indices.size(); i++) { if (burst_end_indices[i] - burst_begin_indices[i] > 0) { span = PVTime[burst_end_indices[i]] - PVTime[burst_begin_indices[i]]; - BurstMeanFreq.push_back((burst_end_indices[i] - burst_begin_indices[i] + 1) * 1000 / span); + BurstMeanFreq.push_back( + (burst_end_indices[i] - burst_begin_indices[i] + 1) * 1000 / span); } } @@ -2215,37 +2334,37 @@ int LibV5::strict_burst_mean_freq(mapStr2intVec& IntFeatureData, mapStr2Str& StringData) { // Retrieve all required double and int features at once const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"burst_begin_indices", "burst_end_indices"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"burst_begin_indices", "burst_end_indices"}); vector BurstMeanFreq; int retVal = __strict_burst_mean_freq( - doubleFeatures.at("peak_time"), - intFeatures.at("burst_begin_indices"), - intFeatures.at("burst_end_indices"), - BurstMeanFreq - ); + doubleFeatures.at("peak_time"), intFeatures.at("burst_begin_indices"), + intFeatures.at("burst_end_indices"), BurstMeanFreq); if (retVal >= 0) { - setVec(DoubleFeatureData, StringData, "strict_burst_mean_freq", BurstMeanFreq); + setVec(DoubleFeatureData, StringData, "strict_burst_mean_freq", + BurstMeanFreq); } return retVal; } int LibV5::strict_burst_number(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"strict_burst_mean_freq"}); + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"strict_burst_mean_freq"}); vector BurstNum; BurstNum.push_back(doubleFeatures.at("strict_burst_mean_freq").size()); setVec(IntFeatureData, StringData, "strict_burst_number", BurstNum); return BurstNum.size(); } - static int __strict_interburst_voltage(const vector& burst_begin_indices, - const vector& PeakIndex, - const vector& T, const vector& V, - vector& IBV) { + const vector& PeakIndex, + const vector& T, + const vector& V, + vector& IBV) { if (burst_begin_indices.size() < 1) return 0; int j, pIndex, tsIndex, teIndex, cnt; double tStart, tEnd, vTotal = 0; @@ -2275,18 +2394,15 @@ static int __strict_interburst_voltage(const vector& burst_begin_indices, } int LibV5::strict_interburst_voltage(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "burst_begin_indices"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"peak_indices", "burst_begin_indices"}); vector IBV; int retVal = __strict_interburst_voltage( - intFeatures.at("burst_begin_indices"), - intFeatures.at("peak_indices"), - doubleFeatures.at("T"), - doubleFeatures.at("V"), - IBV - ); + intFeatures.at("burst_begin_indices"), intFeatures.at("peak_indices"), + doubleFeatures.at("T"), doubleFeatures.at("V"), IBV); if (retVal > 0) { setVec(DoubleFeatureData, StringData, "strict_interburst_voltage", IBV); @@ -2294,25 +2410,25 @@ int LibV5::strict_interburst_voltage(mapStr2intVec& IntFeatureData, return retVal; } - // strict_stiminterval should be True when using this feature static int __ADP_peak_indices(const vector& v, - const vector& min_AHP_indices, - const vector& min_between_peaks_indices, - vector& ADP_peak_indices, - vector& ADP_peak_values) { - if (min_AHP_indices.size() > min_between_peaks_indices.size()){ + const vector& min_AHP_indices, + const vector& min_between_peaks_indices, + vector& ADP_peak_indices, + vector& ADP_peak_values) { + if (min_AHP_indices.size() > min_between_peaks_indices.size()) { GErrorStr += - "\nmin_AHP_indices should not have less elements than min_between_peaks_indices\n"; + "\nmin_AHP_indices should not have less elements than " + "min_between_peaks_indices\n"; return -1; } unsigned adp_peak_index; for (size_t i = 0; i < min_AHP_indices.size(); i++) { - adp_peak_index = max_element( - v.begin() + min_AHP_indices[i], v.begin() + min_between_peaks_indices[i] - ) - v.begin(); - + adp_peak_index = max_element(v.begin() + min_AHP_indices[i], + v.begin() + min_between_peaks_indices[i]) - + v.begin(); + ADP_peak_indices.push_back(adp_peak_index); ADP_peak_values.push_back(v[adp_peak_index]); } @@ -2322,17 +2438,17 @@ static int __ADP_peak_indices(const vector& v, // strict_stiminterval should be True when using this feature int LibV5::ADP_peak_indices(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "min_between_peaks_indices"}); + const auto& intFeatures = getFeatures( + IntFeatureData, {"min_AHP_indices", "min_between_peaks_indices"}); vector ADP_peak_indices; vector ADP_peak_values; - int retVal = __ADP_peak_indices(doubleFeatures.at("V"), - intFeatures.at("min_AHP_indices"), + int retVal = __ADP_peak_indices(doubleFeatures.at("V"), + intFeatures.at("min_AHP_indices"), intFeatures.at("min_between_peaks_indices"), - ADP_peak_indices, - ADP_peak_values); + ADP_peak_indices, ADP_peak_values); if (retVal > 0) { setVec(IntFeatureData, StringData, "ADP_peak_indices", ADP_peak_indices); setVec(DoubleFeatureData, StringData, "ADP_peak_values", ADP_peak_values); @@ -2342,48 +2458,49 @@ int LibV5::ADP_peak_indices(mapStr2intVec& IntFeatureData, // strict_stiminterval should be True when using this feature int LibV5::ADP_peak_values(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { -return 1; + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + return 1; } - // strict_stiminterval should be True when using this feature int LibV5::ADP_peak_amplitude(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"min_AHP_values", "ADP_peak_values"}); + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"min_AHP_values", "ADP_peak_values"}); vector ADP_peak_amplitude; const vector& min_AHP_values = doubleFeatures.at("min_AHP_values"); const vector& ADP_peak_values = doubleFeatures.at("ADP_peak_values"); - if (min_AHP_values.size() != ADP_peak_values.size()){ + if (min_AHP_values.size() != ADP_peak_values.size()) { GErrorStr += - "\nmin_AHP_values and ADP_peak_values should have the same number of elements\n"; + "\nmin_AHP_values and ADP_peak_values should have the same number of " + "elements\n"; return -1; } for (size_t i = 0; i < ADP_peak_values.size(); i++) { ADP_peak_amplitude.push_back(ADP_peak_values[i] - min_AHP_values[i]); } - setVec(DoubleFeatureData, StringData, "ADP_peak_amplitude", ADP_peak_amplitude); + setVec(DoubleFeatureData, StringData, "ADP_peak_amplitude", + ADP_peak_amplitude); return ADP_peak_amplitude.size(); } - static int __interburst_min_indices(const vector& v, - const vector& peak_indices, - const vector& burst_end_indices, - vector& interburst_min_indices, - vector& interburst_min_values) { + const vector& peak_indices, + const vector& burst_end_indices, + vector& interburst_min_indices, + vector& interburst_min_values) { unsigned interburst_min_index; - for (size_t i = 0; - i < burst_end_indices.size() && burst_end_indices[i] + 1 < peak_indices.size(); + for (size_t i = 0; i < burst_end_indices.size() && + burst_end_indices[i] + 1 < peak_indices.size(); i++) { - interburst_min_index = min_element( - v.begin() + peak_indices[burst_end_indices[i]], - v.begin() + peak_indices[burst_end_indices[i] + 1] - ) - v.begin(); - + interburst_min_index = + min_element(v.begin() + peak_indices[burst_end_indices[i]], + v.begin() + peak_indices[burst_end_indices[i] + 1]) - + v.begin(); + interburst_min_indices.push_back(interburst_min_index); interburst_min_values.push_back(v[interburst_min_index]); } @@ -2394,22 +2511,21 @@ int LibV5::interburst_min_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"V"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "burst_end_indices"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"peak_indices", "burst_end_indices"}); vector interburst_min_indices; vector interburst_min_values; const vector& v = doubleFeatures.at("V"); const vector& peak_indices = intFeatures.at("peak_indices"); const vector& burst_end_indices = intFeatures.at("burst_end_indices"); - int retVal = __interburst_min_indices( - v, - peak_indices, - burst_end_indices, - interburst_min_indices, - interburst_min_values - ); + int retVal = + __interburst_min_indices(v, peak_indices, burst_end_indices, + interburst_min_indices, interburst_min_values); if (retVal > 0) { - setVec(IntFeatureData, StringData, "interburst_min_indices", interburst_min_indices); - setVec(DoubleFeatureData, StringData, "interburst_min_values", interburst_min_values); + setVec(IntFeatureData, StringData, "interburst_min_indices", + interburst_min_indices); + setVec(DoubleFeatureData, StringData, "interburst_min_values", + interburst_min_values); } return retVal; } @@ -2420,7 +2536,6 @@ int LibV5::interburst_min_values(mapStr2intVec& IntFeatureData, return 1; } - static int __postburst_min_indices(const vector& t, const vector& v, const vector& peak_indices, @@ -2429,26 +2544,28 @@ static int __postburst_min_indices(const vector& t, vector& postburst_min_values, const double stim_end) { unsigned postburst_min_index, stim_end_index, end_index; - stim_end_index = distance(t.begin(), find_if(t.begin(), t.end(), [stim_end](double x) { return x >= stim_end; })); + stim_end_index = distance( + t.begin(), find_if(t.begin(), t.end(), + [stim_end](double x) { return x >= stim_end; })); end_index = distance(t.begin(), t.end()); for (size_t i = 0; i < burst_end_indices.size(); i++) { - if (burst_end_indices[i] + 1 < peak_indices.size()){ - postburst_min_index = min_element( - v.begin() + peak_indices[burst_end_indices[i]], - v.begin() + peak_indices[burst_end_indices[i] + 1] - ) - v.begin(); - } else if (peak_indices[burst_end_indices[i]] < stim_end_index){ - postburst_min_index = min_element( - v.begin() + peak_indices[burst_end_indices[i]], - v.begin() + stim_end_index - ) - v.begin(); + if (burst_end_indices[i] + 1 < peak_indices.size()) { + postburst_min_index = + min_element(v.begin() + peak_indices[burst_end_indices[i]], + v.begin() + peak_indices[burst_end_indices[i] + 1]) - + v.begin(); + } else if (peak_indices[burst_end_indices[i]] < stim_end_index) { + postburst_min_index = + min_element(v.begin() + peak_indices[burst_end_indices[i]], + v.begin() + stim_end_index) - + v.begin(); } else { - postburst_min_index = min_element( - v.begin() + peak_indices[burst_end_indices[i]], - v.begin() + end_index - ) - v.begin(); + postburst_min_index = + min_element(v.begin() + peak_indices[burst_end_indices[i]], + v.begin() + end_index) - + v.begin(); } - + postburst_min_indices.push_back(postburst_min_index); postburst_min_values.push_back(v[postburst_min_index]); } @@ -2457,60 +2574,63 @@ static int __postburst_min_indices(const vector& t, } int LibV5::postburst_min_indices(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "stim_end"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices", "burst_end_indices"}); + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"T", "V", "stim_end"}); + const auto& intFeatures = + getFeatures(IntFeatureData, {"peak_indices", "burst_end_indices"}); vector postburst_min_indices; vector postburst_min_values; double stim_end = doubleFeatures.at("stim_end").front(); int retVal = __postburst_min_indices( - doubleFeatures.at("T"), - doubleFeatures.at("V"), - intFeatures.at("peak_indices"), - intFeatures.at("burst_end_indices"), - postburst_min_indices, - postburst_min_values, - stim_end - ); + doubleFeatures.at("T"), doubleFeatures.at("V"), + intFeatures.at("peak_indices"), intFeatures.at("burst_end_indices"), + postburst_min_indices, postburst_min_values, stim_end); if (retVal > 0) { - setVec(IntFeatureData, StringData, "postburst_min_indices", postburst_min_indices); - setVec(DoubleFeatureData, StringData, "postburst_min_values", postburst_min_values); + setVec(IntFeatureData, StringData, "postburst_min_indices", + postburst_min_indices); + setVec(DoubleFeatureData, StringData, "postburst_min_values", + postburst_min_values); } return retVal; } int LibV5::postburst_min_values(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { + mapStr2doubleVec& DoubleFeatureData, + mapStr2Str& StringData) { return 1; } - int LibV5::time_to_interburst_min(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { // Retrieve all required double and int features at once - const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "peak_time"}); - const auto& intFeatures = getFeatures(IntFeatureData, {"burst_end_indices", "interburst_min_indices"}); + const auto& doubleFeatures = + getFeatures(DoubleFeatureData, {"T", "peak_time"}); + const auto& intFeatures = getFeatures( + IntFeatureData, {"burst_end_indices", "interburst_min_indices"}); vector time_to_interburst_min; const vector& time = doubleFeatures.at("T"); const vector& peak_time = doubleFeatures.at("peak_time"); const vector& burst_end_indices = intFeatures.at("burst_end_indices"); - const vector& interburst_min_indices = intFeatures.at("interburst_min_indices"); + const vector& interburst_min_indices = + intFeatures.at("interburst_min_indices"); - if (burst_end_indices.size() < interburst_min_indices.size()){ + if (burst_end_indices.size() < interburst_min_indices.size()) { GErrorStr += - "\nburst_end_indices should not have less elements than interburst_min_indices\n"; + "\nburst_end_indices should not have less elements than " + "interburst_min_indices\n"; return -1; -} + } for (size_t i = 0; i < interburst_min_indices.size(); i++) { time_to_interburst_min.push_back(time[interburst_min_indices[i]] - - peak_time[burst_end_indices[i]]); + peak_time[burst_end_indices[i]]); } - setVec(DoubleFeatureData, StringData, "time_to_interburst_min", time_to_interburst_min); + setVec(DoubleFeatureData, StringData, "time_to_interburst_min", + time_to_interburst_min); return time_to_interburst_min.size(); } diff --git a/efel/cppcore/Utils.cpp b/efel/cppcore/Utils.cpp index 52738d58..63842e81 100644 --- a/efel/cppcore/Utils.cpp +++ b/efel/cppcore/Utils.cpp @@ -17,39 +17,38 @@ */ #include "Utils.h" + +#include +#include + #include #include #include -#include #include -#include -#include -int LinearInterpolation(double Stepdx, - const vector& X, - const vector& Y, - vector& InterpX, +int LinearInterpolation(double Stepdx, const vector& X, + const vector& Y, vector& InterpX, vector& InterpY) { EFEL_ASSERT(X.size() == Y.size(), "X & Y have to have the same point count"); EFEL_ASSERT(2 < X.size(), "Need at least 2 points in X"); EFEL_ASSERT(Stepdx > 0, "Interpolation step needs to be strictly positive"); - + double dx, dy, dydx; size_t InterpX_size; double x = X[0]; double start = X[0]; double stop = X[X.size() - 1]; - + // Inspired by the way numpy.arange works // Do not remove the 'ceil' in favor of < stop in for loop - InterpX_size = ceil((stop - start)/Stepdx); + InterpX_size = ceil((stop - start) / Stepdx); for (size_t i = 0; i < InterpX_size; i++) { - InterpX.push_back(x); - x += Stepdx; + InterpX.push_back(x); + x += Stepdx; } - if (InterpX[InterpX.size() - 1] < X[X.size() - 1]){ + if (InterpX[InterpX.size() - 1] < X[X.size() - 1]) { InterpX.push_back(x); InterpX_size += 1; } @@ -59,37 +58,35 @@ int LinearInterpolation(double Stepdx, for (size_t i = 0; i < InterpX.size(); i++) { x = InterpX[i]; - EFEL_ASSERT((j+1) < X.size(), "Interpolation accessing point outside of X"); - - while ( X[j+1] < x ) { - j++; - if (j+1 >= X.size()) { - j = X.size() - 1; - break; - } - EFEL_ASSERT((j+1) < X.size(), + EFEL_ASSERT((j + 1) < X.size(), "Interpolation accessing point outside of X"); - } - + while (X[j + 1] < x) { + j++; + if (j + 1 >= X.size()) { + j = X.size() - 1; + break; + } + EFEL_ASSERT((j + 1) < X.size(), + "Interpolation accessing point outside of X"); + } if (j == X.size() - 1) { - // Last point - InterpY.push_back(Y[j]); - break; - } - else { - EFEL_ASSERT((j+1) < X.size(), - "Interpolation accessing point outside of X"); - - dx = X[j+1] - X[j]; - dy = Y[j+1] - Y[j]; + // Last point + InterpY.push_back(Y[j]); + break; + } else { + EFEL_ASSERT((j + 1) < X.size(), + "Interpolation accessing point outside of X"); + + dx = X[j + 1] - X[j]; + dy = Y[j + 1] - Y[j]; - EFEL_ASSERT(dx != 0, "Interpolation using dx == 0"); //!=0 per definition + EFEL_ASSERT(dx != 0, "Interpolation using dx == 0"); //!=0 per definition - dydx = dy/dx; + dydx = dy / dx; - InterpY.push_back(Y[j] + dydx * (x - X[j])); + InterpY.push_back(Y[j] + dydx * (x - X[j])); } } @@ -125,10 +122,8 @@ void getfivepointstencilderivative(const vector& v, } // fit a straight line to the points (x[i], y[i]) and return the slope y'(x) -linear_fit_result -slope_straight_line_fit(const vector& x, - const vector& y - ) { +linear_fit_result slope_straight_line_fit(const vector& x, + const vector& y) { EFEL_ASSERT(x.size() == y.size(), "X & Y have to have the same point count"); EFEL_ASSERT(1 <= x.size(), "Need at least 1 points in X"); @@ -160,7 +155,8 @@ slope_straight_line_fit(const vector& x, // calculate the normalized standard deviation // the normalisation helps comparing between dataset with different ranges - double range = *max_element(y.begin(), y.end()) - *min_element(y.begin(), y.end()); + double range = + *max_element(y.begin(), y.end()) - *min_element(y.begin(), y.end()); result.normalized_std = residuals / (range * range); // calculate the coefficient of determination R^2 @@ -175,68 +171,65 @@ slope_straight_line_fit(const vector& x, return result; } -std::pair get_time_index(const std::vector &t, double startTime, - double endTime, double precisionThreshold) { +std::pair get_time_index(const std::vector& t, + double startTime, double endTime, + double precisionThreshold) { /* - * Returns the start and end index of the time array + * Returns the start and end index of the time array * Uses a threshold to tolerate the precision loss - * */ + * */ size_t startIndex = 0; size_t endIndex = t.size(); - for (size_t i = 0; i < t.size(); i++){ - if (t[i] >= startTime) - { + for (size_t i = 0; i < t.size(); i++) { + if (t[i] >= startTime) { startIndex = i; break; } } - for (size_t i = t.size() - 1; i > 0; i--){ // backward iterator using indices - if (t[i] - endTime < precisionThreshold) - { - endIndex = i+1; + for (size_t i = t.size() - 1; i > 0; + i--) { // backward iterator using indices + if (t[i] - endTime < precisionThreshold) { + endIndex = i + 1; break; } } return std::pair(startIndex, endIndex); - } -template -double vec_mean(const vector &v) { +template +double vec_mean(const vector& v) { /* * Computes the mean of input vector v * Does not modify the reference v * Returns the mean value * */ - double sum = accumulate( v.begin(), v.end(), 0.0); - size_t v_size = v.size(); - double mean = sum / v_size; - return mean; + double sum = accumulate(v.begin(), v.end(), 0.0); + size_t v_size = v.size(); + double mean = sum / v_size; + return mean; } -template +template double vec_median(vector v) { - /* - * param v: the input vector - * param v is called by value since std::sort modifies the container - * Returns the median value of the vector - * */ - - // sort using the default operator< - std::sort(v.begin(), v.end()); + /* + * param v: the input vector + * param v is called by value since std::sort modifies the container + * Returns the median value of the vector + * */ - size_t n = v.size(); - if (n % 2 != 0) // odd - return (double)v[n/2]; - return (double)(v[(n-1)/2] + v[n/2])/2.0; // even + // sort using the default operator< + std::sort(v.begin(), v.end()); + size_t n = v.size(); + if (n % 2 != 0) // odd + return (double)v[n / 2]; + return (double)(v[(n - 1) / 2] + v[n / 2]) / 2.0; // even } - -template double vec_mean(const vector &v); +template double vec_mean(const vector& v); template double vec_median(vector v); diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 82d1d378..71edf28b 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -17,20 +17,18 @@ */ #include "cfeature.h" -#include "Global.h" + +#include #include #include -#include +#include "Global.h" using std::endl; - - cFeature::cFeature(const string& strDepFile, const string& outdir) - : logger(outdir) -{ + : logger(outdir) { FillFptrTable(); mapFptrLib["LibV1"] = &FptrTableV1; mapFptrLib["LibV2"] = &FptrTableV2; @@ -57,20 +55,21 @@ cFeature::cFeature(const string& strDepFile, const string& outdir) } template -const vector cFeature::getMapData(const string& strName, const map>& mapData) { - auto mapItr = mapData.find(strName); - if (mapItr == mapData.end()) { - return vector{}; // Return an empty vector without modifying the map - } - return mapItr->second; +const vector cFeature::getMapData(const string& strName, + const map>& mapData) { + auto mapItr = mapData.find(strName); + if (mapItr == mapData.end()) { + return vector{}; // Return an empty vector without modifying the map + } + return mapItr->second; } const vector cFeature::getmapIntData(string strName) { - return getMapData(strName, mapIntData); + return getMapData(strName, mapIntData); } const vector cFeature::getmapDoubleData(string strName) { - return getMapData(strName, mapDoubleData); + return getMapData(strName, mapDoubleData); } void cFeature::fillfeaturetypes() { @@ -248,70 +247,68 @@ int cFeature::setFeatureInt(string strName, vector& v) { } int cFeature::calc_features(const std::string& name) { - // stimulus extension - auto lookup_it = fptrlookup.find(name); - if (lookup_it == fptrlookup.end()) { - throw std::runtime_error("Feature dependency file entry or pointer table entry for '" + name + "' is missing."); - } + // stimulus extension + auto lookup_it = fptrlookup.find(name); + if (lookup_it == fptrlookup.end()) { + throw std::runtime_error( + "Feature dependency file entry or pointer table entry for '" + name + + "' is missing."); + } - bool last_failed = false; + bool last_failed = false; - for (const auto& pfptrstring : lookup_it->second) { - feature_function function = pfptrstring; - setFeatureString("params", ""); + for (const auto& pfptrstring : lookup_it->second) { + feature_function function = pfptrstring; + setFeatureString("params", ""); - if (function(mapIntData, mapDoubleData, mapStrData) < 0) { - last_failed = true; - } else { - last_failed = false; - } + if (function(mapIntData, mapDoubleData, mapStrData) < 0) { + last_failed = true; + } else { + last_failed = false; } + } - return last_failed ? -1 : 0; // -1 if the last attempt failed, 0 otherwise + return last_failed ? -1 : 0; // -1 if the last attempt failed, 0 otherwise } template int cFeature::getFeature(string strName, vector& vec) { - const map>* dataMap; - if constexpr (std::is_same_v) - dataMap = &mapIntData; - else // cppcore sends only int or double, no other types - dataMap = &mapDoubleData; - - // 1) Check if the feature is in the map. - vec = getMapData(strName, *dataMap); - if (!vec.empty()) { - logger << "Reusing computed value of " << strName << "." << endl; - return vec.size(); - } else { - // 2) If it's not in the map, compute. - logger << "Going to calculate feature " << strName << " ..." << endl; - int retVal = 0; - try{ - retVal = calc_features(strName); - } - catch (const FeatureComputationError& e) { - GErrorStr += e.what(); - return -1; - } - catch (const EmptyFeatureError& e) - { - GErrorStr += e.what(); - return -1; - } - if (retVal < 0) { - logger << "Failed to calculate feature " << strName << ": " << GErrorStr << endl; - return -1; - } - vec = getMapData(strName, *dataMap); - if (vec.empty()) - GErrorStr += "Feature [" + strName + "] data is missing\n"; - - logger << "Calculated feature " << strName << ":" << vec << endl; - return vec.size(); + const map>* dataMap; + if constexpr (std::is_same_v) + dataMap = &mapIntData; + else // cppcore sends only int or double, no other types + dataMap = &mapDoubleData; + + // 1) Check if the feature is in the map. + vec = getMapData(strName, *dataMap); + if (!vec.empty()) { + logger << "Reusing computed value of " << strName << "." << endl; + return vec.size(); + } else { + // 2) If it's not in the map, compute. + logger << "Going to calculate feature " << strName << " ..." << endl; + int retVal = 0; + try { + retVal = calc_features(strName); + } catch (const FeatureComputationError& e) { + GErrorStr += e.what(); + return -1; + } catch (const EmptyFeatureError& e) { + GErrorStr += e.what(); + return -1; } -} + if (retVal < 0) { + logger << "Failed to calculate feature " << strName << ": " << GErrorStr + << endl; + return -1; + } + vec = getMapData(strName, *dataMap); + if (vec.empty()) GErrorStr += "Feature [" + strName + "] data is missing\n"; + logger << "Calculated feature " << strName << ":" << vec << endl; + return vec.size(); + } +} int cFeature::setFeatureString(const string& key, const string& value) { logger << "Set " << key << ": " << value << endl; @@ -347,9 +344,8 @@ int cFeature::setFeatureDouble(string strName, vector& v) { return 1; } -double cFeature::getDistance(string strName, double mean, double std, - bool trace_check, double error_dist) { - +double cFeature::getDistance(string strName, double mean, double std, + bool trace_check, double error_dist) { vector feature_vec; vector feature_veci; string featureType; @@ -359,10 +355,10 @@ double cFeature::getDistance(string strName, double mean, double std, // Check if a the trace doesn't contain any spikes outside of the stimulus // interval if (trace_check) { - retVal = getFeature("trace_check", feature_veci); - if (retVal < 0) { - return error_dist; - } + retVal = getFeature("trace_check", feature_veci); + if (retVal < 0) { + return error_dist; + } } featureType = featuretype(strName); @@ -370,7 +366,7 @@ double cFeature::getDistance(string strName, double mean, double std, if (featureType == "int") { retVal = getFeature(strName, feature_veci); intFlag = 1; - } else { // double + } else { // double retVal = getFeature(strName, feature_vec); intFlag = 0; } diff --git a/efel/cppcore/cppcore.cpp b/efel/cppcore/cppcore.cpp index aa52a00e..223dfc37 100644 --- a/efel/cppcore/cppcore.cpp +++ b/efel/cppcore/cppcore.cpp @@ -35,14 +35,13 @@ */ #include - -#include #include -cFeature *pFeature = NULL; +#include +cFeature* pFeature = NULL; -int Initialize(const char *strDepFile, const char *outdir) { +int Initialize(const char* strDepFile, const char* outdir) { if (pFeature != NULL) { delete pFeature; } @@ -56,8 +55,7 @@ int Initialize(const char *strDepFile, const char *outdir) { } static PyObject* CppCoreInitialize(PyObject* self, PyObject* args) { - - char* depfilename, *outfilename; + char *depfilename, *outfilename; if (!PyArg_ParseTuple(args, "ss", &depfilename, &outfilename)) { return NULL; } @@ -82,7 +80,7 @@ static void PyList_from_vectorint(vector input, PyObject* output) { size_t vector_size = input.size(); for (size_t index = 0; index < vector_size; index++) { - PyObject *obj = Py_BuildValue("i", input[index]); + PyObject* obj = Py_BuildValue("i", input[index]); PyList_Append(output, obj); Py_DECREF(obj); } @@ -104,7 +102,7 @@ static void PyList_from_vectordouble(vector input, PyObject* output) { size_t vector_size = input.size(); for (size_t index = 0; index < vector_size; index++) { - PyObject *obj = Py_BuildValue("f", input[index]); + PyObject* obj = Py_BuildValue("f", input[index]); PyList_Append(output, obj); Py_DECREF(obj); } @@ -114,14 +112,14 @@ static void PyList_from_vectorstring(vector input, PyObject* output) { size_t vector_size = input.size(); for (size_t index = 0; index < vector_size; index++) { - PyObject *obj = Py_BuildValue("s", input[index].c_str()); + PyObject* obj = Py_BuildValue("s", input[index].c_str()); PyList_Append(output, obj); Py_DECREF(obj); } } -static PyObject* -_getfeature(PyObject* self, PyObject* args, const string &input_type) { +static PyObject* _getfeature(PyObject* self, PyObject* args, + const string& input_type) { char* feature_name; PyObject* py_values; @@ -134,7 +132,8 @@ _getfeature(PyObject* self, PyObject* args, const string &input_type) { try { string feature_type = pFeature->featuretype(string(feature_name)); - if (!input_type.empty() && feature_type != input_type){ // when types do not match + if (!input_type.empty() && + feature_type != input_type) { // when types do not match PyErr_SetString(PyExc_TypeError, "Feature type does not match"); return NULL; } @@ -144,30 +143,26 @@ _getfeature(PyObject* self, PyObject* args, const string &input_type) { return_value = pFeature->getFeature(string(feature_name), values); PyList_from_vectorint(values, py_values); return Py_BuildValue("i", return_value); - } else { // double + } else { // double vector values; return_value = pFeature->getFeature(string(feature_name), values); PyList_from_vectordouble(values, py_values); return Py_BuildValue("i", return_value); } - } - catch(EfelAssertionError& e) { // more specialised exception + } catch (EfelAssertionError& e) { // more specialised exception PyErr_SetString(PyExc_AssertionError, e.what()); return NULL; - } - catch(const std::runtime_error& e) { // e.g. feature does not exist + } catch (const std::runtime_error& e) { // e.g. feature does not exist + PyErr_SetString(PyExc_RuntimeError, e.what()); + return NULL; + } catch (const std::exception& e) { // catch standard exceptions PyErr_SetString(PyExc_RuntimeError, e.what()); return NULL; - } - catch(const std::exception& e) { // catch standard exceptions - PyErr_SetString(PyExc_RuntimeError, e.what()); - return NULL; } } - -static PyObject* -_getmapdata(PyObject* self, PyObject* args, const string &type) { +static PyObject* _getmapdata(PyObject* self, PyObject* args, + const string& type) { char* data_name; PyObject* py_values = PyList_New(0); @@ -240,11 +235,11 @@ static PyObject* setfeaturedouble(PyObject* self, PyObject* args) { } static PyObject* getfeaturedouble(PyObject* self, PyObject* args) { - const string type ("double"); + const string type("double"); return _getfeature(self, args, type); } -static PyObject* setfeaturestring(PyObject* self, PyObject* args){ +static PyObject* setfeaturestring(PyObject* self, PyObject* args) { char* feature_name; char* py_value; @@ -256,7 +251,6 @@ static PyObject* setfeaturestring(PyObject* self, PyObject* args){ return_value = pFeature->setFeatureString(string(feature_name), py_value); return Py_BuildValue("i", return_value); - } static PyObject* getFeatureNames(PyObject* self, PyObject* args) { @@ -272,25 +266,23 @@ static PyObject* getFeatureNames(PyObject* self, PyObject* args) { return Py_BuildValue(""); } -static PyObject* getDistance_wrapper(PyObject* self, - PyObject* args, +static PyObject* getDistance_wrapper(PyObject* self, PyObject* args, PyObject* kwds) { char* feature_name; - double mean, std, distance, error_dist=250; + double mean, std, distance, error_dist = 250; int trace_check = 1; - const char *kwlist[] = {"feature_name", "mean", "std", "trace_check", - "error_dist", NULL}; + const char* kwlist[] = {"feature_name", "mean", "std", + "trace_check", "error_dist", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "sdd|id", - const_cast(kwlist), - &feature_name, &mean, &std, - &trace_check, &error_dist)) { + const_cast(kwlist), &feature_name, + &mean, &std, &trace_check, &error_dist)) { return NULL; } - distance = pFeature->getDistance(feature_name, mean, std, - trace_check, error_dist); + distance = + pFeature->getDistance(feature_name, mean, std, trace_check, error_dist); return Py_BuildValue("d", distance); } @@ -316,41 +308,34 @@ static PyObject* getgerrorstr(PyObject* self, PyObject* args) { string errorStr = GErrorStr + pFeature->getGError(); GErrorStr.clear(); - return Py_BuildValue("s", errorStr.c_str()); } static PyMethodDef CppCoreMethods[] = { - {"Initialize", CppCoreInitialize, METH_VARARGS, - "Initialise CppCore."}, + {"Initialize", CppCoreInitialize, METH_VARARGS, "Initialise CppCore."}, {"getFeature", getfeature, METH_VARARGS, - "Get a values associated with a feature. Takes a list() to be filled."}, - {"getFeatureInt", getfeatureint, METH_VARARGS, - "Get a integer feature."}, + "Get a values associated with a feature. Takes a list() to be filled."}, + {"getFeatureInt", getfeatureint, METH_VARARGS, "Get a integer feature."}, {"getFeatureDouble", getfeaturedouble, METH_VARARGS, - "Get a double feature."}, - {"getMapIntData", getmapintdata, METH_VARARGS, - "Get a int data."}, - {"getMapDoubleData", getmapdoubledata, METH_VARARGS, - "Get a double data."}, - - {"setFeatureInt", setfeatureint, METH_VARARGS, - "Set a integer feature."}, + "Get a double feature."}, + {"getMapIntData", getmapintdata, METH_VARARGS, "Get a int data."}, + {"getMapDoubleData", getmapdoubledata, METH_VARARGS, "Get a double data."}, + + {"setFeatureInt", setfeatureint, METH_VARARGS, "Set a integer feature."}, {"setFeatureDouble", setfeaturedouble, METH_VARARGS, - "Set a double feature."}, + "Set a double feature."}, {"setFeatureString", setfeaturestring, METH_VARARGS, - "Set a string feature."}, + "Set a string feature."}, - {"featuretype", featuretype, METH_VARARGS, - "Get the type of a feature"}, - {"getgError", getgerrorstr, METH_VARARGS, - "Get CppCore error string"}, + {"featuretype", featuretype, METH_VARARGS, "Get the type of a feature"}, + {"getgError", getgerrorstr, METH_VARARGS, "Get CppCore error string"}, {"getFeatureNames", getFeatureNames, METH_VARARGS, - "Get the names of all the available features"}, + "Get the names of all the available features"}, - {"getDistance", (PyCFunction)getDistance_wrapper, METH_VARARGS|METH_KEYWORDS, - "Get the distance between a feature and experimental data"}, + {"getDistance", (PyCFunction)getDistance_wrapper, + METH_VARARGS | METH_KEYWORDS, + "Get the distance between a feature and experimental data"}, {NULL, NULL, 0, NULL} /* Sentinel */ }; @@ -369,10 +354,15 @@ static int cppcore_clear(PyObject* m) { return 0; } -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, "cppcore", NULL, - sizeof(struct module_state), CppCoreMethods, NULL, - cppcore_traverse, cppcore_clear, NULL}; +static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, + "cppcore", + NULL, + sizeof(struct module_state), + CppCoreMethods, + NULL, + cppcore_traverse, + cppcore_clear, + NULL}; extern "C" PyObject* PyInit_cppcore(void) { PyObject* module = PyModule_Create(&moduledef); diff --git a/efel/cppcore/mapoperations.cpp b/efel/cppcore/mapoperations.cpp index 27fae68c..7d574889 100644 --- a/efel/cppcore/mapoperations.cpp +++ b/efel/cppcore/mapoperations.cpp @@ -17,7 +17,8 @@ */ #include "mapoperations.h" -# include "EfelExceptions.h" + +#include "EfelExceptions.h" extern string GErrorStr; @@ -25,51 +26,50 @@ template std::map> getFeatures( const std::map>& allFeatures, const std::vector& requestedFeatures) { - - std::map> selectedFeatures; - for (const auto& featureKey : requestedFeatures) { - auto it = allFeatures.find(featureKey); - if (it == allFeatures.end()) { - throw FeatureComputationError("Feature " + featureKey + " not found"); - } else if (it->second.empty()) { - throw EmptyFeatureError("Feature " + featureKey + " is empty"); - } else { - selectedFeatures.insert(*it); - } + std::map> selectedFeatures; + for (const auto& featureKey : requestedFeatures) { + auto it = allFeatures.find(featureKey); + if (it == allFeatures.end()) { + throw FeatureComputationError("Feature " + featureKey + " not found"); + } else if (it->second.empty()) { + throw EmptyFeatureError("Feature " + featureKey + " is empty"); + } else { + selectedFeatures.insert(*it); } - return selectedFeatures; + } + return selectedFeatures; } template std::vector getFeature( const std::map>& allFeatures, const std::string& requestedFeature) { - - // Use getFeatures to retrieve a map with the single requested feature - auto selectedFeatures = getFeatures(allFeatures, {requestedFeature}); - - // Since we requested only one feature, we can directly access the value - // The exception handling in getFeatures ensures we have a valid, non-empty vector - return selectedFeatures.at(requestedFeature); -} + // Use getFeatures to retrieve a map with the single requested feature + auto selectedFeatures = getFeatures(allFeatures, {requestedFeature}); + // Since we requested only one feature, we can directly access the value + // The exception handling in getFeatures ensures we have a valid, non-empty + // vector + return selectedFeatures.at(requestedFeature); +} /* * get(Int|Double|Str)Param provides access to the Int, Double, Str map * */ -template +template int getParam(std::map>& featureData, - const std::string& param, std::vector& vec) { - auto itr = featureData.find(param); - if (itr == featureData.end()) { - GErrorStr += "Parameter [" + param + "] is missing in the map. " - "In the python interface, this can be set using the " - "appropriate setting function\n"; - return -1; - } - vec = itr->second; - return static_cast(vec.size()); + const std::string& param, std::vector& vec) { + auto itr = featureData.find(param); + if (itr == featureData.end()) { + GErrorStr += "Parameter [" + param + + "] is missing in the map. " + "In the python interface, this can be set using the " + "appropriate setting function\n"; + return -1; + } + vec = itr->second; + return static_cast(vec.size()); } int getStrParam(mapStr2Str& StringData, const string& param, string& value) { @@ -83,8 +83,8 @@ int getStrParam(mapStr2Str& StringData, const string& param, string& value) { } template -void setVec(std::map >& FeatureData, mapStr2Str& StringData, - string key, const vector& value){ +void setVec(std::map>& FeatureData, + mapStr2Str& StringData, string key, const vector& value) { string params; getStrParam(StringData, "params", params); key += params; @@ -107,13 +107,15 @@ template std::map> getFeatures( const std::map>& allFeatures, const std::vector& requestedFeatures); template int getParam(std::map>& featureData, - const std::string& param, std::vector& vec); + const std::string& param, std::vector& vec); template int getParam(std::map>& featureData, - const std::string& param, std::vector& vec); -template void setVec(std::map >& FeatureData, mapStr2Str& StringData, - string key, const vector& value); -template void setVec(std::map >& FeatureData, mapStr2Str& StringData, - string key, const vector& value); + const std::string& param, std::vector& vec); +template void setVec(std::map>& FeatureData, + mapStr2Str& StringData, string key, + const vector& value); +template void setVec(std::map>& FeatureData, + mapStr2Str& StringData, string key, + const vector& value); template std::vector getFeature( const std::map>& allFeatures, const std::string& requestedFeature); From d1101d9bdbf6da9e09056fb72dd0dda16aa0408e Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 11:30:28 +0100 Subject: [PATCH 44/85] replace throw EmptyFeatureError with return -1 for consistency --- efel/cppcore/LibV5.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 98ad820f..e8612c54 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -2204,7 +2204,7 @@ int LibV5::AP_width_between_threshold(mapStr2intVec& IntFeatureData, doubleFeatures.at("Threshold").front(), intFeatures.at("min_between_peaks_indices"), ap_width_threshold); if (retval == 0) - throw EmptyFeatureError("AP_width_between_threshold is empty"); + return -1; else if (retval > 0) { setVec(DoubleFeatureData, StringData, "AP_width_between_threshold", ap_width_threshold); From bde76affb3fb4812db2614aa0adbc93c58f381f0 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 11:46:30 +0100 Subject: [PATCH 45/85] remove redundant else condition --- efel/cppcore/LibV1.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index d6ca8c19..9ef731da 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -434,8 +434,6 @@ int LibV1::burst_mean_freq(mapStr2intVec& IntFeatureData, retValIgnore = getParam(IntFeatureData, "ignore_first_ISI", retIgnore); if ((retValIgnore == 1) && (retIgnore.size() > 0) && (retIgnore[0] == 0)) { IgnoreFirstISI = 0; - } else { - IgnoreFirstISI = 1; } vector BurstMeanFreq; int retVal = __burst_mean_freq(doubleFeatures.at("peak_time"), From d6848c3348064231d43f5cb0c680780d2408a6bb Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 11:48:02 +0100 Subject: [PATCH 46/85] avoid fetching ignore_first_ISI twice --- efel/cppcore/LibV1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index 9ef731da..9b8d7a7e 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -427,7 +427,7 @@ int LibV1::burst_mean_freq(mapStr2intVec& IntFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); const auto& intFeatures = - getFeatures(IntFeatureData, {"burst_ISI_indices", "ignore_first_ISI"}); + getFeatures(IntFeatureData, {"burst_ISI_indices"}); int IgnoreFirstISI = 1; int retValIgnore; vector retIgnore; From 3ca2801f3bf016ff0800e422d6dad7f9f45d09c7 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 12:49:16 +0100 Subject: [PATCH 47/85] in the spikewidth2 error message mention spikewidth2 --- efel/cppcore/LibV1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index 9b8d7a7e..c2d5f465 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -799,7 +799,7 @@ int LibV1::spike_width2(mapStr2intVec& IntFeatureData, getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); if (intFeatures.at("peak_indices").size() <= 1) { GErrorStr += - "\nError: More than one spike is needed for spikewidth calculation.\n"; + "\nError: More than one spike is needed for spikewidth2 calculation.\n"; return -1; } vector spike_width2; From 9b9d3829812ac86ca2758d823757d6deaea1b14e Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 13:05:49 +0100 Subject: [PATCH 48/85] update maximum_voltage's success case to be same asminimum_voltages --- efel/cppcore/LibV1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index c2d5f465..9b7c5e04 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -1093,7 +1093,7 @@ int LibV1::maximum_voltage(mapStr2intVec& IntFeatureData, int retVal = __maxmin_voltage(doubleFeatures.at("V"), doubleFeatures.at("T"), doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0], maxV, minV); - if (retVal >= 0) { + if (retVal > 0) { setVec(DoubleFeatureData, StringData, "maximum_voltage", maxV); } return retVal; From d5d5ed7466f8bdea726ff0140df9a93170bea680 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 13:43:28 +0100 Subject: [PATCH 49/85] make peakvoltage vector a reference in amp_drop_first_last --- efel/cppcore/LibV2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/efel/cppcore/LibV2.cpp b/efel/cppcore/LibV2.cpp index 216c9d7e..a0caf7e5 100644 --- a/efel/cppcore/LibV2.cpp +++ b/efel/cppcore/LibV2.cpp @@ -566,7 +566,7 @@ int LibV2::amp_drop_first_last(mapStr2intVec& IntFeatureData, mapStr2Str& StringData) { const auto& peakVoltageFeature = getFeatures(DoubleFeatureData, {"peak_voltage"}); - const vector peakvoltage = peakVoltageFeature.at("peak_voltage"); + const vector& peakvoltage = peakVoltageFeature.at("peak_voltage"); if (peakvoltage.size() < 2) { GErrorStr += From e7907c8e213c8917e0dfe92febad0e4fa031e74f Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 13:48:09 +0100 Subject: [PATCH 50/85] remove obsolete empty feature checks in spike_width1 --- efel/cppcore/LibV5.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index e8612c54..268cf9e8 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -390,13 +390,6 @@ int LibV5::spike_width1(mapStr2intVec& IntFeatureData, getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); vector spike_width1; - // Check if peak_indices and min_AHP_indices are empty - if (intFeatures.at("peak_indices").empty() || - intFeatures.at("min_AHP_indices").empty()) { - setVec(DoubleFeatureData, StringData, "spike_half_width", spike_width1); - return 0; - } - // Calculate spike width int retVal = __spike_width1(doubleFeatures.at("T"), doubleFeatures.at("V"), intFeatures.at("peak_indices"), From e790e161c35df4cd58c29ed20222abb34f69ff00 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 13:49:51 +0100 Subject: [PATCH 51/85] remove else after throw --- efel/cppcore/LibV5.cpp | 50 +++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 268cf9e8..e304fac1 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -715,11 +715,10 @@ int LibV5::AP2_amp(mapStr2intVec& IntFeatureData, if (AP_amplitudes.size() < 2) { throw FeatureComputationError( "Size of AP_amplitude should be >= 2 for AP2_amp"); - } else { - AP2_amp.push_back(AP_amplitudes[1]); - setVec(DoubleFeatureData, StringData, "AP2_amp", AP2_amp); - return 1; } + AP2_amp.push_back(AP_amplitudes[1]); + setVec(DoubleFeatureData, StringData, "AP2_amp", AP2_amp); + return 1; } // Peak voltage of the second spike @@ -732,11 +731,10 @@ int LibV5::AP2_peak(mapStr2intVec& IntFeatureData, if (peak_voltage.size() < 2) { throw FeatureComputationError( "Size of peak_voltage should be >= 2 for AP2_peak"); - } else { - AP2_peak.push_back(peak_voltage[1]); - setVec(DoubleFeatureData, StringData, "AP2_peak", AP2_peak); - return 1; } + AP2_peak.push_back(peak_voltage[1]); + setVec(DoubleFeatureData, StringData, "AP2_peak", AP2_peak); + return 1; } // Difference amplitude of the second to first spike @@ -749,11 +747,10 @@ int LibV5::AP2_AP1_diff(mapStr2intVec& IntFeatureData, if (AP_amplitudes.size() < 2) { throw FeatureComputationError( "Size of AP_amplitude should be >= 2 for AP2_AP1_diff"); - } else { - AP2_AP1_diff.push_back(AP_amplitudes[1] - AP_amplitudes[0]); - setVec(DoubleFeatureData, StringData, "AP2_AP1_diff", AP2_AP1_diff); - return 1; } + AP2_AP1_diff.push_back(AP_amplitudes[1] - AP_amplitudes[0]); + setVec(DoubleFeatureData, StringData, "AP2_AP1_diff", AP2_AP1_diff); + return 1; } // Difference peak_amp of the second to first spike @@ -766,12 +763,11 @@ int LibV5::AP2_AP1_peak_diff(mapStr2intVec& IntFeatureData, if (peak_voltage.size() < 2) { throw FeatureComputationError( "Size of peak_voltage should be >= 2 for AP2_AP1_peak_diff"); - } else { - AP2_AP1_peak_diff.push_back(peak_voltage[1] - peak_voltage[0]); - setVec(DoubleFeatureData, StringData, "AP2_AP1_peak_diff", - AP2_AP1_peak_diff); - return 1; } + AP2_AP1_peak_diff.push_back(peak_voltage[1] - peak_voltage[0]); + setVec(DoubleFeatureData, StringData, "AP2_AP1_peak_diff", + AP2_AP1_peak_diff); + return 1; } // Width of the first spike @@ -796,11 +792,10 @@ int LibV5::AP2_width(mapStr2intVec& IntFeatureData, if (spike_half_width.size() < 2) { throw FeatureComputationError( "Size of spike_half_width should be >= 2 for AP2_width"); - } else { - AP2_width.push_back(spike_half_width[1]); - setVec(DoubleFeatureData, StringData, "AP2_width", AP2_width); - return 1; } + AP2_width.push_back(spike_half_width[1]); + setVec(DoubleFeatureData, StringData, "AP2_width", AP2_width); + return 1; } // Width of the last spike @@ -897,9 +892,8 @@ int LibV5::AHP2_depth_from_peak(mapStr2intVec& IntFeatureData, if (ahpDepthFromPeak.size() < 2) { throw FeatureComputationError( "Size of AHP_depth_from_peak should be >= 2 for AHP2_depth_from_peak"); - } else { - ahp2DepthFromPeak.push_back(ahpDepthFromPeak[1]); } + ahp2DepthFromPeak.push_back(ahpDepthFromPeak[1]); setVec(DoubleFeatureData, StringData, "AHP2_depth_from_peak", ahp2DepthFromPeak); return 1; @@ -1043,10 +1037,8 @@ int LibV5::AP2_begin_voltage(mapStr2intVec& IntFeatureData, if (AP_begin_voltage.size() < 2) { throw FeatureComputationError("There are less than 2 spikes in the trace."); - } else { - AP2_begin_voltage.push_back(AP_begin_voltage[1]); } - + AP2_begin_voltage.push_back(AP_begin_voltage[1]); setVec(DoubleFeatureData, StringData, "AP2_begin_voltage", AP2_begin_voltage); return 1; } @@ -1070,9 +1062,8 @@ int LibV5::AP2_begin_width(mapStr2intVec& IntFeatureData, vector AP2_begin_width; if (AP_begin_width.size() < 2) { throw FeatureComputationError("There are less than 2 spikes in the trace."); - } else { - AP2_begin_width.push_back(AP_begin_width[1]); } + AP2_begin_width.push_back(AP_begin_width[1]); setVec(DoubleFeatureData, StringData, "AP2_begin_width", AP2_begin_width); return 1; } @@ -1086,9 +1077,8 @@ int LibV5::AP2_AP1_begin_width_diff(mapStr2intVec& IntFeatureData, vector AP2_AP1_begin_width_diff; if (AP_begin_widths.size() < 2) { throw FeatureComputationError("There are less than 2 spikes in the trace."); - } else { - AP2_AP1_begin_width_diff.push_back(AP_begin_widths[1] - AP_begin_widths[0]); } + AP2_AP1_begin_width_diff.push_back(AP_begin_widths[1] - AP_begin_widths[0]); setVec(DoubleFeatureData, StringData, "AP2_AP1_begin_width_diff", AP2_AP1_begin_width_diff); return 1; From f3adcc386205eb089c2a7765992ab9016325d3e6 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 13:57:57 +0100 Subject: [PATCH 52/85] update new line in code comment for readability --- efel/cppcore/LibV5.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index e304fac1..ea9b5be6 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -913,8 +913,8 @@ static int __AP_begin_width(const vector& t, const vector& v, // keep only min_ahp_indices values that are after stim start // because AP_begin_indices are all after stim start - // if not done, could cause cases where AP_begin_indices[i] > - // min_ahp_indices[i] leading to segmentation faults + // if not done, could cause cases where AP_begin_indices[i] > min_ahp_indices[i] + // leading to segmentation faults auto it = find_if(t.begin(), t.end(), [stimstart](double val) { return val >= stimstart; }); int stimbeginindex = distance(t.begin(), it); From 83a57b18e1bb8df0b7330d52aca0895832266bb6 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 14:59:35 +0100 Subject: [PATCH 53/85] replace GErrorStr+1 and return -1 via exception --- efel/cppcore/LibV1.cpp | 104 +++++++++++-------------------------- efel/cppcore/LibV2.cpp | 16 ++---- efel/cppcore/LibV5.cpp | 114 ++++++++++++----------------------------- 3 files changed, 67 insertions(+), 167 deletions(-) diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index 9b7c5e04..e6a1c421 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -97,10 +97,8 @@ int LibV1::ISI_values(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); - if (doubleFeatures.at("peak_time").size() < 3) { - GErrorStr += "\n Three spikes required for calculation of ISI_values.\n"; - return -1; - } + if (doubleFeatures.at("peak_time").size() < 3) + throw FeatureComputationError("Three spikes required for calculation of ISI_values."); const auto& intFeatures = getFeatures(IntFeatureData, {"ignore_first_ISI"}); int IgnoreFirstISI = 1; @@ -178,10 +176,8 @@ int LibV1::firing_rate(mapStr2intVec& IntFeatureData, nCount++; } } - if (lastAPTime == doubleFeatures.at("stim_start")[0]) { - GErrorStr += "\nPrevent divide by zero.\n"; - return -1; - } + if (lastAPTime == doubleFeatures.at("stim_start")[0]) + throw FeatureComputationError("Prevent divide by zero."); vector firing_rate; firing_rate.push_back(nCount * 1000 / (lastAPTime - doubleFeatures.at("stim_start")[0])); @@ -208,10 +204,8 @@ int LibV1::first_spike_time(mapStr2intVec& IntFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); - if (doubleFeatures.at("peak_time").size() < 1) { - GErrorStr += "\n One spike required for time_to_first_spike.\n"; - return -1; - } + if (doubleFeatures.at("peak_time").size() < 1) + throw FeatureComputationError("One spike required for time_to_first_spike."); vector first_spike; first_spike.push_back(doubleFeatures.at("peak_time")[0] - doubleFeatures.at("stim_start")[0]); @@ -236,13 +230,8 @@ int LibV1::AP_amplitude(mapStr2intVec& IntFeatureData, getFeatures(DoubleFeatureData, {"V", "stim_start", "stim_end", "peak_voltage", "peak_time"}); const auto& intFeatures = getFeatures(IntFeatureData, {"AP_begin_indices"}); - if (doubleFeatures.at("peak_voltage").size() != - doubleFeatures.at("peak_time").size()) { - GErrorStr += - "AP_amplitude: Not the same amount of peak_time and peak_voltage " - "entries"; - return -1; - } + if (doubleFeatures.at("peak_voltage").size() != doubleFeatures.at("peak_time").size()) + throw FeatureComputationError("AP_amplitude: Not the same amount of peak_time and peak_voltage entries"); vector peakvoltage_duringstim; for (size_t i = 0; i < doubleFeatures.at("peak_time").size(); i++) { if (doubleFeatures.at("peak_time")[i] >= @@ -251,13 +240,8 @@ int LibV1::AP_amplitude(mapStr2intVec& IntFeatureData, peakvoltage_duringstim.push_back(doubleFeatures.at("peak_voltage")[i]); } } - if (peakvoltage_duringstim.size() > - intFeatures.at("AP_begin_indices").size()) { - GErrorStr += - "AP_amplitude: More peak_voltage entries during the stimulus than " - "AP_begin_indices entries"; - return -1; - } + if (peakvoltage_duringstim.size() > intFeatures.at("AP_begin_indices").size()) + throw FeatureComputationError("AP_amplitude: More peak_voltage entries during the stimulus than AP_begin_indices entries"); vector apamplitude; apamplitude.resize(peakvoltage_duringstim.size()); for (size_t i = 0; i < apamplitude.size(); i++) { @@ -301,12 +285,8 @@ int LibV1::AHP_depth_abs_slow(mapStr2intVec& IntFeatureData, const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"T", "V", "sahp_start"}); const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); - if (intFeatures.at("peak_indices").size() < 3) { - GErrorStr += - "\n At least 3 spikes needed for AHP_depth_abs_slow and " - "AHP_slow_time.\n"; - return -1; - } + if (intFeatures.at("peak_indices").size() < 3) + throw FeatureComputationError("At least 3 spikes needed for AHP_depth_abs_slow and AHP_slow_time."); double sahp_start = (doubleFeatures.at("sahp_start").empty()) ? 5 : doubleFeatures.at("sahp_start")[0]; @@ -372,11 +352,8 @@ int LibV1::burst_ISI_indices(mapStr2intVec& IntFeatureData, const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"ISI_values", "burst_factor"}); const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); - if (intFeatures.at("peak_indices").size() < 5) { - GErrorStr += - "\nError: More than 5 spike is needed for burst calculation.\n"; - return -1; - } + if (intFeatures.at("peak_indices").size() < 5) + throw FeatureComputationError("More than 5 spikes are needed for burst calculation."); double BurstFactor = (doubleFeatures.at("burst_factor").empty()) ? 2 : doubleFeatures.at("burst_factor")[0]; @@ -542,10 +519,8 @@ static int __adaptation_index(double spikeSkipf, int maxnSpike, } // Adaptation index can not be calculated if nAPVec <4 or no of ISI is <3 - if (SpikeTime.size() < 4) { - GErrorStr += "\nMinimum 4 spike needed for feature [adaptation_index].\n"; - return -1; - } + if (SpikeTime.size() < 4) + throw FeatureComputationError("Minimum 4 spikes needed for feature [adaptation_index]."); // Generate ISI vector list::iterator lstItr = SpikeTime.begin(); @@ -579,8 +554,7 @@ int LibV1::adaptation_index(mapStr2intVec& IntFeatureData, if (doubleFeatures.at("spike_skipf")[0] < 0 || doubleFeatures.at("spike_skipf")[0] >= 1) { - GErrorStr += "\nspike_skipf should lie between [0 1).\n"; - return -1; + throw FeatureComputationError("spike_skipf should lie between [0 1)."); } vector OffSetVec; double Offset; @@ -620,10 +594,7 @@ static int __adaptation_index2(double StimStart, double StimEnd, double Offset, } if (SpikeTime.size() < 4) { - GErrorStr += - "\n At least 4 spikes within stimulus interval needed for " - "adaptation_index2.\n"; - return -1; + throw FeatureComputationError("At least 4 spikes within stimulus interval needed for adaptation_index2."); } // start at second ISI: SpikeTime.pop_front(); @@ -664,8 +635,7 @@ int LibV1::adaptation_index2(mapStr2intVec& IntFeatureData, Offset = OffSetVec[0]; if (doubleFeatures.at("peak_time").size() < 4) { - GErrorStr += "\n At least 4 spikes needed for adaptation_index2.\n"; - return -1; + throw FeatureComputationError("At least 4 spikes needed for adaptation_index2."); } vector adaptationindex2; @@ -700,10 +670,7 @@ int LibV1::trace_check(mapStr2intVec& IntFeatureData, setVec(IntFeatureData, StringData, "trace_check", tc); return tc.size(); } else { - GErrorStr += - "Trace sanity check failed, there were spike outside the stimulus " - "interval.\n"; - return -1; + throw FeatureComputationError("Trace sanity check failed, there were spike outside the stimulus interval."); } } @@ -724,8 +691,7 @@ static int __spike_width2(const vector& t, const vector& V, for (int j = minAHPIndex[i]; j <= PeakIndex[i + 1]; j++) { if (j < 0) { - GErrorStr += "\nInvalid index\n"; - return -1; + throw FeatureComputationError("Invalid index"); } v.push_back(V[j]); } @@ -775,8 +741,7 @@ static int __spike_width2(const vector& t, const vector& V, } if (index == V.size()) { - GErrorStr += "\nFalling phase of last spike is missing.\n"; - return -1; + throw FeatureComputationError("Falling phase of last spike is missing."); } T0 = t[index - 1]; @@ -798,9 +763,7 @@ int LibV1::spike_width2(mapStr2intVec& IntFeatureData, const auto& intFeatures = getFeatures(IntFeatureData, {"min_AHP_indices", "peak_indices"}); if (intFeatures.at("peak_indices").size() <= 1) { - GErrorStr += - "\nError: More than one spike is needed for spikewidth2 calculation.\n"; - return -1; + throw FeatureComputationError("More than one spike is needed for spikewidth2 calculation."); } vector spike_width2; int retVal = __spike_width2(doubleFeatures.at("T"), doubleFeatures.at("V"), @@ -866,8 +829,7 @@ static int __time_constant(const vector& v, const vector& t, return val > -min_derivative; }) != dvdt.begin() + i_start + 5) { if (dvdt.begin() + i_start + 5 == dvdt.end()) { - GErrorStr += "Could not find the decay.\n"; - return -1; + throw FeatureComputationError("Could not find the decay."); } i_start++; } @@ -902,8 +864,7 @@ static int __time_constant(const vector& v, const vector& t, vector t_decay(part_t.begin() + i_start, part_t.begin() + i_flat); vector v_decay(part_v.begin() + i_start, part_v.begin() + i_flat); if (dvdt_decay.size() < min_length) { - GErrorStr += "\nTrace fall time too short.\n"; - return -1; + throw FeatureComputationError("Trace fall time too short."); } // fit to exponential @@ -1053,10 +1014,8 @@ int LibV1::ohmic_input_resistance(mapStr2intVec& IntFeatureData, static int __maxmin_voltage(const vector& v, const vector& t, double stimStart, double stimEnd, vector& maxV, vector& minV) { - if (stimStart > t[t.size() - 1]) { - GErrorStr += "\nStimulus start larger than max time in trace\n"; - return -1; - } + if (stimStart > t[t.size() - 1]) + throw FeatureComputationError("Stimulus start larger than max time in trace"); if (stimEnd > t[t.size() - 1]) stimEnd = t.back(); @@ -1065,8 +1024,7 @@ static int __maxmin_voltage(const vector& v, const vector& t, stimstartindex++; if (stimstartindex >= t.size()) { - GErrorStr += "\nStimulus start index not found\n"; - return -1; + throw FeatureComputationError("Stimulus start index not found"); } size_t stimendindex = 0; @@ -1074,8 +1032,7 @@ static int __maxmin_voltage(const vector& v, const vector& t, stimendindex++; if (stimendindex >= t.size()) { - GErrorStr += "\nStimulus end index not found\n"; - return -1; + throw FeatureComputationError("Stimulus end index not found"); } maxV.push_back(*max_element(&v[stimstartindex], &v[stimendindex])); @@ -1269,8 +1226,7 @@ int LibV1::doublet_ISI(mapStr2intVec& IntFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"peak_time"}); if (doubleFeatures.at("peak_time").size() < 2) { - GErrorStr += "\nNeed at least two spikes for doublet_ISI.\n"; - return -1; + throw FeatureComputationError("Need at least two spikes for doublet_ISI."); } vector doubletisi( 1, doubleFeatures.at("peak_time")[1] - doubleFeatures.at("peak_time")[0]); diff --git a/efel/cppcore/LibV2.cpp b/efel/cppcore/LibV2.cpp index a0caf7e5..e5788293 100644 --- a/efel/cppcore/LibV2.cpp +++ b/efel/cppcore/LibV2.cpp @@ -542,9 +542,7 @@ int LibV2::amp_drop_first_second(mapStr2intVec& IntFeatureData, const vector peakvoltage = features.at("peak_voltage"); if (peakvoltage.size() < 2) { - GErrorStr += - "At least 2 spikes needed for calculation of amp_drop_first_second.\n"; - return -1; + throw FeatureComputationError("At least 2 spikes needed for calculation of amp_drop_first_second."); } vector ampdropfirstsecond; int retval = __amp_drop_first_second(peakvoltage, ampdropfirstsecond); @@ -569,9 +567,7 @@ int LibV2::amp_drop_first_last(mapStr2intVec& IntFeatureData, const vector& peakvoltage = peakVoltageFeature.at("peak_voltage"); if (peakvoltage.size() < 2) { - GErrorStr += - "At least 2 spikes needed for calculation of amp_drop_first_last.\n"; - return -1; + throw FeatureComputationError("At least 2 spikes needed for calculation of amp_drop_first_last."); } vector ampdropfirstlast; int retval = __amp_drop_first_last(peakvoltage, ampdropfirstlast); @@ -597,9 +593,7 @@ int LibV2::amp_drop_second_last(mapStr2intVec& IntFeatureData, const vector& peakvoltage = peakVoltageFeatures.at("peak_voltage"); // Ensure there are at least 3 spikes for calculation if (peakvoltage.size() < 3) { - GErrorStr += - "At least 3 spikes needed for calculation of amp_drop_second_last.\n"; - return -1; + throw FeatureComputationError("At least 3 spikes needed for calculation of amp_drop_second_last."); } vector ampdropsecondlast; int retval = __amp_drop_second_last(peakvoltage, ampdropsecondlast); @@ -633,9 +627,7 @@ int LibV2::max_amp_difference(mapStr2intVec& IntFeatureData, // Ensure there are at least 2 spikes for calculation if (features.at("peak_voltage").size() < 2) { - GErrorStr += - "At least 2 spikes needed for calculation of max_amp_difference.\n"; - return -1; + throw FeatureComputationError("At least 2 spikes needed for calculation of max_amp_difference."); } vector maxampdifference; int retval = diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index ea9b5be6..e0abd90e 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -117,10 +117,8 @@ int LibV5::ISI_log_slope_skip(mapStr2intVec& IntFeatureData, const auto maxnSpike = getFeature(IntFeatureData, {"max_spike_skip"}).front(); // Check the validity of spikeSkipf value - if (spikeSkipf < 0 || spikeSkipf >= 1) { - GErrorStr += "\nspike_skipf should lie between [0 1).\n"; - return -1; - } + if (spikeSkipf < 0 || spikeSkipf >= 1) + throw FeatureComputationError("spike_skipf should lie between [0 1)."); vector slope; bool semilog = false; @@ -142,10 +140,9 @@ int LibV5::time_to_second_spike(mapStr2intVec& IntFeatureData, getFeatures(DoubleFeatureData, {"peak_time", "stim_start"}); const auto& peaktime = doubleFeatures.at("peak_time"); const auto& stimstart = doubleFeatures.at("stim_start"); - if (peaktime.size() < 2) { - GErrorStr += "\n Two spikes required for time_to_second_spike.\n"; - return -1; - } + if (peaktime.size() < 2) + throw FeatureComputationError("Two spikes required for time_to_second_spike."); + vector second_spike = {peaktime[1] - stimstart[0]}; setVec(DoubleFeatureData, StringData, "time_to_second_spike", second_spike); return 1; @@ -450,10 +447,8 @@ static int __AP_begin_indices(const vector& t, const vector& v, } } int endindex = distance(t.begin(), t.end()); - if (minima.size() < peak_indices.size()) { - GErrorStr += "\nMore peaks than min_AHP in AP_begin_indices\n"; - return -1; - } + if (minima.size() < peak_indices.size()) + throw FeatureComputationError("More peaks than min_AHP in AP_begin_indices."); // printf("Found %d minima\n", minima.size()); for (size_t i = 0; i < peak_indices.size(); i++) { @@ -523,10 +518,8 @@ int LibV5::AP_begin_indices(mapStr2intVec& IntFeatureData, // Get DerivativeWindow vector derivative_window; retVal = getParam(IntFeatureData, "DerivativeWindow", derivative_window); - if (retVal <= 0) { - GErrorStr += "\nDerivativeWindow not set\n"; - return -1; - } + if (retVal <= 0) + throw FeatureComputationError("DerivativeWindow not set."); // Calculate feature retVal = __AP_begin_indices( @@ -1268,10 +1261,8 @@ int LibV5::all_ISI_values(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const vector& peak_time = getFeature(DoubleFeatureData, "peak_time"); - if (peak_time.size() < 2) { - GErrorStr += "\n Two spikes required for calculation of all_ISI_values.\n"; - return -1; - } + if (peak_time.size() < 2) + throw FeatureComputationError("Two spikes required for calculation of all_ISI_values."); vector VecISI; for (size_t i = 1; i < peak_time.size(); i++) { @@ -1414,10 +1405,8 @@ int LibV5::voltage_base(mapStr2intVec& IntFeatureData, double endTime = stimStart[0] * vb_end_perc; // Validate start and end times. - if (startTime >= endTime) { - GErrorStr += "\nvoltage_base: startTime >= endTime\n"; - return -1; - } + if (startTime >= endTime) + throw FeatureComputationError("voltage_base: startTime >= endTime"); const auto& precisionThreshold = getFeature(DoubleFeatureData, "precision_threshold"); @@ -1443,11 +1432,8 @@ int LibV5::voltage_base(mapStr2intVec& IntFeatureData, vBase = vec_mean(subVector); else if (computation_mode == "median") vBase = vec_median(subVector); - else { - GErrorStr += - "\nUndefined computational mode. Only mean and median are enabled\n"; - return -1; - } + else + throw FeatureComputationError("Undefined computational mode. Only mean and median are enabled."); vector vRest = {vBase}; setVec(DoubleFeatureData, StringData, "voltage_base", vRest); @@ -1477,10 +1463,8 @@ int LibV5::current_base(mapStr2intVec& IntFeatureData, double startTime = doubleFeatures.at("stim_start")[0] * cb_start_perc; double endTime = doubleFeatures.at("stim_start")[0] * cb_end_perc; - if (startTime >= endTime) { - GErrorStr += "\ncurrent_base: startTime >= endTime\n"; - return -1; - } + if (startTime >= endTime) + throw FeatureComputationError("current_base: startTime >= endTime"); vector precisionThreshold; int retVal = @@ -1501,12 +1485,8 @@ int LibV5::current_base(mapStr2intVec& IntFeatureData, iBase = vec_mean(subVector); else if (computation_mode == "median") iBase = vec_median(subVector); - else { - GErrorStr += - "\ncurrent_base error: Undefined computational mode. Only mean and " - "median are enabled\n"; - return -1; - } + else + throw FeatureComputationError("Undefined computational mode. Only mean and median are enabled."); vector iRest{iBase}; setVec(DoubleFeatureData, StringData, "current_base", iRest); @@ -1543,10 +1523,7 @@ double __decay_time_constant_after_stim(const vector& times, } if (decayTimes.size() < 1 || decayValues.size() < 1) { - GErrorStr += - "\ndecay_time_constant_after_stim: no data points to calculate this " - "feature\n"; - return -1; + throw FeatureComputationError("No data points to calculate decay_time_constant_after_stim"); } else { linear_fit_result fit; fit = slope_straight_line_fit(decayTimes, decayValues); @@ -1581,11 +1558,8 @@ int LibV5::decay_time_constant_after_stim(mapStr2intVec& IntFeatureData, decay_end_after_stim = 10.0; // Default value if not found } // Validate decay times - if (decay_start_after_stim >= decay_end_after_stim) { - GErrorStr += - "Error decay_start_after_stim small larger than decay_end_after_stim"; - return -1; - } + if (decay_start_after_stim >= decay_end_after_stim) + throw FeatureComputationError("Error decay_start_after_stim small larger than decay_end_after_stim"); // Perform calculation const double val = __decay_time_constant_after_stim( @@ -1683,10 +1657,7 @@ static int __sag_time_constant(const vector& times, decayValues[i] = log(u0); } if (decayValues.size() < min_length) { - GErrorStr += - "\nsag time constant: Not enough data points to compute time " - "constant.\n"; - return -1; + throw FeatureComputationError("Not enough data points to compute time constant."); } linear_fit_result fit; fit = slope_straight_line_fit(TInterval, decayValues); @@ -1901,11 +1872,8 @@ int LibV5::sag_amplitude(mapStr2intVec& IntFeatureData, sag_amplitude.push_back( doubleFeatures.at("steady_state_voltage_stimend")[0] - doubleFeatures.at("minimum_voltage")[0]); - } else { - // In case of positive voltage deflection, return an error - GErrorStr += "\nsag_amplitude: voltage_deflection is positive\n"; - return -1; - } + } else + throw FeatureComputationError("sag_amplitude: voltage_deflection is positive"); if (!sag_amplitude.empty()) { setVec(DoubleFeatureData, StringData, "sag_amplitude", sag_amplitude); @@ -1921,11 +1889,8 @@ int LibV5::sag_ratio1(mapStr2intVec& IntFeatureData, DoubleFeatureData, {"sag_amplitude", "voltage_base", "minimum_voltage"}); vector sag_ratio1; - if (doubleFeatures.at("minimum_voltage")[0] == - doubleFeatures.at("voltage_base")[0]) { - GErrorStr += "\nsag_ratio1: voltage_base equals minimum_voltage\n"; - // In case of possible division by zero return error - return -1; + if (doubleFeatures.at("minimum_voltage")[0] == doubleFeatures.at("voltage_base")[0]) { + throw FeatureComputationError("voltage_base equals minimum_voltage"); } else { sag_ratio1.push_back(doubleFeatures.at("sag_amplitude")[0] / (doubleFeatures.at("voltage_base")[0] - @@ -1947,11 +1912,8 @@ int LibV5::sag_ratio2(mapStr2intVec& IntFeatureData, {"voltage_base", "minimum_voltage", "steady_state_voltage_stimend"}); vector sag_ratio2; - if (doubleFeatures.at("minimum_voltage")[0] == - doubleFeatures.at("voltage_base")[0]) { - GErrorStr += "\nsag_ratio2: voltage_base equals minimum_voltage\n"; - // In case of possible division by zero return error - return -1; + if (doubleFeatures.at("minimum_voltage")[0] == doubleFeatures.at("voltage_base")[0]) { + throw FeatureComputationError("voltage_base equals minimum_voltage"); } else { sag_ratio2.push_back( (doubleFeatures.at("voltage_base")[0] - @@ -2400,10 +2362,7 @@ static int __ADP_peak_indices(const vector& v, vector& ADP_peak_indices, vector& ADP_peak_values) { if (min_AHP_indices.size() > min_between_peaks_indices.size()) { - GErrorStr += - "\nmin_AHP_indices should not have less elements than " - "min_between_peaks_indices\n"; - return -1; + throw FeatureComputationError("min_AHP_indices should not have less elements than min_between_peaks_indices"); } unsigned adp_peak_index; @@ -2456,12 +2415,8 @@ int LibV5::ADP_peak_amplitude(mapStr2intVec& IntFeatureData, const vector& min_AHP_values = doubleFeatures.at("min_AHP_values"); const vector& ADP_peak_values = doubleFeatures.at("ADP_peak_values"); - if (min_AHP_values.size() != ADP_peak_values.size()) { - GErrorStr += - "\nmin_AHP_values and ADP_peak_values should have the same number of " - "elements\n"; - return -1; - } + if (min_AHP_values.size() != ADP_peak_values.size()) + throw FeatureComputationError("min_AHP_values and ADP_peak_values should have the same number of elements"); for (size_t i = 0; i < ADP_peak_values.size(); i++) { ADP_peak_amplitude.push_back(ADP_peak_values[i] - min_AHP_values[i]); } @@ -2602,10 +2557,7 @@ int LibV5::time_to_interburst_min(mapStr2intVec& IntFeatureData, intFeatures.at("interburst_min_indices"); if (burst_end_indices.size() < interburst_min_indices.size()) { - GErrorStr += - "\nburst_end_indices should not have less elements than " - "interburst_min_indices\n"; - return -1; + throw FeatureComputationError("burst_end_indices should not have less elements than interburst_min_indices"); } for (size_t i = 0; i < interburst_min_indices.size(); i++) { From 444bfe7d4e99c94062e213ae40f47035c3f960f8 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 16:46:43 +0100 Subject: [PATCH 54/85] add test to cover single spike case in min_voltage_between_spikes --- efel/cppcore/LibV5.cpp | 5 ++--- tests/test_basic.py | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index e0abd90e..33959e3b 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -1295,9 +1295,8 @@ int LibV5::min_voltage_between_spikes(mapStr2intVec& IntFeatureData, const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); if (intFeatures.at("peak_indices").size() < 2) { - setVec(DoubleFeatureData, StringData, "min_voltage_between_spikes", - vector()); - return 0; + throw FeatureComputationError( + "Size of peak_indices should be >= 2 for min_voltage_between_spikes"); } vector min_voltage_between_spikes; diff --git a/tests/test_basic.py b/tests/test_basic.py index bf5c682b..117415d1 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1651,6 +1651,26 @@ def test_min_voltage_between_spikes1(): min_voltage_between_spikes_value) +def test_min_voltage_between_spikes_single_spike(): + """basic: Test min_voltage_between_spikes testing the edge case of 1 spike.""" + import efel + efel.reset() + + time, voltage = load_ascii_input(meanfrequency1_url) + # get the last 45% of time and voltage (contains a single spike) + time = time[-int(len(time) * 0.45):] + voltage = voltage[-int(len(voltage) * 0.45):] + # stim_start and stim_end are not effective for this feature + trace = {'T': time, 'V': voltage, 'stim_start': [-2], 'stim_end': [-1]} + + features = ['min_voltage_between_spikes'] + feature_values = \ + efel.getFeatureValues( + [trace], + features) + assert feature_values[0]['min_voltage_between_spikes'] is None + + def test_getFeatureNames(): """basic: Test getting all feature names""" import efel From 5a5c22d25df2f0176ae2a7becc90b1067c48d399 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 17:18:32 +0100 Subject: [PATCH 55/85] cover stimulus_current==0.0 edge case in ohmic resistance features --- efel/cppcore/LibV1.cpp | 2 ++ efel/cppcore/LibV5.cpp | 6 ++++-- tests/test_basic.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index e6a1c421..02706b1e 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -992,6 +992,8 @@ int LibV1::voltage_deflection(mapStr2intVec& IntFeatureData, static int __ohmic_input_resistance(double voltage_deflection, double stimulus_current, vector& oir) { + if (stimulus_current == 0) + throw FeatureComputationError("Stimulus current is zero which will result in division by zero."); oir.push_back(voltage_deflection / stimulus_current); return 1; } diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 33959e3b..e61327e1 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -1712,10 +1712,12 @@ int LibV5::ohmic_input_resistance_vb_ssse(mapStr2intVec& IntFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures( DoubleFeatureData, {"voltage_deflection_vb_ssse", "stimulus_current"}); + const double stimulus_current = doubleFeatures.at("stimulus_current")[0]; + if (stimulus_current == 0) + throw FeatureComputationError("Stimulus current is zero which will result in division by zero."); vector ohmic_input_resistance_vb_ssse; ohmic_input_resistance_vb_ssse.push_back( - doubleFeatures.at("voltage_deflection_vb_ssse")[0] / - doubleFeatures.at("stimulus_current")[0]); + doubleFeatures.at("voltage_deflection_vb_ssse")[0] / stimulus_current); setVec(DoubleFeatureData, StringData, "ohmic_input_resistance_vb_ssse", ohmic_input_resistance_vb_ssse); diff --git a/tests/test_basic.py b/tests/test_basic.py index 117415d1..f8edf044 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1367,6 +1367,23 @@ def test_ohmic_inputresistance(): stimulus_current) +def test_ohmic_inputresistance_zero_stimulus_current(): + """Test the edge case of having 0.0 stimulus current.""" + import efel + efel.reset() + + time, voltage = load_ascii_input(meanfrequency1_url) + trace = {'T': time, 'V': voltage, 'stim_start': [-2], 'stim_end': [-1]} + features = ['ohmic_input_resistance'] + + stimulus_current = 0.0 + efel.setDoubleSetting('stimulus_current', stimulus_current) + feature_values = efel.getFeatureValues([trace], features) + + ohmic_input_resistance = feature_values[0]['ohmic_input_resistance'] + assert ohmic_input_resistance is None + + def test_sag_amplitude(): """basic: Test sag_amplitude""" @@ -1579,6 +1596,22 @@ def test_ohmic_input_resistance_vb_ssse(): stimulus_current) +def test_ohmic_input_resistance_vb_ssse_zero_stimulus_current(): + """edge case of having zero stimulus current.""" + import efel + efel.reset() + + time, voltage = load_ascii_input(meanfrequency1_url) + # start and end times are not used for this feature + trace = {'T': time, 'V': voltage, 'stim_start': [500.0], 'stim_end': [900.0]} + + stimulus_current = 0.0 + efel.setDoubleSetting('stimulus_current', stimulus_current) + feature_values = efel.getFeatureValues([trace], ['ohmic_input_resistance_vb_ssse']) + ohmic_input_resistance = feature_values[0]['ohmic_input_resistance_vb_ssse'] + assert ohmic_input_resistance is None + + def test_spikecount2(): """basic: Test Spikecount 2: test empty trace""" From d7c576f592a3b0afc5fdfe87e20daa44e6fa8f5c Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 17:23:06 +0100 Subject: [PATCH 56/85] remove else after throw in 3 LibV5 places --- efel/cppcore/LibV5.cpp | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index e61327e1..a724a9ba 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -1523,13 +1523,12 @@ double __decay_time_constant_after_stim(const vector& times, if (decayTimes.size() < 1 || decayValues.size() < 1) { throw FeatureComputationError("No data points to calculate decay_time_constant_after_stim"); - } else { - linear_fit_result fit; - fit = slope_straight_line_fit(decayTimes, decayValues); + } + linear_fit_result fit; + fit = slope_straight_line_fit(decayTimes, decayValues); - const double tau = -1.0 / fit.slope; - return std::abs(tau); - } + const double tau = -1.0 / fit.slope; + return std::abs(tau); } // *** Decay time constant measured during decay after the stimulus*** @@ -1890,13 +1889,12 @@ int LibV5::sag_ratio1(mapStr2intVec& IntFeatureData, DoubleFeatureData, {"sag_amplitude", "voltage_base", "minimum_voltage"}); vector sag_ratio1; - if (doubleFeatures.at("minimum_voltage")[0] == doubleFeatures.at("voltage_base")[0]) { + if (doubleFeatures.at("minimum_voltage")[0] == doubleFeatures.at("voltage_base")[0]) throw FeatureComputationError("voltage_base equals minimum_voltage"); - } else { - sag_ratio1.push_back(doubleFeatures.at("sag_amplitude")[0] / - (doubleFeatures.at("voltage_base")[0] - - doubleFeatures.at("minimum_voltage")[0])); - } + + sag_ratio1.push_back(doubleFeatures.at("sag_amplitude")[0] / + (doubleFeatures.at("voltage_base")[0] - + doubleFeatures.at("minimum_voltage")[0])); if (!sag_ratio1.empty()) { setVec(DoubleFeatureData, StringData, "sag_ratio1", sag_ratio1); @@ -1913,15 +1911,14 @@ int LibV5::sag_ratio2(mapStr2intVec& IntFeatureData, {"voltage_base", "minimum_voltage", "steady_state_voltage_stimend"}); vector sag_ratio2; - if (doubleFeatures.at("minimum_voltage")[0] == doubleFeatures.at("voltage_base")[0]) { + if (doubleFeatures.at("minimum_voltage")[0] == doubleFeatures.at("voltage_base")[0]) throw FeatureComputationError("voltage_base equals minimum_voltage"); - } else { - sag_ratio2.push_back( - (doubleFeatures.at("voltage_base")[0] - - doubleFeatures.at("steady_state_voltage_stimend")[0]) / - (doubleFeatures.at("voltage_base")[0] - - doubleFeatures.at("minimum_voltage")[0])); - } + + sag_ratio2.push_back( + (doubleFeatures.at("voltage_base")[0] - + doubleFeatures.at("steady_state_voltage_stimend")[0]) / + (doubleFeatures.at("voltage_base")[0] - + doubleFeatures.at("minimum_voltage")[0])); if (!sag_ratio2.empty()) { setVec(DoubleFeatureData, StringData, "sag_ratio2", sag_ratio2); From 944140a715be15c740d33ce47c0c250cf554b5fd Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 15 Dec 2023 14:50:00 +0100 Subject: [PATCH 57/85] typo in test name --- tests/test_basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index f8edf044..360228d1 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1367,7 +1367,7 @@ def test_ohmic_inputresistance(): stimulus_current) -def test_ohmic_inputresistance_zero_stimulus_current(): +def test_ohmic_input_resistance_zero_stimulus_current(): """Test the edge case of having 0.0 stimulus current.""" import efel efel.reset() From b3a33f307e534a491263b3901b615cae799c01fa Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 15 Dec 2023 14:51:06 +0100 Subject: [PATCH 58/85] test_ohmic_input_resistance_zero_stimulus_current update stim params --- tests/test_basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index 360228d1..ebc95042 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1373,7 +1373,7 @@ def test_ohmic_input_resistance_zero_stimulus_current(): efel.reset() time, voltage = load_ascii_input(meanfrequency1_url) - trace = {'T': time, 'V': voltage, 'stim_start': [-2], 'stim_end': [-1]} + trace = {'T': time, 'V': voltage, 'stim_start': [500], 'stim_end': [900]} features = ['ohmic_input_resistance'] stimulus_current = 0.0 From 1253dd3d790e7e3c7a36fb3549c86b31f23a76a1 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 19 Dec 2023 11:07:13 +0100 Subject: [PATCH 59/85] update fail case for spikecount & spikecount_stimint --- efel/cppcore/LibV1.cpp | 8 +------- efel/cppcore/LibV5.cpp | 37 +++++++++++------------------------ efel/pyfeatures/pyfeatures.py | 2 ++ tests/test_basic.py | 4 ++-- 4 files changed, 16 insertions(+), 35 deletions(-) diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index 02706b1e..2202e24b 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -80,13 +80,7 @@ int LibV1::interpolate(mapStr2intVec& IntFeatureData, int LibV1::Spikecount(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { - size_t spikecount_value; - try { // handle empty peak_indices - const auto& intFeatures = getFeatures(IntFeatureData, {"peak_indices"}); - spikecount_value = intFeatures.at("peak_indices").size(); - } catch (const EmptyFeatureError& e) { - spikecount_value = 0; - } + size_t spikecount_value = getFeature(IntFeatureData, {"peak_indices"}).size(); vector spikecount(1, spikecount_value); setVec(IntFeatureData, StringData, "Spikecount", spikecount); return spikecount_value; diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index a724a9ba..6b4cb5b8 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -1739,30 +1739,20 @@ int LibV5::maximum_voltage_from_voltagebase(mapStr2intVec& IntFeatureData, return 1; } -struct InInterval { - InInterval(double lower, double upper) : lower(lower), upper(upper) {} - bool operator()(double value) { - return ((value >= lower) && (value <= upper)); - } - - private: - double lower, upper; -}; - int LibV5::Spikecount_stimint(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { const auto& doubleFeatures = getFeatures(DoubleFeatureData, {"stim_start", "stim_end", "peak_time"}); - // Get the number of peaks between stim start and end int spikecount_stimint_value = - count_if(doubleFeatures.at("peak_time").begin(), - doubleFeatures.at("peak_time").end(), - InInterval(doubleFeatures.at("stim_start")[0], - doubleFeatures.at("stim_end")[0])); + count_if(doubleFeatures.at("peak_time").begin(), doubleFeatures.at("peak_time").end(), + [&](double time) { + return time >= doubleFeatures.at("stim_start")[0] && + time <= doubleFeatures.at("stim_end")[0]; + }); - vector spikecount_stimint(1, spikecount_stimint_value); + vector spikecount_stimint{spikecount_stimint_value}; setVec(IntFeatureData, StringData, "Spikecount_stimint", spikecount_stimint); return 1; @@ -1784,15 +1774,10 @@ static int __peak_indices(double threshold, const vector& V, dnVec.push_back(i); } } - if (dnVec.size() == 0) { - GErrorStr += - "\nVoltage never goes below or above threshold in spike detection.\n"; - return 0; - } - if (upVec.size() == 0) { - GErrorStr += "\nVoltage never goes above threshold in spike detection.\n"; - return 0; - } + if (dnVec.size() == 0) + throw FeatureComputationError("Voltage never goes below or above threshold in spike detection."); + if (upVec.size() == 0) + throw FeatureComputationError("Voltage never goes above threshold in spike detection."); // case where voltage starts above threshold: remove 1st dnVec while (dnVec.size() > 0 && dnVec[0] < upVec[0]) { @@ -1854,7 +1839,7 @@ int LibV5::peak_indices(mapStr2intVec& IntFeatureData, doubleFeatures.at("T"), PeakIndex, strict_stiminterval, doubleFeatures.at("stim_start")[0], doubleFeatures.at("stim_end")[0]); - if (retVal >= 0) { + if (retVal > 0) { setVec(IntFeatureData, StringData, "peak_indices", PeakIndex); } return retVal; diff --git a/efel/pyfeatures/pyfeatures.py b/efel/pyfeatures/pyfeatures.py index f3d41d2f..502510a3 100644 --- a/efel/pyfeatures/pyfeatures.py +++ b/efel/pyfeatures/pyfeatures.py @@ -72,6 +72,8 @@ def impedance(): holding_current = _get_cpp_feature("current_base") normalized_current = current_trace - holding_current spike_count = _get_cpp_feature("Spikecount") + if spike_count is None: + spike_count = 0 if spike_count < 1: # if there is no spikes in ZAP fft_volt = numpy.fft.fft(normalized_voltage) fft_cur = numpy.fft.fft(normalized_current) diff --git a/tests/test_basic.py b/tests/test_basic.py index ebc95042..e6025fa5 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1638,8 +1638,8 @@ def test_spikecount2(): [trace], features) - spikecount = feature_values[0]['Spikecount'][0] - assert spikecount == 0 + spikecount = feature_values[0]['Spikecount'] + assert spikecount is None def test_min_voltage_between_spikes1(): From 5784c066e2cd14dd7a5c83c80369d72f7854e918 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 19 Dec 2023 11:09:19 +0100 Subject: [PATCH 60/85] add test calling all features on constant trace --- tests/test_allfeatures.py | 45 ++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index 6c006fd2..dfa38a4d 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -28,10 +28,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ +import json import os import warnings -# pylint: disable=R0914 +import numpy as np + +import efel testdata_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'testdata', @@ -41,7 +44,6 @@ def get_allfeature_values(): """Get back all the feature names and value""" - import efel import numpy efel.reset() @@ -127,12 +129,10 @@ def test_allfeatures(): feature_values = get_allfeature_values() - import json test_data_path = os.path.join(testdata_dir, 'expectedresults.json') with open(test_data_path, 'r') as expected_json: expected_results = json.load(expected_json) - import numpy assert set(feature_values.keys()) == set(expected_results.keys()) failed_feature = False for feature_name, feature_value in feature_values.items(): @@ -145,7 +145,7 @@ def test_allfeatures(): equal = (expected_value is None) else: equal = (len(feature_value) == len(expected_value)) \ - and numpy.allclose(feature_value, expected_value) + and np.allclose(feature_value, expected_value) if not equal: print("Difference in feature %s: value=%s expected=%s" % @@ -153,3 +153,38 @@ def test_allfeatures(): failed_feature = True assert not failed_feature + + +def test_allfeatures_on_constant_voltage(): + """Call all features on constant voltage input.""" + time = np.linspace(0, 999, 1000) + voltage = np.full(1000, -80.0) + + efel.reset() + traces = [{'T': time, 'V': voltage, 'stim_start': [100], 'stim_end': [999]}] + all_featurenames = efel.getFeatureNames() + feature_values = efel.getFeatureValues(traces, all_featurenames)[0] + assert all(feature_values["voltage"] == -80.0) + # Assert that each element in time is greater than or equal to the previous element + assert np.all(feature_values["time"][1:] >= feature_values["time"][:-1]) + + # Assert for array fields to be non-empty arrays + # If you add a new feature in the future that results in an array, add here + array_fields = [ + "minimum_voltage", "maximum_voltage", "maximum_voltage_from_voltagebase", + "sag_amplitude", "voltage_after_stim", "steady_state_hyper", + "steady_state_voltage", "steady_state_voltage_stimend", + "voltage_deflection", "voltage_deflection_begin", "voltage_deflection_vb_ssse", + "depol_block", "depol_block_bool", "voltage_base" + ] + + for field in array_fields: + if field in feature_values: + assert isinstance(feature_values[field], np.ndarray) + assert len(feature_values[field]) > 0 + + # Assert the rest of the fields are None + excluded_fields = array_fields + ["voltage", "time"] + for key in feature_values: + if key not in excluded_fields: + assert feature_values[key] is None, f"Field {key} is not None" From c101450e68fb89dddbf017d3aa6459b32af80455 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 19 Dec 2023 11:52:02 +0100 Subject: [PATCH 61/85] remove re imported import in test --- tests/test_allfeatures.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index dfa38a4d..423d4969 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -43,14 +43,12 @@ def get_allfeature_values(): """Get back all the feature names and value""" - - import numpy efel.reset() all_featurenames = efel.getFeatureNames() def load_data(filename): - data = numpy.loadtxt(os.path.join(testdata_dir, filename)) + data = np.loadtxt(os.path.join(testdata_dir, filename)) return data[:, 0], data[:, 1] soma_time, soma_voltage = load_data('testdata.txt') From 267220d0aba38f2064e927568d6711178da44f87 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 19 Dec 2023 16:54:04 +0100 Subject: [PATCH 62/85] impute Spikecount missing val to 0.0 in GranuleCellDeap1.ipynb --- examples/deap/GranuleCell1/GranuleCellDeap1.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb b/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb index e373adcc..d94d7292 100644 --- a/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb +++ b/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb @@ -110,7 +110,8 @@ " \n", " times.append(time)\n", " voltages.append(voltage)\n", - " \n", + "\n", + " feature_values[0][\"Spikecount\"] = 0.0 # replace None with 0.0 \n", " return feature_values, times, voltages\n", "\n", "orig_features, orig_times, orig_voltages = get_features(orig_conductances)" From 9e9286f1b9740d44ee5a91aedd3701b79d134d4c Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 21 Dec 2023 21:33:58 +0100 Subject: [PATCH 63/85] remove unnecessary variable --- efel/cppcore/cfeature.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 71edf28b..982f7849 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -257,8 +257,7 @@ int cFeature::calc_features(const std::string& name) { bool last_failed = false; - for (const auto& pfptrstring : lookup_it->second) { - feature_function function = pfptrstring; + for (const feature_function& function : lookup_it->second) { setFeatureString("params", ""); if (function(mapIntData, mapDoubleData, mapStrData) < 0) { From 241a2d768aeba113442ed1e78130b9c0319cddab Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 21 Dec 2023 21:47:53 +0100 Subject: [PATCH 64/85] move Spikecount implementation to Python --- efel/DependencyV5.txt | 3 +-- efel/cppcore/FillFptrTable.cpp | 1 - efel/cppcore/LibV1.cpp | 11 --------- efel/cppcore/LibV1.h | 2 -- efel/cppcore/cfeature.cpp | 1 - efel/pyfeatures/pyfeatures.py | 23 +++++++++++++++---- .../deap/GranuleCell1/GranuleCellDeap1.ipynb | 3 +-- setup.py | 2 +- tests/DependencyV5_LibV5peakindices.txt | 1 - tests/test_allfeatures.py | 2 +- tests/test_basic.py | 6 ++--- 11 files changed, 25 insertions(+), 30 deletions(-) diff --git a/efel/DependencyV5.txt b/efel/DependencyV5.txt index 91ac3977..51da6b7f 100644 --- a/efel/DependencyV5.txt +++ b/efel/DependencyV5.txt @@ -28,8 +28,7 @@ LibV1:maximum_voltage #LibV1:interpolate LibV1:minimum_voltage #LibV1:interpolate LibV1:steady_state_voltage #LibV1:interpolate LibV3:depolarized_base #LibV5:AP_end_indices #LibV5:AP_begin_indices #LibV1:interpolate -LibV1:ISI_CV #LibV1:ISI_values #LibV1:interpolate -LibV1:Spikecount #LibV5:peak_indices #LibV1:interpolate +LibV1:ISI_CV #LibV1:ISI_values #LibV1:interpolate LibV5:Spikecount_stimint #LibV1:peak_time #LibV1:interpolate LibV1:AHP_depth #LibV5:voltage_base #LibV5:min_AHP_values #LibV1:interpolate LibV1:AHP_depth_slow #LibV5:voltage_base #LibV1:AHP_depth_abs_slow #LibV1:interpolate diff --git a/efel/cppcore/FillFptrTable.cpp b/efel/cppcore/FillFptrTable.cpp index 1889759c..d1293a3c 100644 --- a/efel/cppcore/FillFptrTable.cpp +++ b/efel/cppcore/FillFptrTable.cpp @@ -48,7 +48,6 @@ int FillFptrTable() { FptrTableV1["ISI_CV"] = &LibV1::ISI_CV; FptrTableV1["AHP_depth_abs_slow"] = &LibV1::AHP_depth_abs_slow; FptrTableV1["AHP_slow_time"] = &LibV1::AHP_slow_time; - FptrTableV1["Spikecount"] = &LibV1::Spikecount; FptrTableV1["AHP_depth"] = &LibV1::AHP_depth; FptrTableV1["AHP_depth_slow"] = &LibV1::AHP_depth_slow; FptrTableV1["burst_number"] = &LibV1::burst_number; diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index 2202e24b..75cd23a1 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -76,17 +76,6 @@ int LibV1::interpolate(mapStr2intVec& IntFeatureData, return 1; } -// *** Spikecount *** -int LibV1::Spikecount(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - size_t spikecount_value = getFeature(IntFeatureData, {"peak_indices"}).size(); - vector spikecount(1, spikecount_value); - setVec(IntFeatureData, StringData, "Spikecount", spikecount); - return spikecount_value; -} -// end of Spikecount - int LibV1::ISI_values(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData) { diff --git a/efel/cppcore/LibV1.h b/efel/cppcore/LibV1.h index 9ed20207..769e245b 100644 --- a/efel/cppcore/LibV1.h +++ b/efel/cppcore/LibV1.h @@ -116,8 +116,6 @@ int AHP_depth_abs_slow(mapStr2intVec& IntFeatureData, mapStr2Str& StringData); int AHP_slow_time(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int Spikecount(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); int AHP_depth(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); int AHP_depth_slow(mapStr2intVec& IntFeatureData, diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 982f7849..5c4f4924 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -128,7 +128,6 @@ void cFeature::fillfeaturetypes() { featuretypes["ISI_CV"] = "double"; featuretypes["AHP_depth_abs_slow"] = "double"; featuretypes["AHP_slow_time"] = "double"; - featuretypes["Spikecount"] = "int"; featuretypes["Spikecount_stimint"] = "int"; featuretypes["AHP_depth"] = "double"; featuretypes["AHP_depth_slow"] = "double"; diff --git a/efel/pyfeatures/pyfeatures.py b/efel/pyfeatures/pyfeatures.py index 502510a3..1b9d4469 100644 --- a/efel/pyfeatures/pyfeatures.py +++ b/efel/pyfeatures/pyfeatures.py @@ -25,6 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ +from typing_extensions import deprecated import numpy import efel.cppcore @@ -41,6 +42,7 @@ 'initburst_sahp_ssse', 'depol_block', 'depol_block_bool', + 'Spikecount', 'spikes_per_burst', 'spikes_per_burst_diff', 'spikes_in_burst1_burst2_diff', @@ -59,6 +61,19 @@ def time(): return _get_cpp_feature("time") +@deprecated("Use spike_count instead.") +def Spikecount() -> numpy.ndarray: + return spike_count() + + +def spike_count() -> numpy.ndarray: + """Get spike count.""" + peak_indices = _get_cpp_feature("peak_indices") + if peak_indices is None: + return numpy.array([0]) + return numpy.array([peak_indices.size]) + + def impedance(): from scipy.ndimage.filters import gaussian_filter1d @@ -71,10 +86,10 @@ def impedance(): if current_trace is not None: holding_current = _get_cpp_feature("current_base") normalized_current = current_trace - holding_current - spike_count = _get_cpp_feature("Spikecount") - if spike_count is None: - spike_count = 0 - if spike_count < 1: # if there is no spikes in ZAP + n_spikes = spike_count() + if n_spikes is None: + n_spikes = 0 + if n_spikes < 1: # if there is no spikes in ZAP fft_volt = numpy.fft.fft(normalized_voltage) fft_cur = numpy.fft.fft(normalized_current) if any(fft_cur) == 0: diff --git a/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb b/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb index d94d7292..b7cf0d02 100644 --- a/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb +++ b/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb @@ -111,7 +111,6 @@ " times.append(time)\n", " voltages.append(voltage)\n", "\n", - " feature_values[0][\"Spikecount\"] = 0.0 # replace None with 0.0 \n", " return feature_values, times, voltages\n", "\n", "orig_features, orig_times, orig_voltages = get_features(orig_conductances)" @@ -406,7 +405,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.4" + "version": "3.10.12" } }, "nbformat": 4, diff --git a/setup.py b/setup.py index 0c5b47a4..96b978c7 100644 --- a/setup.py +++ b/setup.py @@ -78,7 +78,7 @@ name="efel", version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass(), - install_requires=['numpy>=1.6', 'neo>=0.5.2'], + install_requires=['numpy>=1.6', 'neo>=0.5.2', 'typing-extensions>=4.8.0'], packages=['efel', 'efel.pyfeatures', 'efel.units'], author="BlueBrain Project, EPFL", maintainer="Werner Van Geit", diff --git a/tests/DependencyV5_LibV5peakindices.txt b/tests/DependencyV5_LibV5peakindices.txt index 7b173dce..0b011fb7 100644 --- a/tests/DependencyV5_LibV5peakindices.txt +++ b/tests/DependencyV5_LibV5peakindices.txt @@ -27,7 +27,6 @@ LibV1:interpolate LibV1:steady_state_voltage LibV3:depolarized_base LibV1:ISI_CV #LibV1:ISI_values -LibV1:Spikecount #LibV5:peak_indices LibV1:AHP_depth #LibV5:voltage_base #LibV5:min_AHP_values LibV2:AP_rise_indices #LibV5:peak_indices #LibV5:AP_begin_indices LibV2:AP_end_indices #LibV5:peak_indices diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index 423d4969..ca4a5b3e 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -173,7 +173,7 @@ def test_allfeatures_on_constant_voltage(): "sag_amplitude", "voltage_after_stim", "steady_state_hyper", "steady_state_voltage", "steady_state_voltage_stimend", "voltage_deflection", "voltage_deflection_begin", "voltage_deflection_vb_ssse", - "depol_block", "depol_block_bool", "voltage_base" + "depol_block", "depol_block_bool", "voltage_base", "Spikecount" ] for field in array_fields: diff --git a/tests/test_basic.py b/tests/test_basic.py index e6025fa5..5f17ed2e 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -626,7 +626,6 @@ def test_strict_stiminterval(): peak_indices = feature_values[0]['peak_indices'] peak_time = feature_values[0]['peak_time'] spikecount = feature_values[0]['Spikecount'] - assert len(peak_indices) == n_of_spikes assert len(peak_time) == n_of_spikes assert spikecount == n_of_spikes @@ -1132,7 +1131,6 @@ def test_getDistance_trace_check(): trace['stim_start'] = [10] trace['stim_end'] = [70] traces.append(trace) - numpy.testing.assert_allclose( efel.getDistance(trace, 'Spikecount', 0, 1), 3.0 ) @@ -1638,8 +1636,8 @@ def test_spikecount2(): [trace], features) - spikecount = feature_values[0]['Spikecount'] - assert spikecount is None + spikecount = feature_values[0]['Spikecount'][0] + assert spikecount == 0 def test_min_voltage_between_spikes1(): From 46007d22c3619da3ece2ec00718109d8a74cfba7 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 21 Dec 2023 21:59:51 +0100 Subject: [PATCH 65/85] change doc of Spikecount as Python efeature --- docs/source/eFeatures.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/eFeatures.rst b/docs/source/eFeatures.rst index de9295cc..9c603cd6 100644 --- a/docs/source/eFeatures.rst +++ b/docs/source/eFeatures.rst @@ -150,8 +150,8 @@ time from stimulus start to last spike else: time_to_last_spike = 0 -`LibV1`_ : Spikecount -~~~~~~~~~~~~~~~~~~~~~ +`Python efeature`_ : Spikecount +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ number of spikes in the trace, including outside of stimulus interval From 818e3a17d072dae9615b480bb3a7b17adee7a8a1 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 21 Dec 2023 22:13:56 +0100 Subject: [PATCH 66/85] move Spikecount_stimint to Python --- docs/source/eFeatures.rst | 4 ++-- efel/DependencyV5.txt | 1 - efel/cppcore/FillFptrTable.cpp | 1 - efel/cppcore/LibV5.cpp | 19 ------------------- efel/cppcore/LibV5.h | 3 --- efel/cppcore/cfeature.cpp | 1 - efel/pyfeatures/pyfeatures.py | 18 ++++++++++++++++++ tests/test_allfeatures.py | 3 ++- 8 files changed, 22 insertions(+), 28 deletions(-) diff --git a/docs/source/eFeatures.rst b/docs/source/eFeatures.rst index 9c603cd6..e9d1f724 100644 --- a/docs/source/eFeatures.rst +++ b/docs/source/eFeatures.rst @@ -161,8 +161,8 @@ number of spikes in the trace, including outside of stimulus interval Spikecount = len(peak_indices) -`LibV5`_ : Spikecount_stimint -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`Python efeature`_ : Spikecount_stimint +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ number of spikes inside the stimulus interval diff --git a/efel/DependencyV5.txt b/efel/DependencyV5.txt index 51da6b7f..66884172 100644 --- a/efel/DependencyV5.txt +++ b/efel/DependencyV5.txt @@ -29,7 +29,6 @@ LibV1:minimum_voltage #LibV1:interpolate LibV1:steady_state_voltage #LibV1:interpolate LibV3:depolarized_base #LibV5:AP_end_indices #LibV5:AP_begin_indices #LibV1:interpolate LibV1:ISI_CV #LibV1:ISI_values #LibV1:interpolate -LibV5:Spikecount_stimint #LibV1:peak_time #LibV1:interpolate LibV1:AHP_depth #LibV5:voltage_base #LibV5:min_AHP_values #LibV1:interpolate LibV1:AHP_depth_slow #LibV5:voltage_base #LibV1:AHP_depth_abs_slow #LibV1:interpolate LibV2:AP_rise_indices #LibV5:peak_indices #LibV5:AP_begin_indices #LibV1:interpolate diff --git a/efel/cppcore/FillFptrTable.cpp b/efel/cppcore/FillFptrTable.cpp index d1293a3c..92dcfed0 100644 --- a/efel/cppcore/FillFptrTable.cpp +++ b/efel/cppcore/FillFptrTable.cpp @@ -195,7 +195,6 @@ int FillFptrTable() { &LibV5::voltage_deflection_vb_ssse; FptrTableV5["maximum_voltage_from_voltagebase"] = &LibV5::maximum_voltage_from_voltagebase; - FptrTableV5["Spikecount_stimint"] = &LibV5::Spikecount_stimint; FptrTableV5["peak_indices"] = &LibV5::peak_indices; FptrTableV5["sag_amplitude"] = &LibV5::sag_amplitude; diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index 6b4cb5b8..fad1233a 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -1739,25 +1739,6 @@ int LibV5::maximum_voltage_from_voltagebase(mapStr2intVec& IntFeatureData, return 1; } -int LibV5::Spikecount_stimint(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto& doubleFeatures = - getFeatures(DoubleFeatureData, {"stim_start", "stim_end", "peak_time"}); - // Get the number of peaks between stim start and end - int spikecount_stimint_value = - count_if(doubleFeatures.at("peak_time").begin(), doubleFeatures.at("peak_time").end(), - [&](double time) { - return time >= doubleFeatures.at("stim_start")[0] && - time <= doubleFeatures.at("stim_end")[0]; - }); - - vector spikecount_stimint{spikecount_stimint_value}; - setVec(IntFeatureData, StringData, "Spikecount_stimint", spikecount_stimint); - - return 1; -} - static int __peak_indices(double threshold, const vector& V, const vector& t, vector& PeakIndex, bool strict_stiminterval, double stim_start, diff --git a/efel/cppcore/LibV5.h b/efel/cppcore/LibV5.h index e2aff3cb..ba31646d 100644 --- a/efel/cppcore/LibV5.h +++ b/efel/cppcore/LibV5.h @@ -211,9 +211,6 @@ int ohmic_input_resistance_vb_ssse(mapStr2intVec& IntFeatureData, int maximum_voltage_from_voltagebase(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int Spikecount_stimint(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); int peak_indices(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 5c4f4924..785f8375 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -128,7 +128,6 @@ void cFeature::fillfeaturetypes() { featuretypes["ISI_CV"] = "double"; featuretypes["AHP_depth_abs_slow"] = "double"; featuretypes["AHP_slow_time"] = "double"; - featuretypes["Spikecount_stimint"] = "int"; featuretypes["AHP_depth"] = "double"; featuretypes["AHP_depth_slow"] = "double"; featuretypes["amp_drop_first_second"] = "double"; diff --git a/efel/pyfeatures/pyfeatures.py b/efel/pyfeatures/pyfeatures.py index 1b9d4469..7d6a56e8 100644 --- a/efel/pyfeatures/pyfeatures.py +++ b/efel/pyfeatures/pyfeatures.py @@ -43,6 +43,7 @@ 'depol_block', 'depol_block_bool', 'Spikecount', + 'Spikecount_stimint', 'spikes_per_burst', 'spikes_per_burst_diff', 'spikes_in_burst1_burst2_diff', @@ -74,6 +75,23 @@ def spike_count() -> numpy.ndarray: return numpy.array([peak_indices.size]) +@deprecated("Use spike_count_stimint instead.") +def Spikecount_stimint() -> numpy.ndarray: + return spike_count_stimint() + + +def spike_count_stimint() -> numpy.ndarray: + """Get spike count within stimulus interval.""" + stim_start = _get_cpp_data("stim_start") + stim_end = _get_cpp_data("stim_end") + peak_times = _get_cpp_feature("peak_time") + if peak_times is None: + return numpy.array([0]) + + res = sum(1 for time in peak_times if stim_start <= time <= stim_end) + return numpy.array([res]) + + def impedance(): from scipy.ndimage.filters import gaussian_filter1d diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index ca4a5b3e..72c53db2 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -173,7 +173,8 @@ def test_allfeatures_on_constant_voltage(): "sag_amplitude", "voltage_after_stim", "steady_state_hyper", "steady_state_voltage", "steady_state_voltage_stimend", "voltage_deflection", "voltage_deflection_begin", "voltage_deflection_vb_ssse", - "depol_block", "depol_block_bool", "voltage_base", "Spikecount" + "depol_block", "depol_block_bool", "voltage_base", "Spikecount", + "Spikecount_stimint" ] for field in array_fields: From f778c6acea3d8cb0bd46a7c7344026fba7f32324 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 4 Jan 2024 13:56:23 +0100 Subject: [PATCH 67/85] add validation module with check_ais_initiation --- efel/validation.py | 24 ++++++++++++++ tests/test_validation.py | 67 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 efel/validation.py create mode 100644 tests/test_validation.py diff --git a/efel/validation.py b/efel/validation.py new file mode 100644 index 00000000..6b5dd1b5 --- /dev/null +++ b/efel/validation.py @@ -0,0 +1,24 @@ +"""Contains scientific validation methods on input signals.""" +import efel + + +def check_ais_initiation(soma_trace: dict, ais_trace: dict) -> bool: + """Checks the initiation of action potential in AIS wrt. soma.""" + f_values = efel.getFeatureValues([soma_trace, ais_trace], ["AP_begin_time"]) + soma_ap_begin_time = f_values[0]["AP_begin_time"] + ais_ap_begin_time = f_values[1]["AP_begin_time"] + + if soma_ap_begin_time is None or ais_ap_begin_time is None: + raise ValueError("AP_begin_time feature is not computed") + + if len(soma_ap_begin_time) != len(ais_ap_begin_time): + raise ValueError("Number of APs in soma and AIS do not match") + + # Checking if no spike in the soma starts earlier than in the AIS + for soma_time, ais_time in zip(soma_ap_begin_time, ais_ap_begin_time): + if soma_time < ais_time: + raise ValueError( + "There is a spike that initiates in the soma before the axon" + ) + + return True diff --git a/tests/test_validation.py b/tests/test_validation.py new file mode 100644 index 00000000..146efafb --- /dev/null +++ b/tests/test_validation.py @@ -0,0 +1,67 @@ +"""Unit tests for the validation module.""" +from pathlib import Path + +import numpy as np +import pytest + +import efel +from efel.io import load_ascii_input +from efel.validation import check_ais_initiation + + +testdata_dir = Path(__file__).parent / "testdata" +meanfrequency1_url = testdata_dir / "basic" / "mean_frequency_1.txt" + + +def test_check_ais_initiation(): + """Unit test for check_ais_initiation.""" + efel.reset() + stim_start, stim_end = 1.0, 2.0 # dummy values not used in this feature + + time, voltage = load_ascii_input(meanfrequency1_url) + soma_trace = ais_trace = { + "T": time, + "V": voltage, + "stim_start": [stim_start], + "stim_end": [stim_end], + } + assert check_ais_initiation(soma_trace, ais_trace) + + # test edge cases + + # 0. no spikes + ais_trace = { + "T": time[35000:], # slice to remove spikes + "V": voltage[35000:], + "stim_start": [stim_start], + "stim_end": [stim_end], + } + + with pytest.raises(ValueError) as excinfo: + check_ais_initiation(soma_trace, ais_trace) + assert "AP_begin_time feature is not computed" in str(excinfo.value) + + # 1. different number of spikes + ais_trace = { + "T": time[15000:], # slice to remove spikes + "V": voltage[15000:], + "stim_start": [stim_start], + "stim_end": [stim_end], + } + with pytest.raises(ValueError) as excinfo: + check_ais_initiation(soma_trace, ais_trace) + assert "Number of APs in soma and AIS do not match" in str(excinfo.value) + + # 2. spike in soma starts earlier than in AIS + ais_trace = { + "T": time, + "V": np.roll(voltage, 500), # shift the spike by 500 samples, + "stim_start": [stim_start], + "stim_end": [stim_end], + } + + with pytest.raises(ValueError) as excinfo: + check_ais_initiation(soma_trace, ais_trace) + assert "There is a spike that initiates in the soma before the axon" in str( + excinfo.value + ) From eebc16e60e191f0fa49136444692511c017207d5 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 4 Jan 2024 21:05:42 +0100 Subject: [PATCH 68/85] add bpap_attenuation as a multitrace feature --- efel/pyfeatures/multitrace.py | 24 +++++++++++++++++++++ tests/test_multitrace.py | 39 +++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 efel/pyfeatures/multitrace.py create mode 100644 tests/test_multitrace.py diff --git a/efel/pyfeatures/multitrace.py b/efel/pyfeatures/multitrace.py new file mode 100644 index 00000000..72919285 --- /dev/null +++ b/efel/pyfeatures/multitrace.py @@ -0,0 +1,24 @@ +"""Contains the features that are computed using multiple traces.""" + + +import numpy as np + +import efel + + +def bpap_attenuation(soma_trace: dict, dendrite_trace: dict) -> float: + """Computes the attenuation of backpropagating action potential. + + Backpropagating action potential is the action potential that is initiated + in the soma and propagates to the dendrite. The attenuation is the ratio + of the amplitude of the action potential in the soma and the dendrite. + The attenuation is computed by first subtracting the resting potential + from the voltage traces. + """ + f_values = efel.getFeatureValues([soma_trace, dendrite_trace], ["voltage_base"]) + vb_soma = f_values[0]["voltage_base"][0] + vb_dend = f_values[1]["voltage_base"][0] + v_soma = soma_trace["V"] + v_dend = dendrite_trace["V"] + res = (np.max(v_soma) - vb_soma) / (np.max(v_dend) - vb_dend) + return res diff --git a/tests/test_multitrace.py b/tests/test_multitrace.py new file mode 100644 index 00000000..3f58f5d3 --- /dev/null +++ b/tests/test_multitrace.py @@ -0,0 +1,39 @@ +"""Unit tests for the multitrace module.""" + +from pathlib import Path +import efel +from efel.io import load_ascii_input +from efel.pyfeatures.multitrace import bpap_attenuation + + +testdata_dir = Path(__file__).parent / "testdata" +meanfrequency1_url = testdata_dir / "basic" / "mean_frequency_1.txt" + + +def test_bpap_attenuation(): + efel.reset() + stim_start, stim_end = 1.0, 2.0 # dummy values not used in this feature + + time, voltage = load_ascii_input(meanfrequency1_url) + soma_trace = dendrite_trace = { + "T": time, + "V": voltage, + "stim_start": [stim_start], + "stim_end": [stim_end], + } + assert bpap_attenuation(soma_trace, dendrite_trace) == 1.0 + + # test voltage base subtraction + soma_trace = { + "T": time, + "V": voltage, + "stim_start": [stim_start], + "stim_end": [stim_end], + } + # subtract 10 mv from V of soma_trace + soma_trace["V"] = soma_trace["V"] - 10 + assert bpap_attenuation(soma_trace, dendrite_trace) == 1.0 + + # divide by 2 + soma_trace["V"] = voltage / 2 + assert bpap_attenuation(soma_trace, dendrite_trace) == 0.5 From 31b7212974a7ad9785b45947546459f3ad4ec63a Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 5 Jan 2024 11:57:46 +0100 Subject: [PATCH 69/85] move burst_number and strict_burst_number to Python --- docs/source/eFeatures.rst | 8 ++++---- efel/DependencyV5.txt | 2 -- efel/cppcore/FillFptrTable.cpp | 2 -- efel/cppcore/LibV1.cpp | 11 ----------- efel/cppcore/LibV1.h | 2 -- efel/cppcore/LibV5.cpp | 11 ----------- efel/cppcore/LibV5.h | 3 --- efel/cppcore/cfeature.cpp | 2 -- efel/pyfeatures/pyfeatures.py | 25 +++++++++++++++++++++++++ tests/DependencyV5_LibV5peakindices.txt | 1 - tests/test_allfeatures.py | 2 +- tests/test_basic.py | 4 ++-- 12 files changed, 32 insertions(+), 41 deletions(-) diff --git a/docs/source/eFeatures.rst b/docs/source/eFeatures.rst index e9d1f724..6fd9f421 100644 --- a/docs/source/eFeatures.rst +++ b/docs/source/eFeatures.rst @@ -402,8 +402,8 @@ The burst detection can be fine-tuned by changing the setting strict_burst_facto ) ) -`LibV1`_ : burst_number -~~~~~~~~~~~~~~~~~~~~~~~ +`Python efeature`_ : burst_number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The number of bursts @@ -413,8 +413,8 @@ The number of bursts burst_number = len(burst_mean_freq) -`LibV5`_ : strict_burst_number -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`Python efeature`_ : strict_burst_number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The number of bursts diff --git a/efel/DependencyV5.txt b/efel/DependencyV5.txt index 66884172..e9f89c6e 100644 --- a/efel/DependencyV5.txt +++ b/efel/DependencyV5.txt @@ -13,7 +13,6 @@ LibV1:adaptation_index2 #LibV1:peak_time #LibV1:interpolate LibV1:spike_width2 #LibV5:min_AHP_indices #LibV1:interpolate LibV1:AP_width #LibV5:peak_indices #LibV5:min_AHP_indices #LibV1:interpolate LibV1:burst_mean_freq #LibV1:burst_ISI_indices #LibV1:peak_time #LibV1:interpolate -LibV1:burst_number #LibV1:burst_mean_freq #LibV1:interpolate LibV1:interburst_voltage #LibV1:burst_ISI_indices #LibV1:interpolate LibV1:AP_height #LibV1:peak_voltage #LibV1:interpolate LibV1:AP_amplitude #LibV5:AP_begin_indices #LibV1:peak_voltage #LibV1:peak_time #LibV1:interpolate @@ -125,7 +124,6 @@ LibV5:AP_width_between_threshold #LibV5:min_between_peaks_indices #LibV1:inte LibV5:burst_begin_indices #LibV5:all_ISI_values #LibV1:interpolate LibV5:burst_end_indices #LibV5:burst_begin_indices #LibV1:interpolate LibV5:strict_burst_mean_freq #LibV1:peak_time #LibV5:burst_begin_indices #LibV5:burst_end_indices #LibV1:interpolate -LibV5:strict_burst_number #LibV5:strict_burst_mean_freq #LibV1:interpolate LibV5:strict_interburst_voltage #LibV5:peak_indices #LibV5:burst_begin_indices #LibV1:interpolate LibV5:ADP_peak_indices #LibV5:min_AHP_indices #LibV5:min_between_peaks_indices #LibV1:interpolate LibV5:ADP_peak_values #LibV5:ADP_peak_indices #LibV1:interpolate diff --git a/efel/cppcore/FillFptrTable.cpp b/efel/cppcore/FillFptrTable.cpp index 92dcfed0..f9609934 100644 --- a/efel/cppcore/FillFptrTable.cpp +++ b/efel/cppcore/FillFptrTable.cpp @@ -50,7 +50,6 @@ int FillFptrTable() { FptrTableV1["AHP_slow_time"] = &LibV1::AHP_slow_time; FptrTableV1["AHP_depth"] = &LibV1::AHP_depth; FptrTableV1["AHP_depth_slow"] = &LibV1::AHP_depth_slow; - FptrTableV1["burst_number"] = &LibV1::burst_number; FptrTableV1["AP_amplitude_diff"] = &LibV1::AP_amplitude_diff; FptrTableV1["AHP_depth_diff"] = &LibV1::AHP_depth_diff; @@ -210,7 +209,6 @@ int FillFptrTable() { FptrTableV5["burst_begin_indices"] = &LibV5::burst_begin_indices; FptrTableV5["burst_end_indices"] = &LibV5::burst_end_indices; FptrTableV5["strict_burst_mean_freq"] = &LibV5::strict_burst_mean_freq; - FptrTableV5["strict_burst_number"] = &LibV5::strict_burst_number; FptrTableV5["strict_interburst_voltage"] = &LibV5::strict_interburst_voltage; FptrTableV5["ADP_peak_indices"] = &LibV5::ADP_peak_indices; diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index 75cd23a1..d14f2ff7 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -405,17 +405,6 @@ int LibV1::burst_mean_freq(mapStr2intVec& IntFeatureData, return retVal; } -int LibV1::burst_number(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto& doubleFeatures = - getFeatures(DoubleFeatureData, {"burst_mean_freq"}); - vector BurstNum; - BurstNum.push_back(doubleFeatures.at("burst_mean_freq").size()); - setVec(IntFeatureData, StringData, "burst_number", BurstNum); - return BurstNum.size(); -} - // reminder: first ISI value is ignored in burst_ISI_indices if IgnoreFirstISI=1 static int __interburst_voltage(const vector& BurstIndex, const vector& PeakIndex, diff --git a/efel/cppcore/LibV1.h b/efel/cppcore/LibV1.h index 769e245b..e14e4622 100644 --- a/efel/cppcore/LibV1.h +++ b/efel/cppcore/LibV1.h @@ -121,8 +121,6 @@ int AHP_depth(mapStr2intVec& IntFeatureData, int AHP_depth_slow(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int burst_number(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); int AP_amplitude_diff(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); diff --git a/efel/cppcore/LibV5.cpp b/efel/cppcore/LibV5.cpp index fad1233a..098d1354 100644 --- a/efel/cppcore/LibV5.cpp +++ b/efel/cppcore/LibV5.cpp @@ -2258,17 +2258,6 @@ int LibV5::strict_burst_mean_freq(mapStr2intVec& IntFeatureData, return retVal; } -int LibV5::strict_burst_number(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto& doubleFeatures = - getFeatures(DoubleFeatureData, {"strict_burst_mean_freq"}); - vector BurstNum; - BurstNum.push_back(doubleFeatures.at("strict_burst_mean_freq").size()); - setVec(IntFeatureData, StringData, "strict_burst_number", BurstNum); - return BurstNum.size(); -} - static int __strict_interburst_voltage(const vector& burst_begin_indices, const vector& PeakIndex, const vector& T, diff --git a/efel/cppcore/LibV5.h b/efel/cppcore/LibV5.h index ba31646d..3556a9c3 100644 --- a/efel/cppcore/LibV5.h +++ b/efel/cppcore/LibV5.h @@ -247,9 +247,6 @@ int burst_end_indices(mapStr2intVec& IntFeatureData, int strict_burst_mean_freq(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int strict_burst_number(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData); int strict_interburst_voltage(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 785f8375..ea0f1661 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -135,7 +135,6 @@ void cFeature::fillfeaturetypes() { featuretypes["amp_drop_second_last"] = "double"; featuretypes["max_amp_difference"] = "double"; featuretypes["depolarized_base"] = "double"; - featuretypes["burst_number"] = "int"; // LibV5 featuretypes["ISI_log_slope"] = "double"; @@ -212,7 +211,6 @@ void cFeature::fillfeaturetypes() { featuretypes["burst_begin_indices"] = "int"; featuretypes["burst_end_indices"] = "int"; featuretypes["strict_burst_mean_freq"] = "double"; - featuretypes["strict_burst_number"] = "int"; featuretypes["strict_interburst_voltage"] = "double"; featuretypes["ADP_peak_indices"] = "int"; diff --git a/efel/pyfeatures/pyfeatures.py b/efel/pyfeatures/pyfeatures.py index 7d6a56e8..bf940457 100644 --- a/efel/pyfeatures/pyfeatures.py +++ b/efel/pyfeatures/pyfeatures.py @@ -49,6 +49,8 @@ 'spikes_in_burst1_burst2_diff', 'spikes_in_burst1_burstlast_diff', 'impedance', + 'burst_number', + 'strict_burst_number' ] @@ -92,6 +94,29 @@ def spike_count_stimint() -> numpy.ndarray: return numpy.array([res]) +def burst_number() -> numpy.ndarray: + """The number of bursts.""" + burst_mean_freq = _get_cpp_feature("burst_mean_freq") + if burst_mean_freq is None: + return numpy.array([0]) + return numpy.array([burst_mean_freq.size]) + + +def strict_burst_number() -> numpy.ndarray: + """Calculate the strict burst number. + + This implementation does not assume that every spike belongs to a burst. + The first spike is ignored by default. This can be changed by setting + ignore_first_ISI to 0. + + The burst detection can be fine-tuned by changing the setting + strict_burst_factor. Default value is 2.0.""" + burst_mean_freq = _get_cpp_feature("strict_burst_mean_freq") + if burst_mean_freq is None: + return numpy.array([0]) + return numpy.array([burst_mean_freq.size]) + + def impedance(): from scipy.ndimage.filters import gaussian_filter1d diff --git a/tests/DependencyV5_LibV5peakindices.txt b/tests/DependencyV5_LibV5peakindices.txt index 0b011fb7..4c69f3fd 100644 --- a/tests/DependencyV5_LibV5peakindices.txt +++ b/tests/DependencyV5_LibV5peakindices.txt @@ -12,7 +12,6 @@ LibV1:adaptation_index2 #LibV1:peak_time LibV1:spike_width2 #LibV5:min_AHP_indices LibV1:AP_width #LibV5:peak_indices #LibV5:min_AHP_indices LibV1:burst_mean_freq #LibV1:burst_ISI_indices #LibV1:peak_time -LibV1:burst_number #LibV1:burst_mean_freq LibV1:interburst_voltage #LibV1:burst_ISI_indices LibV1:AP_height #LibV1:peak_voltage LibV1:AP_amplitude #LibV5:AP_begin_indices #LibV1:peak_voltage diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index 72c53db2..11a81098 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -174,7 +174,7 @@ def test_allfeatures_on_constant_voltage(): "steady_state_voltage", "steady_state_voltage_stimend", "voltage_deflection", "voltage_deflection_begin", "voltage_deflection_vb_ssse", "depol_block", "depol_block_bool", "voltage_base", "Spikecount", - "Spikecount_stimint" + "Spikecount_stimint", "burst_number", "strict_burst_number" ] for field in array_fields: diff --git a/tests/test_basic.py b/tests/test_basic.py index 5f17ed2e..44d398ae 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -201,9 +201,9 @@ def test_failing_int_feature(): feature_value = efel.getFeatureValues( [trace], - ['burst_number'], raise_warnings=False)[0]['burst_number'] + ['burst_number'], raise_warnings=False)[0]['burst_number'][0] - assert feature_value is None + assert feature_value == 0 def test_empty_trace(): From 4c1aae39d2ca7393da3fcc63a5c0f644ec2fb237 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 5 Jan 2024 15:03:26 +0100 Subject: [PATCH 70/85] update impedance, remove spikecount is None check --- efel/pyfeatures/pyfeatures.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/efel/pyfeatures/pyfeatures.py b/efel/pyfeatures/pyfeatures.py index bf940457..0d0c6687 100644 --- a/efel/pyfeatures/pyfeatures.py +++ b/efel/pyfeatures/pyfeatures.py @@ -130,8 +130,6 @@ def impedance(): holding_current = _get_cpp_feature("current_base") normalized_current = current_trace - holding_current n_spikes = spike_count() - if n_spikes is None: - n_spikes = 0 if n_spikes < 1: # if there is no spikes in ZAP fft_volt = numpy.fft.fft(normalized_voltage) fft_cur = numpy.fft.fft(normalized_current) From d2877920e6323a6452a5c4c961106503615f3411 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Fri, 5 Jan 2024 15:25:10 +0100 Subject: [PATCH 71/85] add CHANGELOG.md --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..0a2d6bd1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,21 @@ + +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [5.4.0] - 2024-01 + +### C++ changes +- New C++ function `getFeatures` replaced `getVec`. +- `getFeatures` automatically handles failures & distinguishes empty results from failures. +- Centralized error handling in `getFeatures` shortens the code by removing repetitions. +- C++ features' access is restricted. Read-only references are marked `const`. +- Removed wildcard features from C++ API. Use of Python is encouraged for that purpose. + +### Python changes +- `bpap_attenuation` feature is added to the Python API. +- `Spikecount`, `Spikecount_stimint`, `burst_number` and `strict_burst_number` features migrated to Python from C++. +- `check_ais_initiation` is added to the Python API. From cc4f705be0e06d2fd9b26a365a6dde41f6c8306c Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Mon, 8 Jan 2024 14:46:37 +0100 Subject: [PATCH 72/85] docs: add multitrace and validation modules to API --- docs/source/api.rst | 2 ++ efel/validation.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/api.rst b/docs/source/api.rst index fe30b389..7fbddd3f 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -15,6 +15,8 @@ Submodules api io + pyfeatures.multitrace pyfeatures.pyfeatures units settings + validation diff --git a/efel/validation.py b/efel/validation.py index 6b5dd1b5..467b74b8 100644 --- a/efel/validation.py +++ b/efel/validation.py @@ -3,7 +3,7 @@ def check_ais_initiation(soma_trace: dict, ais_trace: dict) -> bool: - """Checks the initiation of action potential in AIS wrt. soma.""" + """Checks the initiation of action potential in AIS with respect to soma.""" f_values = efel.getFeatureValues([soma_trace, ais_trace], ["AP_begin_time"]) soma_ap_begin_time = f_values[0]["AP_begin_time"] ais_ap_begin_time = f_values[1]["AP_begin_time"] From df224bdcc204d3971e4949016565f0c8bfda1e52 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Mon, 8 Jan 2024 14:54:00 +0100 Subject: [PATCH 73/85] Docs: add name change warnings --- docs/source/eFeatures.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/source/eFeatures.rst b/docs/source/eFeatures.rst index 6fd9f421..ac597f84 100644 --- a/docs/source/eFeatures.rst +++ b/docs/source/eFeatures.rst @@ -161,6 +161,8 @@ number of spikes in the trace, including outside of stimulus interval Spikecount = len(peak_indices) +**Note**: In the future this feature will be called "spike_count". + `Python efeature`_ : Spikecount_stimint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -173,6 +175,8 @@ number of spikes inside the stimulus interval peaktimes_stimint = numpy.where((peak_time >= stim_start) & (peak_time <= stim_end)) Spikecount_stimint = len(peaktimes_stimint) +**Note**: In the future this feature will be called "spike_count_stimint". + `LibV5`_ : number_initial_spikes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 082f2050b354c16a2a834e0059ba2f3e1ec0a321 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 13:29:43 +0100 Subject: [PATCH 74/85] add int/double template instantiations to cfeature --- efel/cppcore/cfeature.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index ea0f1661..9252c473 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -416,3 +416,8 @@ string cFeature::getGError() { GErrorStr.clear(); return error; } + +template int cFeature::getFeature(string strName, vector& vec); +template int cFeature::getFeature(string strName, vector& vec); +template const vector cFeature::getMapData(const string& strName, const map>& mapData); +template const vector cFeature::getMapData(const string& strName, const map>& mapData); From c7a4cc9d927ef291dd4b4ac33b3218b9d82029c4 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 15:10:51 +0100 Subject: [PATCH 75/85] remove getDistance_cpp, use python implementation --- efel/api.py | 58 ----------------------------------- efel/cppcore/cfeature.cpp | 63 --------------------------------------- efel/cppcore/cfeature.h | 2 -- efel/cppcore/cppcore.cpp | 23 -------------- tests/test_cppcore.py | 13 -------- tests/test_pyfeatures.py | 28 +---------------- 6 files changed, 1 insertion(+), 186 deletions(-) diff --git a/efel/api.py b/efel/api.py index 751046bc..673aac24 100644 --- a/efel/api.py +++ b/efel/api.py @@ -209,64 +209,6 @@ def FeatureNameExists(feature_name): return feature_name in getFeatureNames() -def _getDistance_cpp( - trace, - featureName, - mean, - std, - trace_check=None, - error_dist=None): - """Calculate distance value for a list of traces. - - Parameters - ========== - trace : trace dicts - Trace dict that represents one trace. The dict should have the - following keys: 'T', 'V', 'stim_start', 'stim_end' - featureName : string - Name of the the features for which to calculate the distance - mean : float - Mean to calculate the distance from - std : float - Std to scale the distance with - trace_check : float - Let the library check if there are spikes outside of stimulus - interval - error_dist : float - Distance returned when error, default is 250 - - Returns - ======= - distance : float - The absolute number of standard deviation the feature is away - from the mean. In case of anomalous results a value of - 'error_dist' standard deviations is returned. - This can happen if: a feature generates an error, there are - spikes outside of the stimulus interval, the feature returns - a NaN, etc. - """ - - _initialise() - - # Next set time, voltage and the stimulus start and end - for item in list(trace.keys()): - cppcore.setFeatureDouble(item, [x for x in trace[item]]) - - kwargs = {} - - kwargs['feature_name'] = featureName - kwargs['mean'] = mean - kwargs['std'] = std - - if trace_check is not None: - kwargs['trace_check'] = 1 if trace_check else 0 - - if error_dist is not None: - kwargs['error_dist'] = error_dist - - return efel.cppcore.getDistance(**kwargs) - - def _get_feature(featureName, raise_warnings=None): """Get feature value, decide to use python or cpp""" if featureName in pyfeatures.all_pyfeatures: diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index 9252c473..bd598d51 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -339,69 +339,6 @@ int cFeature::setFeatureDouble(string strName, vector& v) { return 1; } -double cFeature::getDistance(string strName, double mean, double std, - bool trace_check, double error_dist) { - vector feature_vec; - vector feature_veci; - string featureType; - int retVal, intFlag; - double dError = 0; - - // Check if a the trace doesn't contain any spikes outside of the stimulus - // interval - if (trace_check) { - retVal = getFeature("trace_check", feature_veci); - if (retVal < 0) { - return error_dist; - } - } - - featureType = featuretype(strName); - - if (featureType == "int") { - retVal = getFeature(strName, feature_veci); - intFlag = 1; - } else { // double - retVal = getFeature(strName, feature_vec); - intFlag = 0; - } - // printf("\n Calculating distance for [%s] values [", strName.c_str()); - if (retVal <= 0) { - // printf ("\n Error in feature calculation... [%s]\n",GErrorStr.c_str() ); - return error_dist; - } else { - if (intFlag) { - for (unsigned i = 0; i < feature_veci.size(); i++) { - // printf("%d\t", feature_veci[i]); - dError = dError + fabs(feature_veci[i] - mean); - } - dError = dError / std / feature_veci.size(); - if (dError != dError) { - // printf("Warning: Error distance calculation generated NaN, returning - // error_dist\n"); - return error_dist; - } - // printf("] TotalError = %f\n", dError); - return dError; - } else { - for (unsigned i = 0; i < feature_vec.size(); i++) { - // printf("%f\t", feature_vec[i]); - dError = dError + fabs(feature_vec[i] - mean); - } - dError = dError / std / feature_vec.size(); - if (dError != dError) { - printf( - "Warning: Error distance calculation generated NaN, returning " - "error_dist\n"); - return error_dist; - } - // printf("] TotalError = %f\n", dError); - return dError; - } - } - return error_dist; -} - string cFeature::featuretype(string featurename) { if (featurename == "__test_efel_assertion__") // for testing only throw EfelAssertionError("Test efel assertion is successfully triggered."); diff --git a/efel/cppcore/cfeature.h b/efel/cppcore/cfeature.h index 2d8c984d..9739406f 100644 --- a/efel/cppcore/cfeature.h +++ b/efel/cppcore/cfeature.h @@ -62,8 +62,6 @@ class cFeature { string featuretype(string featurename); string getGError(); void get_feature_names(vector& feature_names); - double getDistance(string strName, double mean, double std, - bool trace_check=true, double error_dist=250); }; diff --git a/efel/cppcore/cppcore.cpp b/efel/cppcore/cppcore.cpp index 223dfc37..8f2fcb32 100644 --- a/efel/cppcore/cppcore.cpp +++ b/efel/cppcore/cppcore.cpp @@ -266,26 +266,6 @@ static PyObject* getFeatureNames(PyObject* self, PyObject* args) { return Py_BuildValue(""); } -static PyObject* getDistance_wrapper(PyObject* self, PyObject* args, - PyObject* kwds) { - char* feature_name; - double mean, std, distance, error_dist = 250; - int trace_check = 1; - - const char* kwlist[] = {"feature_name", "mean", "std", - "trace_check", "error_dist", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "sdd|id", - const_cast(kwlist), &feature_name, - &mean, &std, &trace_check, &error_dist)) { - return NULL; - } - - distance = - pFeature->getDistance(feature_name, mean, std, trace_check, error_dist); - - return Py_BuildValue("d", distance); -} static PyObject* featuretype(PyObject* self, PyObject* args) { char* feature_name; @@ -333,9 +313,6 @@ static PyMethodDef CppCoreMethods[] = { {"getFeatureNames", getFeatureNames, METH_VARARGS, "Get the names of all the available features"}, - {"getDistance", (PyCFunction)getDistance_wrapper, - METH_VARARGS | METH_KEYWORDS, - "Get the distance between a feature and experimental data"}, {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/tests/test_cppcore.py b/tests/test_cppcore.py index 1682cee4..f0a17fa3 100644 --- a/tests/test_cppcore.py +++ b/tests/test_cppcore.py @@ -120,19 +120,6 @@ def test_getFeatureInt_wrong_type(self): # pylint: disable=R0201 import efel efel.cppcore.getFeatureInt("AP_amplitude", list()) - def test_getDistance(self): - """cppcore: Testing getDistance()""" - import efel - - self.setup_data() - np.testing.assert_allclose( - 3.09045815935, - efel.cppcore.getDistance( - 'AP_amplitude', - 50.0, - 10.0, - trace_check=True)) - def test_getFeature(self): """cppcore: Testing getFeature""" import efel diff --git a/tests/test_pyfeatures.py b/tests/test_pyfeatures.py index 006ba2dd..145ed92c 100644 --- a/tests/test_pyfeatures.py +++ b/tests/test_pyfeatures.py @@ -222,7 +222,7 @@ def test_depol_block_bool(): def test_pydistance(): - """pyfeatures: Test python distance against cpp version""" + """pyfeatures: Test python distance.""" mf1_trace = _load_trace('mean_frequency1') feature_name = 'AP_height' @@ -231,24 +231,6 @@ def test_pydistance(): numpy.seterr(divide='ignore') - # Check if cpp and python the same if: - # - baseline - # - std = 0.0 - # - trace_check is enabled - # - trace_check is enabled on faulty trace - # - trace_check is disabled on faulty trace - for args, stim_end in [ - ((mf1_trace, feature_name, mean, std, None), 900), - ((mf1_trace, feature_name, mean, 0.0, None), 900), - ((mf1_trace, feature_name, mean, std, True), 900), - ((mf1_trace, feature_name, mean, std, True), 600), - ((mf1_trace, feature_name, mean, std, False), 600), - ]: - efel.reset() - mf1_trace['stim_end'] = [stim_end] - assert ( - efel.getDistance(*args) == efel.api._getDistance_cpp(*args)) - # Extra sanity checks for trace_check mf1_trace['stim_end'] = [600] @@ -260,14 +242,6 @@ def test_pydistance(): std, trace_check=False), 30.422218394481284) - efel.reset() - numpy.testing.assert_allclose(efel.api._getDistance_cpp( - mf1_trace, - feature_name, - mean, - std, - trace_check=True), 250.0) - def test_pydistance_featurefail(): """pyfeatures: Test failure of feature in getdistance""" From 5f8881bf6901f46cf03fa32f7e7371cf98f66ff2 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 15:14:15 +0100 Subject: [PATCH 76/85] move trace_check to pyfeatures --- CHANGELOG.md | 2 +- efel/DependencyV5.txt | 3 +- efel/api.py | 5 ++-- efel/cppcore/FillFptrTable.cpp | 1 - efel/cppcore/LibV1.cpp | 22 -------------- efel/cppcore/LibV1.h | 3 -- efel/cppcore/cfeature.cpp | 1 - efel/pyfeatures/pyfeatures.py | 20 ++++++++++++- tests/DependencyV5_LibV5peakindices.txt | 1 - tests/test_allfeatures.py | 2 +- tests/test_pyfeatures.py | 38 ++++++++++++++++++++++--- 11 files changed, 58 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a2d6bd1..252cf0c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,5 +17,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Python changes - `bpap_attenuation` feature is added to the Python API. -- `Spikecount`, `Spikecount_stimint`, `burst_number` and `strict_burst_number` features migrated to Python from C++. +- `Spikecount`, `Spikecount_stimint`, `burst_number`, `strict_burst_number` and `trace_check` features migrated to Python from C++. - `check_ais_initiation` is added to the Python API. diff --git a/efel/DependencyV5.txt b/efel/DependencyV5.txt index e9f89c6e..18c2bb36 100644 --- a/efel/DependencyV5.txt +++ b/efel/DependencyV5.txt @@ -1,6 +1,5 @@ LibV1:interpolate -LibV5:peak_indices #LibV1:interpolate -LibV1:trace_check #LibV1:peak_time #LibV1:interpolate +LibV5:peak_indices #LibV1:interpolate LibV1:ISI_values #LibV1:peak_time #LibV1:interpolate LibV1:doublet_ISI #LibV1:peak_time #LibV1:interpolate LibV1:peak_voltage #LibV5:peak_indices #LibV1:interpolate diff --git a/efel/api.py b/efel/api.py index 673aac24..3dd0af89 100644 --- a/efel/api.py +++ b/efel/api.py @@ -261,9 +261,8 @@ def getDistance( cppcore.setFeatureDouble(item, [x for x in trace[item]]) if trace_check: - cppcoreFeatureValues = list() - retval = cppcore.getFeature('trace_check', cppcoreFeatureValues) - if retval < 0: + trace_check_success = getFeatureValues([trace], ['trace_check'])[0] + if trace_check_success["trace_check"] is None: return error_dist feature_values = _get_feature(featureName) diff --git a/efel/cppcore/FillFptrTable.cpp b/efel/cppcore/FillFptrTable.cpp index f9609934..5cb1a6a0 100644 --- a/efel/cppcore/FillFptrTable.cpp +++ b/efel/cppcore/FillFptrTable.cpp @@ -27,7 +27,6 @@ int FillFptrTable() { FptrTableV1["time_to_first_spike"] = &LibV1::first_spike_time; FptrTableV1["burst_ISI_indices"] = &LibV1::burst_ISI_indices; FptrTableV1["adaptation_index"] = &LibV1::adaptation_index; - FptrTableV1["trace_check"] = &LibV1::trace_check; FptrTableV1["spike_width2"] = &LibV1::spike_width2; FptrTableV1["burst_mean_freq"] = &LibV1::burst_mean_freq; FptrTableV1["interburst_voltage"] = &LibV1::interburst_voltage; diff --git a/efel/cppcore/LibV1.cpp b/efel/cppcore/LibV1.cpp index d14f2ff7..b73f9cf2 100644 --- a/efel/cppcore/LibV1.cpp +++ b/efel/cppcore/LibV1.cpp @@ -624,28 +624,6 @@ int LibV1::adaptation_index2(mapStr2intVec& IntFeatureData, // end of adaptation_index2 -int LibV1::trace_check(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, - mapStr2Str& StringData) { - const auto& doubleFeatures = - getFeatures(DoubleFeatureData, {"peak_time", "stim_start", "stim_end"}); - bool sane = true; - for (const auto& peak : doubleFeatures.at("peak_time")) { - if (peak < doubleFeatures.at("stim_start")[0] || - peak > doubleFeatures.at("stim_end")[0] * 1.05) { - sane = false; - break; - } - } - if (sane) { - vector tc = {0}; - setVec(IntFeatureData, StringData, "trace_check", tc); - return tc.size(); - } else { - throw FeatureComputationError("Trace sanity check failed, there were spike outside the stimulus interval."); - } -} - // To find spike width using Central difference derivative vec1[i] = // ((vec[i+1]+vec[i-1])/2)/dx and half width is between // MinAHP and APThreshold diff --git a/efel/cppcore/LibV1.h b/efel/cppcore/LibV1.h index e14e4622..ed2781ae 100644 --- a/efel/cppcore/LibV1.h +++ b/efel/cppcore/LibV1.h @@ -65,9 +65,6 @@ int adaptation_index(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); -int trace_check(mapStr2intVec& IntFeatureData, - mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); - // passive properties int time_constant(mapStr2intVec& IntFeatureData, mapStr2doubleVec& DoubleFeatureData, mapStr2Str& StringData); diff --git a/efel/cppcore/cfeature.cpp b/efel/cppcore/cfeature.cpp index bd598d51..57a56f72 100644 --- a/efel/cppcore/cfeature.cpp +++ b/efel/cppcore/cfeature.cpp @@ -75,7 +75,6 @@ const vector cFeature::getmapDoubleData(string strName) { void cFeature::fillfeaturetypes() { // initialize feature type information featuretypes["peak_indices"] = "int"; - featuretypes["trace_check"] = "int"; featuretypes["ISI_values"] = "double"; featuretypes["peak_voltage"] = "double"; featuretypes["burst_ISI_indices"] = "int"; diff --git a/efel/pyfeatures/pyfeatures.py b/efel/pyfeatures/pyfeatures.py index 0d0c6687..0a6ec87f 100644 --- a/efel/pyfeatures/pyfeatures.py +++ b/efel/pyfeatures/pyfeatures.py @@ -50,7 +50,8 @@ 'spikes_in_burst1_burstlast_diff', 'impedance', 'burst_number', - 'strict_burst_number' + 'strict_burst_number', + 'trace_check' ] @@ -94,6 +95,23 @@ def spike_count_stimint() -> numpy.ndarray: return numpy.array([res]) +def trace_check() -> numpy.ndarray | None: + """Returns np.array([0]) if there are no spikes outside stimulus boundaries. + + Returns None upon failure. + """ + stim_start = _get_cpp_data("stim_start") + stim_end = _get_cpp_data("stim_end") + peak_times = _get_cpp_feature("peak_time") + if peak_times is None: # If no spikes, then no problem + return numpy.array([0]) + # Check if there are no spikes or if all spikes are within the stimulus interval + if numpy.all((peak_times >= stim_start) & (peak_times <= stim_end * 1.05)): + return numpy.array([0]) # 0 if trace is valid + else: + return None # None if trace is invalid due to spike outside stimulus interval + + def burst_number() -> numpy.ndarray: """The number of bursts.""" burst_mean_freq = _get_cpp_feature("burst_mean_freq") diff --git a/tests/DependencyV5_LibV5peakindices.txt b/tests/DependencyV5_LibV5peakindices.txt index 4c69f3fd..fe49caac 100644 --- a/tests/DependencyV5_LibV5peakindices.txt +++ b/tests/DependencyV5_LibV5peakindices.txt @@ -1,5 +1,4 @@ LibV5:peak_indices #LibV1:interpolate -LibV1:trace_check #LibV1:peak_time LibV1:ISI_values #LibV1:peak_time LibV1:doublet_ISI #LibV1:peak_time LibV1:peak_voltage #LibV5:peak_indices diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index 11a81098..62ef7300 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -174,7 +174,7 @@ def test_allfeatures_on_constant_voltage(): "steady_state_voltage", "steady_state_voltage_stimend", "voltage_deflection", "voltage_deflection_begin", "voltage_deflection_vb_ssse", "depol_block", "depol_block_bool", "voltage_base", "Spikecount", - "Spikecount_stimint", "burst_number", "strict_burst_number" + "Spikecount_stimint", "burst_number", "strict_burst_number", "trace_check" ] for field in array_fields: diff --git a/tests/test_pyfeatures.py b/tests/test_pyfeatures.py index 145ed92c..10187865 100644 --- a/tests/test_pyfeatures.py +++ b/tests/test_pyfeatures.py @@ -231,16 +231,29 @@ def test_pydistance(): numpy.seterr(divide='ignore') - # Extra sanity checks for trace_check - mf1_trace['stim_end'] = [600] - efel.reset() + mf1_trace['stim_start'] = [0] + mf1_trace['stim_end'] = [900] + # with successful trace_check numpy.testing.assert_allclose(efel.getDistance( mf1_trace, feature_name, mean, std, - trace_check=False), 30.422218394481284) + trace_check=True), 30.422218394481284) + + efel.reset() + # with failed trace_check + mf1_trace["stim_end"] = [600] + error_value = 250.0 + res = efel.getDistance( + mf1_trace, + feature_name, + mean, + std, + trace_check=True, + error_dist=error_value) + assert res == error_value def test_pydistance_featurefail(): @@ -297,3 +310,20 @@ def test_impedance(): expected_values = {feature_name: 4.615384615384615} _test_expected_value(feature_name, expected_values) + + +def test_trace_check(): + """Unit test for trace_check.""" + efel.reset() + + mf1_trace = _load_trace('mean_frequency1') + feature_values = efel.getFeatureValues([mf1_trace], ['trace_check']) + assert feature_values[0]['trace_check'][0] == 0 + # failure + mf1_trace["stim_end"] = [600] + feature_values = efel.getFeatureValues([mf1_trace], ['trace_check']) + assert feature_values[0]['trace_check'] is None + # no spikes + mf1_trace["V"] = [0] * len(mf1_trace["V"]) + feature_values = efel.getFeatureValues([mf1_trace], ['trace_check']) + assert feature_values[0]['trace_check'][0] == 0 From b6940d1fda994de5435b8c36cfda15a31217c383 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 15:19:10 +0100 Subject: [PATCH 77/85] lint fix --- tests/test_pyfeatures.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_pyfeatures.py b/tests/test_pyfeatures.py index 10187865..c7861036 100644 --- a/tests/test_pyfeatures.py +++ b/tests/test_pyfeatures.py @@ -231,7 +231,6 @@ def test_pydistance(): numpy.seterr(divide='ignore') - mf1_trace['stim_start'] = [0] mf1_trace['stim_end'] = [900] # with successful trace_check From 87cc375322bdc253b9c407a3699e494ce15c0683 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 15:22:37 +0100 Subject: [PATCH 78/85] add from __future__ import annotations --- efel/pyfeatures/pyfeatures.py | 1 + 1 file changed, 1 insertion(+) diff --git a/efel/pyfeatures/pyfeatures.py b/efel/pyfeatures/pyfeatures.py index 0a6ec87f..630a1772 100644 --- a/efel/pyfeatures/pyfeatures.py +++ b/efel/pyfeatures/pyfeatures.py @@ -1,3 +1,4 @@ +from __future__ import annotations """Python implementation of features""" """ From 41b087efcd11d73727d23f58b1d0ffaf98e942fa Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 15:37:52 +0100 Subject: [PATCH 79/85] add stimulus_current to test_allfeatures_on_constant_V --- tests/test_allfeatures.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index 62ef7300..5bcb1fb4 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -159,7 +159,15 @@ def test_allfeatures_on_constant_voltage(): voltage = np.full(1000, -80.0) efel.reset() - traces = [{'T': time, 'V': voltage, 'stim_start': [100], 'stim_end': [999]}] + traces = [ + { + "T": time, + "V": voltage, + "stim_start": [100], + "stim_end": [999], + "stimulus_current": [1.0], + } + ] all_featurenames = efel.getFeatureNames() feature_values = efel.getFeatureValues(traces, all_featurenames)[0] assert all(feature_values["voltage"] == -80.0) @@ -174,7 +182,8 @@ def test_allfeatures_on_constant_voltage(): "steady_state_voltage", "steady_state_voltage_stimend", "voltage_deflection", "voltage_deflection_begin", "voltage_deflection_vb_ssse", "depol_block", "depol_block_bool", "voltage_base", "Spikecount", - "Spikecount_stimint", "burst_number", "strict_burst_number", "trace_check" + "Spikecount_stimint", "burst_number", "strict_burst_number", "trace_check", + "ohmic_input_resistance", "ohmic_input_resistance_vb_ssse" ] for field in array_fields: From f39e7eb793905d60032933342f8ad87fd3b13e22 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 17:18:18 +0100 Subject: [PATCH 80/85] allow both spike_count and Spikecount --- efel/pyfeatures/pyfeatures.py | 2 ++ tests/test_allfeatures.py | 10 +++++++--- tests/test_basic.py | 2 ++ tests/test_cppcore.py | 2 ++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/efel/pyfeatures/pyfeatures.py b/efel/pyfeatures/pyfeatures.py index 630a1772..9f06c916 100644 --- a/efel/pyfeatures/pyfeatures.py +++ b/efel/pyfeatures/pyfeatures.py @@ -45,6 +45,8 @@ 'depol_block_bool', 'Spikecount', 'Spikecount_stimint', + 'spike_count', + 'spike_count_stimint', 'spikes_per_burst', 'spikes_per_burst_diff', 'spikes_in_burst1_burst2_diff', diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index 5bcb1fb4..8bc3f750 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -126,7 +126,10 @@ def test_allfeatures(): """allfeatures: Regression testing all features on a trace""" feature_values = get_allfeature_values() - + # drop spike_count and spike_count_stimint from feature values since they + # are the same as deprecated Spikecount and Spikecount_stimint + feature_values.pop('spike_count') + feature_values.pop('spike_count_stimint') test_data_path = os.path.join(testdata_dir, 'expectedresults.json') with open(test_data_path, 'r') as expected_json: expected_results = json.load(expected_json) @@ -182,8 +185,9 @@ def test_allfeatures_on_constant_voltage(): "steady_state_voltage", "steady_state_voltage_stimend", "voltage_deflection", "voltage_deflection_begin", "voltage_deflection_vb_ssse", "depol_block", "depol_block_bool", "voltage_base", "Spikecount", - "Spikecount_stimint", "burst_number", "strict_burst_number", "trace_check", - "ohmic_input_resistance", "ohmic_input_resistance_vb_ssse" + "Spikecount_stimint", "spike_count", "spike_count_stimint", "burst_number", + "strict_burst_number", "trace_check", "ohmic_input_resistance", + "ohmic_input_resistance_vb_ssse" ] for field in array_fields: diff --git a/tests/test_basic.py b/tests/test_basic.py index 44d398ae..5f9ec00a 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1711,6 +1711,8 @@ def test_getFeatureNames(): test_data_path = testdata_dir.parent / 'featurenames.json' with open(test_data_path, 'r') as featurenames_json: expected_featurenames = json.load(featurenames_json) + # add the new names for the deprecated ones + expected_featurenames += ["spike_count", "spike_count_stimint"] assert set(efel.getFeatureNames()) == set(expected_featurenames) diff --git a/tests/test_cppcore.py b/tests/test_cppcore.py index f0a17fa3..af6c7147 100644 --- a/tests/test_cppcore.py +++ b/tests/test_cppcore.py @@ -97,6 +97,8 @@ def test_getFeatureNames(self): # pylint: disable=R0201 test_data_path = os.path.join(testdata_dir, '../featurenames.json') with open(test_data_path, 'r') as featurenames_json: expected_featurenames = json.load(featurenames_json) + # add the new names for the deprecated ones + expected_featurenames += ["spike_count", "spike_count_stimint"] assert set(feature_names) == set(expected_featurenames) def test_getFeatureDouble_failure(self): # pylint: disable=R0201 From 489c2478076b59394f6522d8fd84eef357e056e5 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 17:24:50 +0100 Subject: [PATCH 81/85] move validation.py inside pyfeatures --- docs/source/api.rst | 2 +- efel/{ => pyfeatures}/validation.py | 0 tests/test_validation.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename efel/{ => pyfeatures}/validation.py (100%) diff --git a/docs/source/api.rst b/docs/source/api.rst index 7fbddd3f..399d2bef 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -17,6 +17,6 @@ Submodules io pyfeatures.multitrace pyfeatures.pyfeatures + pyfeatures.validation units settings - validation diff --git a/efel/validation.py b/efel/pyfeatures/validation.py similarity index 100% rename from efel/validation.py rename to efel/pyfeatures/validation.py diff --git a/tests/test_validation.py b/tests/test_validation.py index 146efafb..f71e50fc 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -6,7 +6,7 @@ import efel from efel.io import load_ascii_input -from efel.validation import check_ais_initiation +from efel.pyfeatures.validation import check_ais_initiation testdata_dir = Path(__file__).parent / "testdata" From c6033de888eb813eb0d5369d237e18f3c1da996b Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 17:31:03 +0100 Subject: [PATCH 82/85] Revert "add stimulus_current to test_allfeatures_on_constant_V" This reverts commit 41b087efcd11d73727d23f58b1d0ffaf98e942fa. --- tests/test_allfeatures.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index 8bc3f750..e3d86bc5 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -162,15 +162,7 @@ def test_allfeatures_on_constant_voltage(): voltage = np.full(1000, -80.0) efel.reset() - traces = [ - { - "T": time, - "V": voltage, - "stim_start": [100], - "stim_end": [999], - "stimulus_current": [1.0], - } - ] + traces = [{'T': time, 'V': voltage, 'stim_start': [100], 'stim_end': [999]}] all_featurenames = efel.getFeatureNames() feature_values = efel.getFeatureValues(traces, all_featurenames)[0] assert all(feature_values["voltage"] == -80.0) @@ -185,9 +177,7 @@ def test_allfeatures_on_constant_voltage(): "steady_state_voltage", "steady_state_voltage_stimend", "voltage_deflection", "voltage_deflection_begin", "voltage_deflection_vb_ssse", "depol_block", "depol_block_bool", "voltage_base", "Spikecount", - "Spikecount_stimint", "spike_count", "spike_count_stimint", "burst_number", - "strict_burst_number", "trace_check", "ohmic_input_resistance", - "ohmic_input_resistance_vb_ssse" + "Spikecount_stimint", "burst_number", "strict_burst_number", "trace_check" ] for field in array_fields: From 268249489af25d7cd7443f05b67748f875e44476 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 17:33:14 +0100 Subject: [PATCH 83/85] add spike_count expect it to be 0 for allfeatures_on_constant_voltage --- tests/test_allfeatures.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index e3d86bc5..6e9d5fa0 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -177,7 +177,8 @@ def test_allfeatures_on_constant_voltage(): "steady_state_voltage", "steady_state_voltage_stimend", "voltage_deflection", "voltage_deflection_begin", "voltage_deflection_vb_ssse", "depol_block", "depol_block_bool", "voltage_base", "Spikecount", - "Spikecount_stimint", "burst_number", "strict_burst_number", "trace_check" + "Spikecount_stimint", "burst_number", "strict_burst_number", "trace_check", + "spike_count", "spike_count_stimint" ] for field in array_fields: From 43bf8b3021f40fb2df23300cd7dab3693c5a1b9d Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Tue, 9 Jan 2024 17:54:13 +0100 Subject: [PATCH 84/85] encourage use of spike_count instead of Spikecount --- docs/source/eFeatures.rst | 12 ++--- docs/source/tex/efeatures.tex | 8 +-- efel/units/units.json | 4 +- .../GranuleCell1/GranuleCellDeap1-scoop.py | 2 +- .../deap/GranuleCell1/GranuleCellDeap1.ipynb | 2 +- tests/featurenames.json | 4 +- tests/test_allfeatures.py | 7 ++- tests/test_basic.py | 50 +++++++++---------- tests/test_cppcore.py | 2 +- .../testdata/allfeatures/expectedresults.json | 4 +- 10 files changed, 47 insertions(+), 48 deletions(-) diff --git a/docs/source/eFeatures.rst b/docs/source/eFeatures.rst index ac597f84..d9931606 100644 --- a/docs/source/eFeatures.rst +++ b/docs/source/eFeatures.rst @@ -150,8 +150,8 @@ time from stimulus start to last spike else: time_to_last_spike = 0 -`Python efeature`_ : Spikecount -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`Python efeature`_ : spike_count +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ number of spikes in the trace, including outside of stimulus interval @@ -159,11 +159,11 @@ number of spikes in the trace, including outside of stimulus interval - **Units**: constant - **Pseudocode**: :: - Spikecount = len(peak_indices) + spike_count = len(peak_indices) **Note**: In the future this feature will be called "spike_count". -`Python efeature`_ : Spikecount_stimint +`Python efeature`_ : spike_count_stimint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ number of spikes inside the stimulus interval @@ -173,7 +173,7 @@ number of spikes inside the stimulus interval - **Pseudocode**: :: peaktimes_stimint = numpy.where((peak_time >= stim_start) & (peak_time <= stim_end)) - Spikecount_stimint = len(peaktimes_stimint) + spike_count_stimint = len(peaktimes_stimint) **Note**: In the future this feature will be called "spike_count_stimint". @@ -1902,7 +1902,7 @@ Computes the impedance given a ZAP current input and its voltage response. It will return the frequency at which the impedance is maximal, in the range (0, impedance_max_freq] Hz, with impedance_max_freq being a setting with 50.0 as a default value. -- **Required features**: current, LibV1:Spikecount, LibV5:voltage_base, LibV5:current_base +- **Required features**: current, spike_count, LibV5:voltage_base, LibV5:current_base - **Units**: Hz - **Pseudocode**: :: diff --git a/docs/source/tex/efeatures.tex b/docs/source/tex/efeatures.tex index d083f264..06cf9f62 100644 --- a/docs/source/tex/efeatures.tex +++ b/docs/source/tex/efeatures.tex @@ -858,16 +858,16 @@ \section{Elementary features} \end{efeature} \begin{efeature} - {Spikecount} - {LibV1} - {Spikecount} + {spike_count} + {Python efeature} + {spike_count} {none} {peak indices\\&trace check} {none} {none} {The number of peaks during stimulus} { - APPEND length of peak\_indices TO Spikecount + APPEND length of peak\_indices TO spike_count } Yield the length of \myid{peak indices}. diff --git a/efel/units/units.json b/efel/units/units.json index 22b6dde5..e656d2a9 100644 --- a/efel/units/units.json +++ b/efel/units/units.json @@ -55,8 +55,8 @@ "ISI_log_slope_skip": "ms", "ISI_semilog_slope": "ms", "ISI_values": "ms", - "Spikecount": "constant", - "Spikecount_stimint": "constant", + "spike_count": "constant", + "spike_count_stimint": "constant", "adaptation_index": "constant", "adaptation_index_2": "constant", "all_ISI_values": "ms", diff --git a/examples/deap/GranuleCell1/GranuleCellDeap1-scoop.py b/examples/deap/GranuleCell1/GranuleCellDeap1-scoop.py index 1d717a33..d867a2a7 100644 --- a/examples/deap/GranuleCell1/GranuleCellDeap1-scoop.py +++ b/examples/deap/GranuleCell1/GranuleCellDeap1-scoop.py @@ -39,7 +39,7 @@ from deap import tools FEATURES = ['voltage_base', - 'Spikecount', + 'spike_count', 'min_voltage_between_spikes', 'steady_state_voltage_stimend'] diff --git a/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb b/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb index b7cf0d02..195a2525 100644 --- a/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb +++ b/examples/deap/GranuleCell1/GranuleCellDeap1.ipynb @@ -99,7 +99,7 @@ "\n", " result = efel.getFeatureValues(\n", " traces, [\n", - " 'voltage_base', 'Spikecount', 'min_voltage_between_spikes', 'AP_height', 'steady_state_voltage_stimend'])\n", + " 'voltage_base', 'spike_count', 'min_voltage_between_spikes', 'AP_height', 'steady_state_voltage_stimend'])\n", "\n", " for feature_name, feature_list in result[0].items():\n", " if feature_list is not None and len(feature_list) > 0:\n", diff --git a/tests/featurenames.json b/tests/featurenames.json index 74d3b486..1b2a2cc1 100644 --- a/tests/featurenames.json +++ b/tests/featurenames.json @@ -55,8 +55,8 @@ "ISI_semilog_slope", "ISI_values", "ISIs", - "Spikecount", - "Spikecount_stimint", + "spike_count", + "spike_count_stimint", "adaptation_index", "adaptation_index2", "all_ISI_values", diff --git a/tests/test_allfeatures.py b/tests/test_allfeatures.py index 6e9d5fa0..1f7373ad 100644 --- a/tests/test_allfeatures.py +++ b/tests/test_allfeatures.py @@ -126,10 +126,9 @@ def test_allfeatures(): """allfeatures: Regression testing all features on a trace""" feature_values = get_allfeature_values() - # drop spike_count and spike_count_stimint from feature values since they - # are the same as deprecated Spikecount and Spikecount_stimint - feature_values.pop('spike_count') - feature_values.pop('spike_count_stimint') + # drop Spikecount and Spikecount_stimint deprecated features + feature_values.pop('Spikecount') + feature_values.pop('Spikecount_stimint') test_data_path = os.path.join(testdata_dir, 'expectedresults.json') with open(test_data_path, 'r') as expected_json: expected_results = json.load(expected_json) diff --git a/tests/test_basic.py b/tests/test_basic.py index 5f9ec00a..cd904081 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -616,7 +616,7 @@ def test_strict_stiminterval(): trace['stim_start'] = [stim_start] trace['stim_end'] = [stim_end] - features = ['peak_indices', 'peak_time', 'Spikecount'] + features = ['peak_indices', 'peak_time', 'spike_count'] feature_values = \ efel.getFeatureValues( @@ -625,7 +625,7 @@ def test_strict_stiminterval(): peak_indices = feature_values[0]['peak_indices'] peak_time = feature_values[0]['peak_time'] - spikecount = feature_values[0]['Spikecount'] + spikecount = feature_values[0]['spike_count'] assert len(peak_indices) == n_of_spikes assert len(peak_time) == n_of_spikes assert spikecount == n_of_spikes @@ -1132,7 +1132,7 @@ def test_getDistance_trace_check(): trace['stim_end'] = [70] traces.append(trace) numpy.testing.assert_allclose( - efel.getDistance(trace, 'Spikecount', 0, 1), 3.0 + efel.getDistance(trace, 'spike_count', 0, 1), 3.0 ) trace['stim_end'] = [50] @@ -1141,7 +1141,7 @@ def test_getDistance_trace_check(): numpy.testing.assert_allclose( efel.getDistance( trace, - 'Spikecount', + 'spike_count', 0, 1, trace_check=False), @@ -1149,7 +1149,7 @@ def test_getDistance_trace_check(): efel.reset() numpy.testing.assert_allclose( - efel.getDistance(trace, 'Spikecount', 0, 1), 250.0 + efel.getDistance(trace, 'spike_count', 0, 1), 250.0 ) @@ -1261,8 +1261,8 @@ def test_derivwindow1(): numpy.testing.assert_allclose(AP_begin_voltage, -45.505521563640386) -def test_spikecount1(): - """basic: Test Spikecount 1""" +def test_spike_count1(): + """basic: Test spike_count 1""" import efel efel.reset() @@ -1279,7 +1279,7 @@ def test_spikecount1(): trace['stim_start'] = [stim_start] trace['stim_end'] = [stim_end] - features = ['peak_indices', 'Spikecount'] + features = ['peak_indices', 'spike_count'] feature_values = \ efel.getFeatureValues( @@ -1287,12 +1287,12 @@ def test_spikecount1(): features) peak_indices = feature_values[0]['peak_indices'] - spikecount = feature_values[0]['Spikecount'][0] + spikecount = feature_values[0]['spike_count'][0] assert len(peak_indices) == spikecount -def test_spikecount_stimint1(): - """basic: Test Spikecount_stimint 1.""" +def test_spike_count_stimint1(): + """basic: Test spike_count_stimint 1.""" import efel efel.reset() @@ -1307,7 +1307,7 @@ def test_spikecount_stimint1(): trace['stim_start'] = [stim_start] trace['stim_end'] = [stim_end] - features = ['peak_time', 'Spikecount_stimint', 'Spikecount'] + features = ['peak_time', 'spike_count_stimint', 'spike_count'] feature_values = \ efel.getFeatureValues( @@ -1315,8 +1315,8 @@ def test_spikecount_stimint1(): features) peak_times = feature_values[0]['peak_time'] - spikecount = feature_values[0]['Spikecount'][0] - spikecount_stimint = feature_values[0]['Spikecount_stimint'][0] + spikecount = feature_values[0]['spike_count'][0] + spikecount_stimint = feature_values[0]['spike_count_stimint'][0] interval_peaktimes, = \ numpy.where((peak_times >= stim_start) & (peak_times <= stim_end)) @@ -1610,8 +1610,8 @@ def test_ohmic_input_resistance_vb_ssse_zero_stimulus_current(): assert ohmic_input_resistance is None -def test_spikecount2(): - """basic: Test Spikecount 2: test empty trace""" +def test_spike_count2(): + """basic: Test spike_count 2: test empty trace""" import efel efel.reset() @@ -1629,14 +1629,14 @@ def test_spikecount2(): trace['stim_start'] = [stim_start] trace['stim_end'] = [stim_end] - features = ['Spikecount'] + features = ['spike_count'] feature_values = \ efel.getFeatureValues( [trace], features) - spikecount = feature_values[0]['Spikecount'][0] + spikecount = feature_values[0]['spike_count'][0] assert spikecount == 0 @@ -1712,7 +1712,7 @@ def test_getFeatureNames(): with open(test_data_path, 'r') as featurenames_json: expected_featurenames = json.load(featurenames_json) # add the new names for the deprecated ones - expected_featurenames += ["spike_count", "spike_count_stimint"] + expected_featurenames += ["Spikecount", "Spikecount_stimint"] assert set(efel.getFeatureNames()) == set(expected_featurenames) @@ -2038,7 +2038,7 @@ def test_mean_AP_amplitude(): def test_unfinished_peak(): - """basic: Test if unfinished peak doesn't break Spikecount""" + """basic: Test if unfinished peak doesn't break spike_count""" import efel efel.setIntSetting('strict_stiminterval', True) @@ -2055,17 +2055,17 @@ def test_unfinished_peak(): trace['stim_start'] = [10] trace['stim_end'] = [70] - traces_results = efel.getFeatureValues([trace], ['Spikecount']) - spikecount = traces_results[0]['Spikecount'][0] + traces_results = efel.getFeatureValues([trace], ['spike_count']) + spikecount = traces_results[0]['spike_count'][0] assert spikecount == 3 # When the signal at the end of the trace is larger than the threshold, - # Spikecount and possibly other features cannont be estimated. + # spike_count and possibly other features cannont be estimated. v[int(80 / dt):] = -19 - traces_results = efel.getFeatureValues([trace], ['Spikecount']) - spikecount = traces_results[0]['Spikecount'][0] + traces_results = efel.getFeatureValues([trace], ['spike_count']) + spikecount = traces_results[0]['spike_count'][0] assert spikecount == 3 diff --git a/tests/test_cppcore.py b/tests/test_cppcore.py index af6c7147..8425ec10 100644 --- a/tests/test_cppcore.py +++ b/tests/test_cppcore.py @@ -98,7 +98,7 @@ def test_getFeatureNames(self): # pylint: disable=R0201 with open(test_data_path, 'r') as featurenames_json: expected_featurenames = json.load(featurenames_json) # add the new names for the deprecated ones - expected_featurenames += ["spike_count", "spike_count_stimint"] + expected_featurenames += ["Spikecount", "Spikecount_stimint"] assert set(feature_names) == set(expected_featurenames) def test_getFeatureDouble_failure(self): # pylint: disable=R0201 diff --git a/tests/testdata/allfeatures/expectedresults.json b/tests/testdata/allfeatures/expectedresults.json index e58a356b..77144d0d 100644 --- a/tests/testdata/allfeatures/expectedresults.json +++ b/tests/testdata/allfeatures/expectedresults.json @@ -314,10 +314,10 @@ 675.4999999993856, 250.29999999977235 ], - "Spikecount": [ + "spike_count": [ 6 ], - "Spikecount_stimint": [ + "spike_count_stimint": [ 6 ], "adaptation_index": [ From bc15caaf70028c1caad6d6671ab39d2861d068c8 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Wed, 10 Jan 2024 09:51:06 +0100 Subject: [PATCH 85/85] update deprecation note in the docs --- docs/source/eFeatures.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/eFeatures.rst b/docs/source/eFeatures.rst index d9931606..d162db00 100644 --- a/docs/source/eFeatures.rst +++ b/docs/source/eFeatures.rst @@ -161,7 +161,8 @@ number of spikes in the trace, including outside of stimulus interval spike_count = len(peak_indices) -**Note**: In the future this feature will be called "spike_count". +**Note**: "spike_count" is the new name for the feature "Spikecount". +"Spikecount", while still available, will be removed in the future. `Python efeature`_ : spike_count_stimint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -175,7 +176,8 @@ number of spikes inside the stimulus interval peaktimes_stimint = numpy.where((peak_time >= stim_start) & (peak_time <= stim_end)) spike_count_stimint = len(peaktimes_stimint) -**Note**: In the future this feature will be called "spike_count_stimint". +**Note**: "spike_count_stimint" is the new name for the feature "Spikecount_stimint". +"Spikecount_stimint", while still available, will be removed in the future. `LibV5`_ : number_initial_spikes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~