From 83a57b18e1bb8df0b7330d52aca0895832266bb6 Mon Sep 17 00:00:00 2001 From: Anil Tuncel Date: Thu, 14 Dec 2023 14:59:35 +0100 Subject: [PATCH] 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++) {