From 42e4851cda68012fd1af5586df555814ff945c64 Mon Sep 17 00:00:00 2001 From: William Heymann Date: Mon, 30 Sep 2019 16:03:27 +0200 Subject: [PATCH] fractionation now use fraction_csv to find the csv file all csv entries in the json file are now lowercase updated everything that looks for CSV to look for csv instead fractionationSlide now use spline for smooth sliding and smoother time offets, based on tests this improves convergence --- CADETMatch.egg-info/PKG-INFO | 2 +- CADETMatch.egg-info/SOURCES.txt | 33 +------------------ CADETMatch/CADETMatch.pyproj | 5 ++- CADETMatch/cache.py | 17 ++++++++-- CADETMatch/checkpoint_algorithms.py | 6 ++-- CADETMatch/kde_generator.py | 10 +++--- CADETMatch/match.py | 2 +- CADETMatch/score.py | 2 +- CADETMatch/scores/fractionationSSE.py | 2 +- CADETMatch/scores/fractionationSlide.py | 28 ++++------------ CADETMatch/scores/obsolete/dextranQuad.py | 4 --- CADETMatch/scores/obsolete/fractionation.py | 4 +-- .../scores/obsolete/fractionationCombine.py | 4 +-- .../obsolete/fractionationMeanVariance.py | 4 +-- .../scores/obsolete/fractionationMoment.py | 4 +-- CADETMatch/search/graphSpace.py | 2 +- CADETMatch/search/mcmc.py | 2 +- CADETMatch/search/multistart.py | 2 +- CADETMatch/search/scoretest.py | 2 +- CADETMatch/util.py | 16 ++++----- setup.py | 2 +- 21 files changed, 56 insertions(+), 97 deletions(-) diff --git a/CADETMatch.egg-info/PKG-INFO b/CADETMatch.egg-info/PKG-INFO index 49317f8..5936339 100644 --- a/CADETMatch.egg-info/PKG-INFO +++ b/CADETMatch.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: CADETMatch -Version: 0.4 +Version: 0.4.1 Summary: CADETMatch is a parameter estimation and error modeling library for CADET Home-page: https://github.com/modsim/CADET-Match Author: William Heymann diff --git a/CADETMatch.egg-info/SOURCES.txt b/CADETMatch.egg-info/SOURCES.txt index 86adbbc..c610054 100644 --- a/CADETMatch.egg-info/SOURCES.txt +++ b/CADETMatch.egg-info/SOURCES.txt @@ -39,32 +39,9 @@ CADETMatch.egg-info/top_level.txt CADETMatch/scores/__init__.py CADETMatch/scores/absoluteHeight.py CADETMatch/scores/absoluteTime.py -CADETMatch/scores/breakthrough.py -CADETMatch/scores/breakthroughCross.py -CADETMatch/scores/breakthroughHybrid.py -CADETMatch/scores/breakthroughHybrid2.py CADETMatch/scores/curve.py -CADETMatch/scores/derivative_similarity.py -CADETMatch/scores/derivative_similarity_cross.py -CADETMatch/scores/derivative_similarity_hybrid.py -CADETMatch/scores/derivative_similarity_hybrid2.py -CADETMatch/scores/derivative_similarity_hybrid2_spline.py -CADETMatch/scores/dextran.py -CADETMatch/scores/dextran3.py -CADETMatch/scores/dextranAngle.py -CADETMatch/scores/dextranHybrid.py -CADETMatch/scores/dextranHybrid2.py -CADETMatch/scores/dextranHybrid2_spline.py -CADETMatch/scores/dextranQuad.py CADETMatch/scores/dextranSSE.py CADETMatch/scores/dextranShape.py -CADETMatch/scores/dextranTest.py -CADETMatch/scores/dextran_original.py -CADETMatch/scores/dextran_spline.py -CADETMatch/scores/fractionation.py -CADETMatch/scores/fractionationCombine.py -CADETMatch/scores/fractionationMeanVariance.py -CADETMatch/scores/fractionationMoment.py CADETMatch/scores/fractionationSSE.py CADETMatch/scores/fractionationSlide.py CADETMatch/scores/logsse.py @@ -74,15 +51,7 @@ CADETMatch/scores/shapeDecaySimple.py CADETMatch/scores/shapeOnly.py CADETMatch/scores/shapeSimple.py CADETMatch/scores/similarity.py -CADETMatch/scores/similarityCross.py -CADETMatch/scores/similarityCrossDecay.py CADETMatch/scores/similarityDecay.py -CADETMatch/scores/similarityHybrid.py -CADETMatch/scores/similarityHybrid2.py -CADETMatch/scores/similarityHybrid2_spline.py -CADETMatch/scores/similarityHybridDecay.py -CADETMatch/scores/similarityHybridDecay2.py -CADETMatch/scores/similarityHybridDecay2Spline.py CADETMatch/scores/sse.py CADETMatch/scores/width.py CADETMatch/search/__init__.py @@ -92,8 +61,8 @@ CADETMatch/search/multistart.py CADETMatch/search/nsga2.py CADETMatch/search/nsga2_improved.py CADETMatch/search/nsga3.py -CADETMatch/search/nsga3_deap.py CADETMatch/search/nsga3_improved.py +CADETMatch/search/nsga3_old.py CADETMatch/search/nsga3_strategy.py CADETMatch/search/scoretest.py CADETMatch/search/spea2.py diff --git a/CADETMatch/CADETMatch.pyproj b/CADETMatch/CADETMatch.pyproj index 271ab68..340a5bb 100644 --- a/CADETMatch/CADETMatch.pyproj +++ b/CADETMatch/CADETMatch.pyproj @@ -14,10 +14,9 @@ False CondaEnv|CondaEnv|CADETMatch Standard Python launcher - "F:\DS9\fractionation\NSGA3_binding_fractions.json" 2 + "F:\temp\cadet_tutorial\lesson_5\multiple_components\example_nsga3_fractionation.json" 2 False - - + -m scoop -n 6 true diff --git a/CADETMatch/cache.py b/CADETMatch/cache.py index 81d46da..cced76e 100644 --- a/CADETMatch/cache.py +++ b/CADETMatch/cache.py @@ -169,6 +169,9 @@ def setupSettings(self): with settings_file.open() as json_data: self.settings = json.load(json_data) + if 'CSV' in self.settings: + self.settings['csv'] = self.settings['CSV'] + self.settings['population'] = int(self.settings['population']) self.settings['maxPopulation'] = int(self.settings.get('maxPopulation', self.settings['population'] * 10)) self.settings['minPopulation'] = int(self.settings.get('minPopulation', self.settings['population'])) @@ -305,11 +308,15 @@ def setupExperiment(self, experiment, sim=None, dataFromSim=0): else: CV_time = (area * length) / flow + #force CSV to lowercase + if 'CSV' in experiment: + experiment['csv'] = experiment['CSV'] + if dataFromSim: temp['time'], temp['value'] = get_times_values(sim, {'isotherm':experiment['isotherm']}) - elif 'CSV' in experiment: - data = numpy.loadtxt(experiment['CSV'], delimiter=',') + elif 'csv' in experiment: + data = numpy.loadtxt(experiment['csv'], delimiter=',') temp['time'] = data[:, 0] temp['value'] = data[:, 1] @@ -330,11 +337,15 @@ def setupExperiment(self, experiment, sim=None, dataFromSim=0): temp[featureName] = {} + #switch to lower case if 'CSV' in feature: + feature['csv'] = feature['CSV'] + + if 'csv' in feature: if dataFromSim: temp[featureName]['time'], temp[featureName]['value'] = get_times_values(sim, {'isotherm':feature['isotherm']}) else: - dataLocal = numpy.loadtxt(feature['CSV'], delimiter=',') + dataLocal = numpy.loadtxt(feature['csv'], delimiter=',') temp[featureName]['time'] = dataLocal[:, 0] temp[featureName]['value'] = dataLocal[:, 1] else: diff --git a/CADETMatch/checkpoint_algorithms.py b/CADETMatch/checkpoint_algorithms.py index 2327e64..22eb428 100644 --- a/CADETMatch/checkpoint_algorithms.py +++ b/CADETMatch/checkpoint_algorithms.py @@ -22,7 +22,7 @@ def eaMuCommaLambda(population, toolbox, mu, lambda_, cxpb, mutpb, ngen, setting sim_start = generation_start = time.time() - path = Path(cache.settings['resultsDirBase'], cache.settings['CSV']) + path = Path(cache.settings['resultsDirBase'], cache.settings['csv']) result_data = {'input':[], 'output':[], 'output_meta':[], 'results':{}, 'times':{}, 'input_transform':[], 'input_transform_extended':[], 'strategy':[], 'mean':[], 'confidence':[]} with path.open('a', newline='') as csvfile: @@ -133,7 +133,7 @@ def eaMuPlusLambda(population, toolbox, mu, lambda_, cxpb, mutpb, ngen, settings sim_start = generation_start = time.time() - path = Path(cache.settings['resultsDirBase'], cache.settings['CSV']) + path = Path(cache.settings['resultsDirBase'], cache.settings['csv']) result_data = {'input':[], 'output':[], 'output_meta':[], 'results':{}, 'times':{}, 'input_transform':[], 'input_transform_extended':[], 'strategy':[], 'mean':[], 'confidence':[]} with path.open('a', newline='') as csvfile: @@ -255,7 +255,7 @@ def nsga2(populationSize, ngen, cache, tools): cxpb = cache.settings['crossoverRate'] checkpointFile = Path(cache.settings['resultsDirMisc'], cache.settings['checkpointFile']) - path = Path(cache.settings['resultsDirBase'], cache.settings['CSV']) + path = Path(cache.settings['resultsDirBase'], cache.settings['csv']) result_data = {'input':[], 'output':[], 'output_meta':[], 'results':{}, 'times':{}, 'input_transform':[], 'input_transform_extended':[], 'strategy':[], 'mean':[], 'confidence':[]} with path.open('a', newline='') as csvfile: diff --git a/CADETMatch/kde_generator.py b/CADETMatch/kde_generator.py index a8aa4ba..1ab9d15 100644 --- a/CADETMatch/kde_generator.py +++ b/CADETMatch/kde_generator.py @@ -398,12 +398,12 @@ def setupReferenceResult(cache): for experiment in cache.settings['experiments']: temp_exp = dict(experiment) - if 'CSV' in temp_exp: - temp_exp['data'] = numpy.loadtxt(temp_exp['CSV'], delimiter=',') + if 'csv' in temp_exp: + temp_exp['data'] = numpy.loadtxt(temp_exp['csv'], delimiter=',') for feature in temp_exp['features']: - if 'CSV' in feature: - feature['data'] = numpy.loadtxt(feature['CSV'], delimiter=',') + if 'csv' in feature: + feature['data'] = numpy.loadtxt(feature['csv'], delimiter=',') temp.append(temp_exp) return temp @@ -472,7 +472,7 @@ def pump_delay(cache, data, pump_delay_time=None): #delay = quantize_delay(delay[0], interval) #data[:,1] = score.roll(data[:,1], delay) - data[:,1] = score.roll_spline(data[:,0], data[:,1], -delay) + data[:,1] = score.roll_spline(data[:,0], data[:,1], delay) return delay diff --git a/CADETMatch/match.py b/CADETMatch/match.py index 2e9ef68..9362abc 100644 --- a/CADETMatch/match.py +++ b/CADETMatch/match.py @@ -144,7 +144,7 @@ def createDirectories(cache, json_path): pass def createCSV(cache): - path = Path(cache.settings['resultsDirBase'], cache.settings['CSV']) + path = Path(cache.settings['resultsDirBase'], cache.settings['csv']) if not path.exists(): with path.open('w', newline='') as csvfile: writer = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_ALL) diff --git a/CADETMatch/score.py b/CADETMatch/score.py index b68a853..9ddee0f 100644 --- a/CADETMatch/score.py +++ b/CADETMatch/score.py @@ -23,7 +23,7 @@ def roll_spline(times, values, shift): spline = scipy.interpolate.InterpolatedUnivariateSpline(times, values, ext=1) - times_new = times + shift + times_new = times - shift values_new = spline(times_new) diff --git a/CADETMatch/scores/fractionationSSE.py b/CADETMatch/scores/fractionationSSE.py index 3e5c58a..f8f515a 100644 --- a/CADETMatch/scores/fractionationSSE.py +++ b/CADETMatch/scores/fractionationSSE.py @@ -68,7 +68,7 @@ def run(sim_data, feature): def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): temp = {} - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape start = numpy.array(data.iloc[:, 0]) diff --git a/CADETMatch/scores/fractionationSlide.py b/CADETMatch/scores/fractionationSlide.py index edf099f..d537923 100644 --- a/CADETMatch/scores/fractionationSlide.py +++ b/CADETMatch/scores/fractionationSlide.py @@ -14,7 +14,7 @@ def goal(offset, frac_exp, sim_data_time, sim_data_value, start, stop): - sim_data_value = score.roll(sim_data_value, int(offset)) + sim_data_value = score.roll_spline(sim_data_time, sim_data_value, offset) frac_sim = util.fractionate(start, stop, sim_data_time, sim_data_value) return numpy.sum((frac_exp-frac_sim)**2) @@ -32,21 +32,6 @@ def searchRange(times, start_frac, stop_frac, CV_time): searchIndexStop = numpy.argmax( times[times <= searchStop]) return searchIndexStart, searchIndexStop -def rollRange(times, sim_value, searchIndexStart, searchIndexStop): - peakMaxIndex = numpy.argmax(sim_value) - peakMaxTime = times[peakMaxIndex] - peakMaxValue = sim_value[peakMaxIndex] - - above1 = sim_value < 0.1 * peakMaxValue - beforePeak = times < peakMaxTime - - search = sim_value[beforePeak & above1] - searchMax = numpy.argmax(search) - - rollLeft = searchIndexStart - searchMax - rollRight = searchIndexStop - searchMax - return rollLeft, rollRight, searchMax - def run(sim_data, feature): simulation = sim_data['simulation'] timeFunc = feature['timeFunc'] @@ -77,14 +62,13 @@ def run(sim_data, feature): exp_values = numpy.array(data[str(component)]) sim_value = simulation.root.output.solution[feature['unit']]["solution_outlet_comp_%03d" % component] - rollLeft, rollRight, searchMax = rollRange(times, sim_value, searchIndexStart, searchIndexStop) - bounds = find_bounds(times, sim_value) result = scipy.optimize.differential_evolution(goal, bounds = [bounds,], args = (exp_values, times, sim_value, start, stop)) - time_offset = times[int(abs(result.x[0]))] - sim_data_value = score.roll(sim_value, int(result.x[0])) + time_offset = abs(result.x[0]) + sim_data_value = score.roll_spline(times, sim_value, result.x[0]) + fracOffset = util.fractionate(start, stop, times, sim_data_value) value_score = value_func(max(fracOffset)) @@ -121,7 +105,7 @@ def find_bounds(times, values): def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): temp = {} - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape headers = data.columns.values.tolist() @@ -152,7 +136,7 @@ def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): return temp def headers(experimentName, feature): - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape data_headers = data.columns.values.tolist() diff --git a/CADETMatch/scores/obsolete/dextranQuad.py b/CADETMatch/scores/obsolete/dextranQuad.py index b66dc7d..3b9074c 100644 --- a/CADETMatch/scores/obsolete/dextranQuad.py +++ b/CADETMatch/scores/obsolete/dextranQuad.py @@ -42,10 +42,6 @@ def run(sim_data, feature): pearson, diff_time = score.pearson_spline(exp_time_values, sim_data_zero, exp_data_zero) - #sse_diff, diff_time = score.sse_spline(exp_time_values, sim_data_zero, exp_data_zero) - - #sim_data_zero = score.roll_spline(exp_time_values, sim_data_zero, diff_time) - p = poly_fit(exp_time_values, sim_data_zero) if p is None: return settings.failure diff --git a/CADETMatch/scores/obsolete/fractionation.py b/CADETMatch/scores/obsolete/fractionation.py index a424d51..d9bf0ca 100644 --- a/CADETMatch/scores/obsolete/fractionation.py +++ b/CADETMatch/scores/obsolete/fractionation.py @@ -62,7 +62,7 @@ def run(sim_data, feature): def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): temp = {} - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape start = numpy.array(data.iloc[:, 0]) @@ -92,7 +92,7 @@ def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): return temp def headers(experimentName, feature): - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape #remove first two columns since those are the start and stop times cols = cols - 2 diff --git a/CADETMatch/scores/obsolete/fractionationCombine.py b/CADETMatch/scores/obsolete/fractionationCombine.py index b5b711a..466b448 100644 --- a/CADETMatch/scores/obsolete/fractionationCombine.py +++ b/CADETMatch/scores/obsolete/fractionationCombine.py @@ -73,7 +73,7 @@ def run(sim_data, feature): def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): temp = {} - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape start = numpy.array(data.iloc[:, 0]) @@ -108,7 +108,7 @@ def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): return temp def headers(experimentName, feature): - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape #remove first two columns since those are the start and stop times cols = cols - 2 diff --git a/CADETMatch/scores/obsolete/fractionationMeanVariance.py b/CADETMatch/scores/obsolete/fractionationMeanVariance.py index b18fa74..fbe4a5a 100644 --- a/CADETMatch/scores/obsolete/fractionationMeanVariance.py +++ b/CADETMatch/scores/obsolete/fractionationMeanVariance.py @@ -58,7 +58,7 @@ def run(sim_data, feature): def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): temp = {} - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape headers = data.columns.values.tolist() @@ -97,7 +97,7 @@ def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): return temp def headers(experimentName, feature): - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape data_headers = data.columns.values.tolist() diff --git a/CADETMatch/scores/obsolete/fractionationMoment.py b/CADETMatch/scores/obsolete/fractionationMoment.py index 4c5f73a..20fa01f 100644 --- a/CADETMatch/scores/obsolete/fractionationMoment.py +++ b/CADETMatch/scores/obsolete/fractionationMoment.py @@ -60,7 +60,7 @@ def run(sim_data, feature): def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): temp = {} - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape headers = data.columns.values.tolist() @@ -103,7 +103,7 @@ def setup(sim, feature, selectedTimes, selectedValues, CV_time, abstol): return temp def headers(experimentName, feature): - data = pandas.read_csv(feature['csv']) + data = pandas.read_csv(feature['fraction_csv']) rows, cols = data.shape data_headers = data.columns.values.tolist() diff --git a/CADETMatch/search/graphSpace.py b/CADETMatch/search/graphSpace.py index 7884562..2340834 100644 --- a/CADETMatch/search/graphSpace.py +++ b/CADETMatch/search/graphSpace.py @@ -34,7 +34,7 @@ def run(cache, tools, creator): meta_hof = pareto.ParetoFront(similar=util.similar, similar_fit=util.similar_fit_meta) grad_hof = pareto.ParetoFront(similar=util.similar, similar_fit=util.similar_fit) - path = Path(cache.settings['resultsDirBase'], cache.settings['CSV']) + path = Path(cache.settings['resultsDirBase'], cache.settings['csv']) with path.open('a', newline='') as csvfile: writer = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_ALL) diff --git a/CADETMatch/search/mcmc.py b/CADETMatch/search/mcmc.py index a1f509d..493597f 100644 --- a/CADETMatch/search/mcmc.py +++ b/CADETMatch/search/mcmc.py @@ -358,7 +358,7 @@ def run(cache, tools, creator): scoop.logger.info("loading kde") kde, kde_scaler = kde_generator.getKDE(cache) - path = Path(cache.settings['resultsDirBase'], cache.settings['CSV']) + path = Path(cache.settings['resultsDirBase'], cache.settings['csv']) with path.open('a', newline='') as csvfile: writer = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_ALL) diff --git a/CADETMatch/search/multistart.py b/CADETMatch/search/multistart.py index 74f7b7c..7257443 100644 --- a/CADETMatch/search/multistart.py +++ b/CADETMatch/search/multistart.py @@ -32,7 +32,7 @@ def run(cache, tools, creator): meta_hof = pareto.ParetoFront(similar=util.similar, similar_fit=util.similar_fit_meta) grad_hof = pareto.ParetoFront(similar=util.similar, similar_fit=util.similar_fit) - path = Path(cache.settings['resultsDirBase'], cache.settings['CSV']) + path = Path(cache.settings['resultsDirBase'], cache.settings['csv']) with path.open('a', newline='') as csvfile: writer = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_ALL) diff --git a/CADETMatch/search/scoretest.py b/CADETMatch/search/scoretest.py index 5b8618a..b573a9e 100644 --- a/CADETMatch/search/scoretest.py +++ b/CADETMatch/search/scoretest.py @@ -11,7 +11,7 @@ def run(cache, tools, creator): "run the parameter estimation" - path = Path(cache.settings['resultsDirBase'], cache.settings['CSV']) + path = Path(cache.settings['resultsDirBase'], cache.settings['csv']) with path.open('a', newline='') as csvfile: writer = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_ALL) pop = cache.toolbox.population(n=0) diff --git a/CADETMatch/util.py b/CADETMatch/util.py index a122031..e1d71b6 100644 --- a/CADETMatch/util.py +++ b/CADETMatch/util.py @@ -622,21 +622,21 @@ def copyCSVWithNoise(idx, center, noise): #find CSV files for experiment in settings['experiments']: - if 'CSV' in experiment: - data = numpy.genfromtxt(experiment['CSV'], delimiter=',') + if 'csv' in experiment: + data = numpy.genfromtxt(experiment['csv'], delimiter=',') addNoise(data, center, noise) - csv_path = Path(experiment['CSV']) + csv_path = Path(experiment['csv']) new_csv_path = baseDir / csv_path.name numpy.savetxt(str(new_csv_path), data, delimiter=',') - experiment['CSV'] = str(new_csv_path) + experiment['csv'] = str(new_csv_path) for feature in experiment['features']: - if 'CSV' in feature: - data = numpy.genfromtxt(feature['CSV'], delimiter=',') + if 'csv' in feature: + data = numpy.genfromtxt(feature['csv'], delimiter=',') addNoise(data, center, noise) - csv_path = Path(feature['CSV']) + csv_path = Path(feature['csv']) new_csv_path = baseDir / csv_path.name numpy.savetxt(str(new_csv_path), data, delimiter=',') - feature['CSV'] = str(new_csv_path) + feature['csv'] = str(new_csv_path) new_settings_file = baseDir / settings_file.name with new_settings_file.open(mode="w") as json_data: diff --git a/setup.py b/setup.py index 827f8cf..8ac2556 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="CADETMatch", - version="0.4.1", + version="0.4.2", author="William Heymann", author_email="w.heymann@fz-juelich.de", description="CADETMatch is a parameter estimation and error modeling library for CADET",