diff --git a/TODO b/TODO index 7888754d828ec1a9861d7066dab881e757c545e2..a5dfd3fe963df67392d6ab4f52949778c40b669f 100644 --- a/TODO +++ b/TODO @@ -148,6 +148,8 @@ parallelize global fits == WAITING FOR CLUE == +parallel execution: upon first exception kill all threads + rework dy, dp How to treat blanks in user input: diff --git a/pub/lib/file_in.cpp b/pub/lib/file_in.cpp index 96c6dd0caae75bf3a24ab545338a1b42fb4c26dc..a1f1b9f12290f5c377fcc0d5957c30f1ff4cbd61 100644 --- a/pub/lib/file_in.cpp +++ b/pub/lib/file_in.cpp @@ -33,7 +33,7 @@ using namespace std; namespace NFileIn { - void Load_08( ifstream& F_in, string fnam ); + void Load_yda( ifstream& F_in, string fnam ); } @@ -53,12 +53,7 @@ void NFileIn::load(void) if( FS.fail() ) throw string("cannot open file"); cout << ".. loading file " << fnam << "\n"; - if ( fext=="y08" ) - Load_08( FS, fshort ); - else if ( fext=="yda" ) - cout << "TODO\n"; - else - throw "BUG: unforeseen extension " + fext; + Load_yda( FS, fshort ); FS.close(); } catch(string& ex) { @@ -70,9 +65,9 @@ void NFileIn::load(void) } } -//! Load a YAML file in y08 format. +//! Load a YAML file in yda format. -void NFileIn::Load_08(ifstream& FS, string fnam) +void NFileIn::Load_yda(ifstream& FS, string fnam) { const YAML::Node doc = YAML::Load(FS); if( doc.Type() != YAML::NodeType::Map ) @@ -81,14 +76,19 @@ void NFileIn::Load_08(ifstream& FS, string fnam) //read meta if(!doc["Meta"]) throw S("no Meta"); - if ( doc["Meta"].Type() != YAML::NodeType::Map && doc["Meta"].size() > 0 ) - throw S("Meta is not a MAP type"); + if ( doc["Meta"].Type() != YAML::NodeType::Map ) + throw S("Meta is not of MAP type"); if(!doc["Meta"]["format"]) throw S("no format in Meta"); string s = doc["Meta"]["format"].as<string>(); - if ( s != "frida/y08 for yaml1" ) - throw S("format is not frida/y08 for yaml1"); + int version; + if ( s == "frida/y08 for yaml1" ) + version = 1; + else if ( s == "frida/y15 for yaml1.2" ) + version = 2; + else + throw "unknown data format '" + s + "'"; if(!doc["Meta"]["type"]) throw S("no type in Meta"); @@ -108,13 +108,14 @@ void NFileIn::Load_08(ifstream& FS, string fnam) fc = POlc( new COlc ); fout = fc; } else - throw "Meta section has invalid type "+type; + throw "Invalid file type "+type; // read history if(!doc["History"]) throw S("no History"); - if ( doc["History"].Type() != YAML::NodeType::Sequence && doc["History"].size() > 0 ) - throw S("History is not a SEQUENCE type"); + if ( doc["History"].Type() != YAML::NodeType::Sequence && + (version>1 || doc["History"].size()>0 ) ) + throw S("History is not of SEQUENCE type"); for (int i = 0; i < doc["History"].size(); i++) { string s = doc["History"][i].as<string>(); fout->lDoc.push_back(s); @@ -123,113 +124,225 @@ void NFileIn::Load_08(ifstream& FS, string fnam) // read coord if(!doc["Coord"]) throw S("no Coord"); - if ( doc["Coord"].Type() != YAML::NodeType::Map && doc["Coord"].size() > 0 ) - throw S("Coord is not a MAP type"); - if( const YAML::Node& pName = doc["Coord"]["x"] ){ - fout->xco.name = pName["name"].as<string>(); - fout->xco.unit =pName["unit"].as<string>(); + if ( doc["Coord"].Type() != YAML::NodeType::Map ) + throw S("Coord is not of MAP type"); + if( const YAML::Node& dCo = doc["Coord"]["x"] ){ + fout->xco.name = dCo["name"].as<string>(); + fout->xco.unit =dCo["unit"].as<string>(); } else throw S("no x coord"); - if( const YAML::Node& pName = doc["Coord"]["y"] ){ - fout->yco.name = pName["name"].as<string>(); - fout->yco.unit = pName["unit"].as<string>(); + if( const YAML::Node& dCo = doc["Coord"]["y"] ){ + fout->yco.name = dCo["name"].as<string>(); + fout->yco.unit = dCo["unit"].as<string>(); } else throw S("no y coord"); - - int iz = 0; - while(const YAML::Node& pName = doc["Coord"]["z"+S(iz)]){ - CCoord co(pName["name"].as<string>(), pName["unit"].as<string>()); - fout->ZCo.push_back( co ); - ++iz; + if ( version==1 ) { + int iz = 0; + while(const YAML::Node& dCo = doc["Coord"]["z"+S(iz)]){ + CCoord co(dCo["name"].as<string>(), dCo["unit"].as<string>()); + fout->ZCo.push_back( co ); + ++iz; + } + } else { + if ( doc["Coord"]["z"].Type() != YAML::NodeType::Sequence ) + throw S("Coord[z] is not of SEQUENCE type"); + for ( auto dCo: doc["Coord"]["z"] ) { + CCoord co(dCo["name"].as<string>(), dCo["unit"].as<string>()); + fout->ZCo.push_back( co ); + } } - // read Param - if(!doc["Param"]) - throw S("no Param"); - if ( doc["Param"].Type() != YAML::NodeType::Sequence && doc["Param"].size() > 0) - throw S("Param is not a SEQUENCE type"); - for( int iParam = 0; iParam < (doc["Param"].size()); iParam++ ){ - if ( doc["Param"][iParam].Type() != YAML::NodeType::Map ) - throw "Param " + S(iParam) + " is not a MAP type"; - CCoord co(doc["Param"][iParam]["name"].as<string>(), - doc["Param"][iParam]["unit"].as<string>()); - string s = doc["Param"][iParam]["value"].as<string>(); - double num; - if( !triv::any2dbl( s, &num ) ) - throw "param(" + co.name + "): invalid value " + s; - fout->RPar.push_back( CParam( co, num ) ); + // read r-pars + if ( version==1 ) { + if(!doc["Param"]) + throw S("no Param"); + if ( doc["Param"].Type() != YAML::NodeType::Sequence && doc["Param"].size() > 0) + throw S("Param is not of SEQUENCE type"); + for( int iParam = 0; iParam < (doc["Param"].size()); iParam++ ){ + if ( doc["Param"][iParam].Type() != YAML::NodeType::Map ) + throw "Param " + S(iParam) + " is not of MAP type"; + CCoord co(doc["Param"][iParam]["name"].as<string>(), + doc["Param"][iParam]["unit"].as<string>()); + string s = doc["Param"][iParam]["value"].as<string>(); + double num; + if( !triv::any2dbl( s, &num ) ) + throw "param(" + co.name + "): invalid value " + s; + fout->RPar.push_back( CParam( co, num ) ); + } + } else { + if(!doc["RPar"]) + throw S("no RPar"); + if ( doc["RPar"].Type() != YAML::NodeType::Sequence ) + throw S("RPar is not of SEQUENCE type"); + for ( auto dCo: doc["RPar"] ) { + if ( dCo.Type() != YAML::NodeType::Map ) + throw S("an r-par is not of MAP type"); + CCoord co(dCo["name"].as<string>(), dCo["unit"].as<string>()); + double val = dCo["val"].as<double>(); + fout->RPar.push_back( CParam( co, val ) ); + } } // for curve, read formula if( !isdata ) { - const YAML::Node& pName = doc["Formula"]; - if( !pName ) - throw S("DEFICIENT FILE: no formula"); - string s = pName.as<string>(); - fc->parse_function( s ); + string expr; + if ( version==1 ) { + const YAML::Node& nod = doc["Formula"]; + if( !nod ) + throw S("DEFICIENT FILE: no formula"); + expr = nod.as<string>(); + fc->parse_function( s ); + fc->curve_set_defaults(); + } else { + const YAML::Node& nod = doc["Curve"]; + if( !nod ) + throw S("DEFICIENT FILE: no Curve section"); + expr = nod["expr"].as<string>(); + fc->nP = nod["nPar"].as<int>(); + fc->weighing = COlc::name2wgt( nod["weighing"].as<string>() ); + fc->chi2 = nod["chi2"].as<double>(); + } + fc->parse_function( expr ); fc->curve_set_defaults(); } - //start to read Tables - if(!doc["Tables"]) - throw S("no Tables"); - if ( doc["Tables"].Type() != YAML::NodeType::Sequence && doc["Tables"].size() > 0 ) - throw S("Tables is not a SEQUENCE type"); - for (int iTable = 0; iTable < (doc["Tables"].size()); iTable++) { - if ( doc["Tables"][iTable].Type() != YAML::NodeType::Map ) - throw "Tables " + S(iTable) + " is not a MAP type"; - vector<RObj> z; - for(int iz=0; iz<fout->ZCo.size(); ++iz ){ - string s = doc["Tables"][iTable]["z" + S(iz)].as<string>() ; - double num; - if( !triv::any2dbl( s, &num ) ) - throw "z" + S(iz) + ": invalid value " + s; - z.push_back( RObjDbl( new CObjDbl( num ) ) ); + // start to read slices + if ( version==1 ) { + if(!doc["Tables"]) + throw S("no Tables"); + if ( doc["Tables"].Type() != YAML::NodeType::Sequence && doc["Tables"].size() > 0 ) + throw S("Tables is not of SEQUENCE type"); + for (int iTable = 0; iTable < (doc["Tables"].size()); iTable++) { + if ( doc["Tables"][iTable].Type() != YAML::NodeType::Map ) + throw "Tables " + S(iTable) + " is not of MAP type"; + vector<RObj> z; + for(int iz=0; iz<fout->ZCo.size(); ++iz ){ + string s = doc["Tables"][iTable]["z" + S(iz)].as<string>() ; + double num; + if( !triv::any2dbl( s, &num ) ) + throw "z" + S(iz) + ": invalid value " + s; + z.push_back( RObjDbl( new CObjDbl( num ) ) ); + } + + if( isdata ) { + PSpec sout( new CSpec ); + sout->z = z; + string xytag; + if ( doc["Tables"][iTable]["xy"] ) { + string res, lin; + string val = doc["Tables"][iTable]["xy"].as<string>(); + while( val != "" ) { + triv::string_extract_line( val, &lin, &res ); + double vx, vy; + if( sscanf( lin.c_str(), "%lg %lg\n", &vx, &vy )!=2 ) + throw "xy: bad data line: " + lin; + sout->push_xy( vx, vy ); + val = res; + }; + } else if ( doc["Tables"][iTable]["xyd"] ) { + //itxy.second() >> val; + string res, lin; + string val = doc["Tables"][iTable]["xyd"].as<string>(); + while( val != "" ) { + triv::string_extract_line( val, &lin, &res ); + double vx, vy, dy; + if( sscanf( lin.c_str(), "%lg %lg %lg\n",&vx, &vy, &dy )!=3 ) + throw "xyd: bad data line: " + lin; + sout->push_xyd( vx, vy, dy ); + val = res; + }; + } else + throw "invalid xytag " + xytag; + fout->V.push_back( sout ); + } else { + PCurve cout( new CCurve ); + cout->z = z; + for( int ip=0; ip<fc->nP; ++ip ){ + string res; + string val = doc["Tables"][iTable]["p" + S(ip)].as<string>(); + double num; + if( !triv::any2dbl( val, &num ) ) + throw "p" + S(ip) + ": invalid value " + val; + cout->P.push_back( num ); + cout->ParAttr.push_back( 'u' ); + } + fout->V.push_back( cout ); + } } + } else { + if(!doc["Slices"]) + throw S("no Slices"); + if ( doc["Slices"].Type() != YAML::NodeType::Sequence ) + throw S("section Slices is not of SEQUENCE type"); + for ( const YAML::Node& nodeSlic: doc["Slices"] ) { + if ( nodeSlic.Type() != YAML::NodeType::Map ) + throw S("a slice is not of MAP type"); + const YAML::Node& nodeZ = nodeSlic["z"]; + if(!nodeZ) + throw S("a slice has no z entry"); + if ( nodeZ.Type() != YAML::NodeType::Sequence ) + throw S("a z entry is not of SEQUENCE type"); + vector<RObj> z; + for ( const YAML::Node& nodeZi: nodeZ ) { + if ( nodeSlic.Type() != YAML::NodeType::Map ) + throw S("a z entry is not of MAP type"); + z.push_back( RObjDbl( new CObjDbl( nodeZi["val"].as<double>() ) ) ); + } + if( isdata ) { + PSpec sout( new CSpec ); + sout->z = z; + if(!nodeSlic["x"]) + throw S("a slice has no x entry"); + if ( nodeSlic["x"].Type() != YAML::NodeType::Sequence ) + throw S("an x entry is not of SEQUENCE type"); + for ( const YAML::Node& nodeEle: nodeSlic["x"] ) + sout->x.push_back( nodeEle.as<double>() ); - if( isdata ) { - PSpec sout( new CSpec ); - sout->z = z; - string xytag; - if ( doc["Tables"][iTable]["xy"] ) { - string res, lin; - string val = doc["Tables"][iTable]["xy"].as<string>(); - while( val != "" ) { - triv::string_extract_line( val, &lin, &res ); - double vx, vy; - if( sscanf( lin.c_str(), "%lg %lg\n", &vx, &vy )!=2 ) - throw "xy: bad data line: " + lin; - sout->push_xy( vx, vy ); - val = res; - }; - } else if ( doc["Tables"][iTable]["xyd"] ) { - //itxy.second() >> val; - string res, lin; - string val = doc["Tables"][iTable]["xyd"].as<string>(); - while( val != "" ) { - triv::string_extract_line( val, &lin, &res ); - double vx, vy, dy; - if( sscanf( lin.c_str(), "%lg %lg %lg\n",&vx, &vy, &dy )!=3 ) - throw "xyd: bad data line: " + lin; - sout->push_xyd( vx, vy, dy ); - val = res; - }; - } else - throw "invalid xytag " + xytag; - fout->V.push_back( sout ); - } else { - PCurve cout( new CCurve ); - cout->z = z; - for( int ip=0; ip<fc->nP; ++ip ){ - string res; - string val = doc["Tables"][iTable]["p" + S(ip)].as<string>(); - double num; - if( !triv::any2dbl( val, &num ) ) - throw "p" + S(ip) + ": invalid value " + val; - cout->P.push_back( num ); - cout->ParAttr.push_back( 'u' ); + if(!nodeSlic["y"]) + throw S("a slice has no y entry"); + if ( nodeSlic["y"].Type() != YAML::NodeType::Sequence ) + throw S("a y entry is not of SEQUENCE type"); + for ( const YAML::Node& nodeEle: nodeSlic["y"] ) + sout->y.push_back( nodeEle.as<double>() ); + if( sout->y.size() != sout->x.size() ) + throw S("a y entry differs in length from x"); + + if( nodeSlic["dy"] ) { + if ( nodeSlic["dy"].Type() != YAML::NodeType::Sequence ) + throw S("a dy entry is not of SEQUENCE type"); + for ( const YAML::Node& nodeEle: nodeSlic["dy"] ) + sout->dy.push_back( nodeEle.as<double>() ); + if( sout->dy.size() != sout->x.size() ) + throw S("a dy entry differs in length from x"); + } + fout->V.push_back( sout ); + } else { + PCurve cout( new CCurve ); + cout->z = z; + if(!nodeSlic["p"]) + throw S("a slice has no p entry"); + if ( nodeSlic["p"].Type() != YAML::NodeType::Sequence ) + throw S("a p entry is not of SEQUENCE type"); + for ( const YAML::Node& nodeEle: nodeSlic["p"] ) + cout->P.push_back( nodeEle.as<double>() ); + if ( cout->P.size()!=fc->nP ) + throw S("number of p entries conflicts with nPar"); + + if(!nodeSlic["attr"]) + throw S("a slice has no attr entry"); + if ( nodeSlic["attr"].Type() != YAML::NodeType::Sequence ) + throw S("an attr entry is not of SEQUENCE type"); + for ( const YAML::Node& nodeEle: nodeSlic["attr"] ) + cout->ParAttr.push_back( nodeEle.as<char>() ); + if ( cout->ParAttr.size()!=fc->nP ) + throw S("number of attr entries conflicts with nPar"); + + cout->fitOutcome = nodeSlic["fitOutcome"].as<double>(); + cout->fitChi2 = nodeSlic["fitChi2"].as<double>(); + cout->fitR2 = nodeSlic["fitR2"].as<double>(); + + fout->V.push_back( cout ); } - fout->V.push_back( cout ); } } diff --git a/pub/lib/file_out.cpp b/pub/lib/file_out.cpp index b9ed944547d2e1055aca2d7591ff35514dcf3c8a..0864aac23f2013c712f9affebb974a180fee28ee 100644 --- a/pub/lib/file_out.cpp +++ b/pub/lib/file_out.cpp @@ -95,7 +95,7 @@ void NFileOut::save_yda( std::ofstream& ofs, POlo f ) out << YAML::Key << "format" << YAML::Value << "frida/y15 for yaml1.2"; out << YAML::Key << "type" << YAML::Value << ( fd ? "generic tabular data" : "frida2 curve" ); out << YAML::EndMap; - + out << YAML::Key << "History" << YAML::Value << YAML::BeginSeq; for ( string lin: f->lDoc ) out << lin; @@ -108,7 +108,7 @@ void NFileOut::save_yda( std::ofstream& ofs, POlo f ) out << YAML::Key << "y" << YAML::Value << YAML::Flow << YAML::BeginMap << YAML::Key << "name" << YAML::Value << f->yco.name << YAML::Key << "unit" << YAML::Value << f->yco.unit << YAML::EndMap; - out << YAML::Key << "z" << YAML::Value << YAML::Flow << YAML::BeginSeq; + out << YAML::Key << "z" << YAML::Value << YAML::Flow << YAML::BeginSeq; for ( auto& zco: f->ZCo ) out << YAML::BeginMap << YAML::Key << "name" << YAML::Value << zco.name << @@ -129,12 +129,13 @@ void NFileOut::save_yda( std::ofstream& ofs, POlo f ) out << YAML::Key << "Curve" << YAML::Value << YAML::BeginMap; out << YAML::Key << "expr" << YAML::Value << fc->expr; + out << YAML::Key << "nPar" << YAML::Value << fc->nP; out << YAML::Key << "weighing" << YAML::Value << COlc::wgtNames[fc->weighing]; out << YAML::Key << "chi2" << YAML::Value << fc->chi2; out << YAML::EndMap; } - + out << YAML::Key << "Slices" << YAML::Value << YAML::BeginSeq; for( size_t j=0; j<f->V.size(); ++j ) { out << YAML::BeginMap; diff --git a/pub/lib/olf.cpp b/pub/lib/olf.cpp index 0cd8f596bc114ea918215e4cc31c8170aaeeb192..bed8246427733ca86ef2f2279d0b4fe95368fa07 100644 --- a/pub/lib/olf.cpp +++ b/pub/lib/olf.cpp @@ -330,6 +330,16 @@ bool COld::has_nonzero_dy() const string COlc::wgtNames[] = { "lin", "log", "var", "varc", "vard" }; +//! Converts weight from string to enum + +COlc::TWgt COlc::name2wgt( string name ) +{ + for ( int i=0; i<=_LAST_TWGT; ++i ) + if( name==COlc::wgtNames[i] ) + return (TWgt)i; + throw "undefined weighing key '" + name + "'"; +} + //! Prompt for curve description, and initialize things. void COlc::curve_query( const string& quest ) diff --git a/pub/lib/olf.hpp b/pub/lib/olf.hpp index 47e78e557c85ce93e894f559adcb65d69c783364..3a5812e77f90e205779edd930f0a3b119bac253c 100644 --- a/pub/lib/olf.hpp +++ b/pub/lib/olf.hpp @@ -94,9 +94,10 @@ public: // Fitting: int kd; ///< Index of data file to be fitted. int kconv; ///< Index of resolution file to convolve with. - enum TWgt { _LIN, _LOG, _VAR, _VARC, _VARD } + enum TWgt { _LIN, _LOG, _VAR, _VARC, _VARD, _LAST_TWGT=_VARD } weighing; ///< Weight mode for fitting. static string wgtNames[]; + static TWgt name2wgt( string name ); bool plot_to_grid; ///< Use grid from file 'kd' ? string range_expr; ///< Restricts points to be fitted. RNode range_T; ///< Parsed range_expr.