[Echempp-devel] Experiment/InputFilters InputFilters.cpp, NONE, 1.1 InputFilters.hpp, NONE, 1.1 uti
Status: Beta
Brought to you by:
berndspeiser
|
From: beeblbrox <bee...@us...> - 2008-03-27 13:19:10
|
Update of /cvsroot/echempp/Experiment/InputFilters In directory sc8-pr-cvs17.sourceforge.net:/tmp/cvs-serv14055/Experiment/InputFilters Added Files: InputFilters.cpp InputFilters.hpp util.hpp Log Message: New input filter framework. --- NEW FILE: InputFilters.cpp --- /*! \file InputFilters.hpp \brief implementation file input filters. InputFilters.cpp is part of the Experiment package. */ /* Copyright (C) 2008, Dominik Brugger This file is part of EChem++. EChem++ is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. EChem++ 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "InputFilters.hpp" namespace experiment{ // InputFilter implementation void InputFilter::remove_whitespace(std::istream& is) { char c; do { is.get(c); } while(isspace(c)); is.unget(); } std::string InputFilter::get_between(const std::string& s, const std::string& s1, const std::string& s2) { size_t idx1 = s.find_first_of(s1); size_t idx2 = s.find_first_of(s2); return s.substr(idx1+1, idx2-idx1-1); } // InputFilterBAS implementation bool InputFilterBAS::is_valid_file(std::istream& is) { std::string date, time, label, type; read_header(is, date, time, label, type); if(date.find("Date:") == std::string::npos || time.find("Time:") == std::string::npos || label.find("Label:") == std::string::npos) return false; if(type.find("Cyclic Voltammetry") == std::string::npos && type.find("Chronocoulometry") == std::string::npos && type.find("Chronoamperometry") == std::string::npos) return false; return true; } Experiment* InputFilterBAS::read(std::istream& is) { std::string date, time, label, type; read_header(is, date, time, label, type); if(type.find("Cyclic Voltammetry") != std::string::npos) return read_cv(is, date, time, label); if(type.find("Chronoamperometry") != std::string::npos) return read_ca(is, date, time, label); if(type.find("Chronocoulometry") != std::string::npos) return read_cc(is, date, time, label); return NULL; } Experiment* InputFilterBAS::read_cv(std::istream& is, const std::string& date, const std::string& time, const std::string& label) { experiment::Experiment* ep = new experiment::cv::RealInduced(new experiment::ConditionDataBAS(), new experiment::MeasurementDataCV()); experiment::MeasurementDataCV* md = dynamic_cast<experiment::MeasurementDataCV*>(ep->get_meas_data()); experiment::ConditionDataBAS* cd = dynamic_cast<experiment::ConditionDataBAS*>(ep->get_cond_data()); cd->date = date; cd->time = time; cd->label = label; cd->initE = read_init_potential(is); cd->highE = read_high_potential(is); cd->lowE = read_low_potential(is); cd->pn = read_pn(is); cd->v = read_scan_rate(is); cd->num_segments = read_num_segments(is); cd->sample_interval = read_sample_interval(is); cd->quiet_time = read_quiet_time(is); cd->R = read_resistance(is); cd->sensitivity = read_sensitivity(is); quantity::Time tstep = cd->sample_interval / cd->v; unsigned int num_datasets = read_num_datasets(is); std::string unit1, unit2; read_units(is, unit1, unit2); unsigned int num_datapoints = 0; std::vector<double> x, y; quantity::Time t; t = "0 s"; for(unsigned int i=0; i < num_datasets; ++i) { num_datapoints = read_num_datapoints(is); read_dataset(is, num_datapoints, x, y); for(unsigned int j=0; j < num_datapoints; ++j) { md->push_back(t, value2potential(x[j],unit1), value2current(y[j],unit2)); t += tstep; } } return ep; } Experiment* InputFilterBAS::read_ca(std::istream& is, const std::string& date, const std::string& time, const std::string& label) { experiment::Experiment* ep = new experiment::ca::RealInduced(new experiment::ConditionDataBAS(), new experiment::MeasurementDataCA()); experiment::MeasurementDataCA* md = dynamic_cast<experiment::MeasurementDataCA*>(ep->get_meas_data()); experiment::ConditionDataBAS* cd = dynamic_cast<experiment::ConditionDataBAS*>(ep->get_cond_data()); cd->date = date; cd->time = time; cd->label = label; cd->initE = read_init_potential(is); cd->highE = read_high_potential(is); cd->lowE = read_low_potential(is); cd->pn = read_pn(is); cd->pulse_width = read_pulse_width(is); cd->num_steps = read_num_steps(is); cd->quiet_time = read_quiet_time(is); cd->sensitivity = read_sensitivity(is); std::string unit1, unit2; unsigned int num_datasets = read_num_datasets(is); unsigned int num_datapoints = read_num_datapoints(is); read_units(is, unit1, unit2); std::vector<double> x, y; for(unsigned int i=0; i < num_datasets; ++i) { read_dataset(is, num_datapoints, x, y); for(unsigned int j=0; j < num_datapoints; ++j) { if(i % 2 == 0) md->push_back(value2time(x[j],unit1), cd->initE, value2current(y[j],unit2)); else md->push_back(value2time(x[j],unit1), cd->highE, value2current(y[j],unit2)); } } return ep; } //! Read content of CC measurement file. Experiment* InputFilterBAS::read_cc(std::istream& is, const std::string& date, const std::string& time, const std::string& label) { experiment::Experiment* ep = new experiment::cc::RealInduced(new experiment::ConditionDataBAS(), new experiment::MeasurementDataCC()); experiment::MeasurementDataCC* md = dynamic_cast<experiment::MeasurementDataCC*>(ep->get_meas_data()); experiment::ConditionDataBAS* cd = dynamic_cast<experiment::ConditionDataBAS*>(ep->get_cond_data()); cd->date = date; cd->time = time; cd->label = label; cd->initE = read_init_potential(is); cd->finalE = read_final_potential(is); cd->pulse_width = read_pulse_width(is); cd->num_steps = read_num_steps(is); cd->quiet_time = read_quiet_time(is); cd->sensitivity = read_sensitivity(is); std::string unit1, unit2; unsigned int num_datasets = read_num_datasets(is); unsigned int num_datapoints = read_num_datapoints(is); read_units(is, unit1, unit2); std::vector<double> x, y; quantity::Time xj; quantity::ElectricPotential pot; quantity::ElectricCharge yj; for(unsigned int i=0; i < num_datasets; ++i) { read_dataset(is, num_datapoints, x, y); for(unsigned int j=0; j < num_datapoints; ++j) { if(i % 2 == 0) md->push_back(value2time(x[j], unit1), cd->initE, value2charge(y[j], unit2)); else md->push_back(value2time(x[j], unit1), cd->finalE, value2charge(y[j], unit2)); } } return ep; } //! Read one dataset, e.g. two columns of data placed in x, y with num_datapoints //! each. void InputFilterBAS::read_dataset(std::istream& is, const unsigned int num_datapoints, std::vector<double>& x, std::vector<double>& y) { std::string line; x.resize(num_datapoints); y.resize(num_datapoints); std::string xi, yi; while(std::getline(is,line)) { // find start of next dataset if(line.find("#") != std::string::npos) { for(unsigned int i=0; i<num_datapoints; ++i) { std::getline(is,line); split_at(line, ",", xi, yi); str2value(xi, x[i]); str2value(yi, y[i]); } break; } } } //! Read unit and value from the line designated by string key void InputFilterBAS::read_unit_value(std::istream& is, const std::string& key, std::string& unit, std::string& value) { std::string line; while(std::getline(is,line)) { if(line.find(key) != std::string::npos) { std::string name; split_at(line, "=", name, value); unit = get_between(name, "(", ")"); break; } } } quantity::ElectricPotential InputFilterBAS::read_init_potential(std::istream& is) { std::string key = "Init E"; std::string unit, value; read_unit_value(is, key, unit, value); return str2potential(value, unit); } quantity::ElectricPotential InputFilterBAS::read_high_potential(std::istream& is) { std::string key = "High E"; std::string unit, value; read_unit_value(is, key, unit, value); return str2potential(value, unit); } quantity::ElectricPotential InputFilterBAS::read_low_potential(std::istream& is) { std::string key = "Low E"; std::string unit, value; read_unit_value(is, key, unit, value); return str2potential(value, unit); } quantity::ElectricPotential InputFilterBAS::read_final_potential(std::istream& is) { std::string key = "Final E"; std::string unit, value; read_unit_value(is, key, unit, value); return str2potential(value, unit); } quantity::ElectricPotential InputFilterBAS::read_sample_interval(std::istream& is) { std::string key = "Sample Interval"; std::string unit, value; read_unit_value(is, key, unit, value); return str2potential(value, unit); } quantity::Time InputFilterBAS::read_pulse_width(std::istream& is) { std::string key = "Pulse Width"; std::string unit, value; read_unit_value(is, key, unit, value); return str2time(value, unit); } quantity::VoltageScanRate InputFilterBAS::read_scan_rate(std::istream& is) { std::string key = "V ("; std::string unit, value; read_unit_value(is, key, unit, value); std::string unit1, unit2; split_at(unit, "/", unit1, unit2); return str2voltagescanrate(value, unit1, unit2); } quantity::Time InputFilterBAS::read_quiet_time(std::istream& is) { std::string key = "Quiet Time"; std::string unit, value; read_unit_value(is, key, unit, value); return str2time(value, unit); } bool InputFilterBAS::read_pn(std::istream& is) { bool r = true; std::string line, name, value; getline(is,line); split_at(line, "=", name, value); if(value.find("N") != std::string::npos) r = false; return r; } unsigned int InputFilterBAS::read_num_segments(std::istream& is) { unsigned int r = 0; read_name_value(is, "Number of Segments", "=", r); return r; } unsigned int InputFilterBAS::read_num_steps(std::istream& is) { unsigned int r = 0; read_name_value(is, "Number of Steps", "=", r); return r; } double InputFilterBAS::read_resistance(std::istream& is) { double r = 0; read_name_value(is, "R", "=", r); return r; } double InputFilterBAS::read_sensitivity(std::istream& is) { double r = 0; read_name_value(is, "Sensitivity", "=", r); return r; } unsigned int InputFilterBAS::read_total_num_points(std::istream& is) { unsigned int r = 0; read_name_value(is, "Total Number of Data Points", "=", r); return r; } unsigned int InputFilterBAS::read_num_datapoints(std::istream& is) { unsigned int r = 0; read_name_value(is, "Number of Data Points", "=", r); return r; } unsigned int InputFilterBAS::read_num_datasets(std::istream& is) { std::string line; while(std::getline(is,line)) { if(line.find("Sets of Data") != std::string::npos) { std::string value, rest; split_at(line, " ", value, rest); unsigned int r = 0; str2value(value, r); return r; } } return 0; } void InputFilterBAS::read_units(std::istream& is, std::string& unit1, std::string& unit2) { std::string line; while(std::getline(is,line)) { if(line.find("##") != std::string::npos) break; } std::getline(is,line); std::string u1, u2; split_at(line, ",", u1, u2); unit1 = get_between(u1, "(", ")"); unit2 = get_between(u2, "(", ")"); } void InputFilterBAS::read_header(std::istream& is, std::string& date, std::string& time, std::string& label, std::string& type) { remove_whitespace(is); std::getline(is, date); remove_whitespace(is); std::getline(is, time); remove_whitespace(is); std::getline(is, label); remove_whitespace(is); std::getline(is, type); } // InputFilterASCII implementation bool InputFilterASCII::is_valid_file(std::istream& is) { std::string line; std::getline(is,line); if(line.find("ModSim ASCII export") != std::string::npos) return true; return false; } Experiment* InputFilterASCII::read(std::istream& is) { experiment::Experiment* ep = new experiment::cv::SimInduced(new experiment::ConditionDataModSim(), new experiment::MeasurementDataCV()); experiment::MeasurementDataCV* md = dynamic_cast<experiment::MeasurementDataCV*>(ep->get_meas_data()); std::string header; std::getline(is, header); std::string units; std::getline(is, units); std::string rest, unit1, unit2, unit3; split_at(units, " ", unit1, rest); split_at(rest, " ", unit2, unit3); std::string line, v1, v2, v3; while(std::getline(is,line)) { split_at(line, ",", v1, rest); split_at(rest, ",", v2, v3); md->push_back(str2time(v1, unit1), str2potential(v2, unit2), str2current(v3, unit3)); } return ep; } // InputFilters implementation InputFilters::InputFilters() { filters.push_back(new InputFilterBAS()); filters.push_back(new InputFilterASCII()); // Add your filter here // filters.push_back(new InputFilterMyFormat()); } InputFilters::~InputFilters() { for(unsigned int i=0; i < filters.size(); ++i) delete filters[i]; } Experiment* InputFilters::read(const std::string filename) { std::ifstream ifs(filename.c_str()); if(ifs) { for(unsigned int i=0; i<filters.size(); ++i) { if(filters[i]->is_valid_file(ifs)) { ifs.close(); ifs.open(filename.c_str()); return filters[i]->read(ifs); } ifs.close(); ifs.open(filename.c_str()); } throw InputFilterException("No matching filter found"); } return NULL; } }// end namespace experiment --- NEW FILE: InputFilters.hpp --- /*! \file InputFilters.hpp \brief header file input filters. InputFilters.hpp is part of the Experiment package. */ /* Copyright (C) 2008, Dominik Brugger This file is part of EChem++. EChem++ is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. EChem++ 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // $Id: InputFilters.hpp,v 1.1 2008/03/27 13:19:01 beeblbrox Exp $ #ifndef __INPUT_FILTERS #define __INPUT_FILTERS #include <string> #include <vector> #include <fstream> #include <sstream> #include "Experiment/Experiment.hpp" #include "util.hpp" namespace experiment{ //! This is the base class for all input filters. Each input filter should //! implement the functions is_valid_file and read, where the latter is used //! for reading the file and constructing an Experiment and the former is used //! to determine whether the text file to be read is compliant with the filter. class InputFilter { public: //! Return true if the file given by stream is can be read by the filter. virtual bool is_valid_file(std::istream& is) = 0; //! Read data from text file and construct Experiment. virtual Experiment* read(std::istream& is) = 0; virtual ~InputFilter() {}; protected: //! Remove superfluous whitespace from stream void remove_whitespace(std::istream& is); //! Extract string between string s1 and s2, e.g. between "(" and ")" std::string get_between(const std::string& s, const std::string& s1, const std::string& s2); }; //! Input filter class for reading BAS files from CV, CA and CC //! measurements. class InputFilterBAS : public InputFilter { public: //! Return true if the file given by stream is can be read by the filter. //! Overridden from base class InputFilter. bool is_valid_file(std::istream& is); //! Read data from text file and construct Experiment. //! Overridden from base class InputFilter. Experiment* read(std::istream& is); private: //! Read content of CV measurement file. Experiment* read_cv(std::istream& is, const std::string& date, const std::string& time, const std::string& label); //! Read content of CA measurement file. Experiment* read_ca(std::istream& is, const std::string& date, const std::string& time, const std::string& label); //! Read content of CC measurement file. Experiment* read_cc(std::istream& is, const std::string& date, const std::string& time, const std::string& label); //! Read one dataset, e.g. two columns of data placed in x, y with num_datapoints //! each. void read_dataset(std::istream& is, const unsigned int num_datapoints, std::vector<double>& x, std::vector<double>& y); //! Read unit and value from the line designated by string key void read_unit_value(std::istream& is, const std::string& key, std::string& unit, std::string& value); quantity::ElectricPotential read_init_potential(std::istream& is); quantity::ElectricPotential read_high_potential(std::istream& is); quantity::ElectricPotential read_low_potential(std::istream& is); quantity::ElectricPotential read_final_potential(std::istream& is); quantity::ElectricPotential read_sample_interval(std::istream& is); quantity::Time read_pulse_width(std::istream& is); quantity::VoltageScanRate read_scan_rate(std::istream& is); quantity::Time read_quiet_time(std::istream& is); bool read_pn(std::istream& is); unsigned int read_num_segments(std::istream& is); unsigned int read_num_steps(std::istream& is); double read_resistance(std::istream& is); double read_sensitivity(std::istream& is); unsigned int read_total_num_points(std::istream& is); unsigned int read_num_datapoints(std::istream& is); unsigned int read_num_datasets(std::istream& is); void read_units(std::istream& is, std::string& unit1, std::string& unit2); void read_header(std::istream& is, std::string& date, std::string& time, std::string& label, std::string& type); }; // InputFilterBAS //! Input filter class for reading ASCII files exported by ModSim. class InputFilterASCII : public InputFilter { bool is_valid_file(std::istream& is); Experiment* read(std::istream& is); }; // InputFilterASCII //! Input filters exception. Standard compliant. class InputFilterException : public std::exception { public: InputFilterException(const std::string msg) : _msg(msg) {} ~InputFilterException() throw() {} const char* what() const throw() { return _msg.c_str(); } private: std::string _msg; }; //! Convenience class for using input filters. After adding a new input //! filter class add them in the constructor of InputFilters for easy //! access by the user. //! Usage: //! InputFilters ipf; //! Experiment* ep = ipf.read("myfile.txt"); class InputFilters { public: InputFilters(); ~InputFilters(); Experiment* read(const std::string filename); private: std::vector<InputFilter*> filters; }; // InputFilters } // end namespace experiment #endif --- NEW FILE: util.hpp --- /*! \file util.hpp \brief header file for simple utility functions InputFilters.hpp is part of the Experiment package. */ /* Copyright (C) 2008, Dominik Brugger This file is part of EChem++. EChem++ is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. EChem++ 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __INPUT_FILTERS_UTIL #define __INPUT_FILTERS_UTIL #include "PhysicalQuantities/ElectricCurrent.h" #include "PhysicalQuantities/ElectricPotential.h" #include "PhysicalQuantities/ElectricCharge.h" #include "PhysicalQuantities/Time.h" #include "PhysicalQuantities/VoltageScanRate.h" namespace experiment{ //! Split input string s at seperator string sep returning //! results of split in s1 and s2. void split_at(const std::string& s, const std::string& sep, std::string& s1, std::string& s2) { size_t idx = s.find_first_of(sep); s1 = s.substr(0,idx); s2 = s.substr(idx+1); } //! Convert string to numeric value. template<class T> void str2value(const std::string& value, T& v) { v = 0; std::istringstream iss(value); iss >> v; } //! Read name/value pair seperated by string sep, //! where the keyword string is used to scan the file and //! result is returned in r. template<class T> void read_name_value(std::istream& is, const std::string& keyword, const std::string& sep, T& r) { std::string line; while(std::getline(is,line)) { if(line.find(keyword) != std::string::npos) { std::string name, value; split_at(line, sep, name, value); str2value(value, r); break; } } } //! Convert numeric value to voltage scan rate having units unit1 and unit2, //! e.g. unit1 = "V" and unit2 = "sec". template<class T> quantity::VoltageScanRate value2voltagescanrate(const T v, const std::string& unit1, const std::string& unit2) { if(unit1 == "V" && (unit2 == "s" || unit2 == "sec")) return quantity::VoltageScanRate(v, quantity::voltageScanRate::VoltPerSecond()); // Note the following does not work due to a bug in the Quantities library // if(unit1 == "V" && (unit2 == "ms" || unit2 == "msec")) // return quantity::VoltageScanRate(v, quantity::voltageScanRate::VoltPerMilliSecond()); // if(unit1 == "V" && (unit2 == "us" || unit2 == "usec")) // return quantity::VoltageScanRate(v, quantity::voltageScanRate::VoltPerMicroSecond()); if(unit1 == "mV" && (unit2 == "s" || unit2 == "sec")) return quantity::VoltageScanRate(v, quantity::voltageScanRate::MilliVoltPerSecond()); if(unit1 == "kV" && (unit2 == "s" || unit2 == "sec")) return quantity::VoltageScanRate(v, quantity::voltageScanRate::KiloVoltPerSecond()); return quantity::VoltageScanRate(v, quantity::voltageScanRate::VoltPerSecond()); } //! Convert string value to voltage scan rate having units unit1 and unit2. quantity::VoltageScanRate str2voltagescanrate(const std::string& value, const std::string& unit1, const std::string& unit2) { double v = 0; str2value(value,v); return value2voltagescanrate(v, unit1, unit2); } //! Convert numeric value to current having unit designated by string unit. template<class T> quantity::ElectricCurrent value2current(const T v, const std::string& unit) { if(unit == "uA") return quantity::ElectricCurrent(v, quantity::electricCurrent::MicroAmpere()); if(unit == "mA") return quantity::ElectricCurrent(v, quantity::electricCurrent::MilliAmpere()); if(unit == "A") return quantity::ElectricCurrent(v, quantity::electricCurrent::Ampere()); return quantity::ElectricCurrent(v, quantity::electricCurrent::Ampere()); } //! Convert string value to current having unit designated by string unit. quantity::ElectricCurrent str2current(const std::string& value, const std::string& unit) { double v = 0; str2value(value, v); return value2current(v, unit); } //! Convert numeric value to potential having unit designated by string unit. template<class T> quantity::ElectricPotential value2potential(const T v, const std::string& unit) { if(unit == "uV") return quantity::ElectricPotential(v, quantity::electricPotential::MicroVolt()); if(unit == "mV") return quantity::ElectricPotential(v, quantity::electricPotential::MilliVolt()); if(unit == "V") return quantity::ElectricPotential(v, quantity::electricPotential::Volt()); return quantity::ElectricPotential(v, quantity::electricPotential::Volt()); } //! Convert string value to potential having unit designated by string unit. quantity::ElectricPotential str2potential(const std::string& value, const std::string& unit) { double v = 0; str2value(value, v); return value2potential(v, unit); } //! Convert numeric value to time having unit designated by string unit. template<class T> quantity::Time value2time(const T v, const std::string& unit) { if(unit == "msec" || unit == "ms") return quantity::Time(v, quantity::time::MilliSecond()); if(unit == "msec" || unit == "ms") return quantity::Time(v, quantity::time::MilliSecond()); if(unit == "sec" || unit == "s") return quantity::Time(v, quantity::time::Second()); if(unit == "min" || unit == "m") return quantity::Time(v, quantity::time::Minute()); return quantity::Time(v, quantity::time::Minute()); } //! Convert string value to time having unit designated by string unit. quantity::Time str2time(const std::string& value, const std::string& unit) { double v = 0; str2value(value, v); return value2time(v, unit); } //! Convert numeric value to charge having unit designated by string unit. template<class T> quantity::ElectricCharge value2charge(const T v, const std::string& unit) { if(unit == "mC") return quantity::ElectricCharge(v, quantity::electricCharge::MilliCoulomb()); if(unit == "C") return quantity::ElectricCharge(v, quantity::electricCharge::Coulomb()); return quantity::ElectricCharge(v, quantity::electricCharge::Coulomb()); } //! Convert string value to charge having unit designated by string unit. quantity::ElectricCharge str2charge(const std::string& value, const std::string& unit) { double v = 0; str2value(value, v); return value2charge(v, unit); } } // end namespace experiment #endif |