From fec4b2983ca3cc178532302b708f9b1c2f557a1d Mon Sep 17 00:00:00 2001 From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de> Date: Wed, 8 Mar 2017 12:38:15 +0100 Subject: [PATCH] new function plotter respects prange ... but still does not bisect at limits. --- pub/itest/curveplot.f2t | 15 ++++ pub/lib/commands.cpp | 8 +- pub/lib/curve.cpp | 29 +++++-- pub/lib/curve.hpp | 2 +- pub/lib/fit.cpp | 4 +- pub/lib/obj.hpp | 2 +- pub/lib/olf.cpp | 35 ++++++++- pub/lib/olf.hpp | 10 ++- pub/lib/plot.cpp | 163 +++++++++------------------------------- 9 files changed, 118 insertions(+), 150 deletions(-) diff --git a/pub/itest/curveplot.f2t b/pub/itest/curveplot.f2t index 59b3acd9..0b723b0a 100755 --- a/pub/itest/curveplot.f2t +++ b/pub/itest/curveplot.f2t @@ -67,4 +67,19 @@ op0 26 gya p gfa /tmp/fridatestplot.ps +cca p0+p1*t +crp .2<t && t<.730812 +gx 0 1 +gya +p +gfa /tmp/fridatestplot.ps +gy -3 0 +p +gfa /tmp/fridatestplot.ps +cca sin(t) +crp abs(f(t))<.3 +gx 0 40 +gy -1.1 .9 +p +gfa /tmp/fridatestplot.ps qui diff --git a/pub/lib/commands.cpp b/pub/lib/commands.cpp index 22bb2dc5..0e0132a6 100644 --- a/pub/lib/commands.cpp +++ b/pub/lib/commands.cpp @@ -152,7 +152,9 @@ bool frida_command(string cmd) " cm modify function\n" " cd set data file to fit\n" " cv set file to convolute with (cv-: no convolution)\n" - " cr set fit range restriction\n" + " cr set range restrictions for fit and plot\n" + " crf - for fit only\n" + " crp - for plot only\n" " cf fit\n" " cfs fit, allow slow convolution\n" " cp print parameters\n" @@ -187,8 +189,8 @@ bool frida_command(string cmd) } else if (cmd == "cd" || cmd == "cv" || cmd == "cv-") { NCurveFile::set_file_reference(cmd.substr(1)); - } else if (cmd == "cr") { - NCurveFile::change_range(); + } else if (cmd == "cr" || cmd == "crf" || cmd == "crp") { + NCurveFile::change_range(cmd.substr(2)); } else if (cmd == "cp") { NCurveFile::show_pars(); diff --git a/pub/lib/curve.cpp b/pub/lib/curve.cpp index ece8756d..b3f2265e 100644 --- a/pub/lib/curve.cpp +++ b/pub/lib/curve.cpp @@ -205,20 +205,33 @@ void NCurveFile::set_par_attr(char attr) //! Queries and sets fit range restrictions. -void NCurveFile::change_range() +void NCurveFile::change_range(const string& subcmd) { FileIterator fiter(SFSel::instance()->selC()); - string expr = sask("Expression restricting the fit range"); + string which = ""; + if (subcmd=="") + which = "plot and fit"; + else if (subcmd=="f") + which = "fit"; + else if (subcmd=="p") + which = "plot"; + else + throw "BUG: invalid command"; + + string query = "Expression restricting the " + which + " range"; + string expr = sask(query); // TODO: default if only one file while (COlc* fc = fiter.nextC()) { - fc->range_expr = expr; - fc->log_action("cr " + expr); - if (expr == "") { - fc->range_T = nullptr; - continue; + RNode T = expr!="" ? user_xaxparse(expr.c_str()) : nullptr; + fc->log_action("cr" + subcmd + " " + expr); + if (subcmd=="" || subcmd=="f") { + fc->frange_expr = expr; + fc->frange_T = T; + } else if (subcmd=="" || subcmd=="p") { + fc->prange_expr = expr; + fc->prange_T = T; } - fc->range_T = user_xaxparse(expr.c_str()); } } diff --git a/pub/lib/curve.hpp b/pub/lib/curve.hpp index 9b0c781b..433de2e8 100644 --- a/pub/lib/curve.hpp +++ b/pub/lib/curve.hpp @@ -20,7 +20,7 @@ namespace NCurveFile void create_fitcurve(); void create_freecurve(); void change_expr(); -void change_range(); +void change_range(const string& subcmd); void set_file_reference(const string& which); void set_properties(string which); diff --git a/pub/lib/fit.cpp b/pub/lib/fit.cpp index 49247480..5daae25d 100644 --- a/pub/lib/fit.cpp +++ b/pub/lib/fit.cpp @@ -522,7 +522,7 @@ void NCurveFit::fit(bool _allow_slow_conv) if ((fc->weighing == COlc::_VAR || fc->weighing == COlc::_VARD) && !fd->VS(0)->has_dy()) throw S("Data have no error bars, cannot apply chosen fit weights"); - if (fc->range_T) { + if (fc->frange_T) { throw S("TODO: restore range evaluation"); /* // overwrite fd with data that obye the range restriction: @@ -532,7 +532,7 @@ void NCurveFit::fit(bool _allow_slow_conv) PSpec sout = PSpec( new CSpec ); sout->z = sin->z; vector<double> range( sin->size() ); - fc->range_T->tree_vec_val( &range, 0, fc->kd, j ); + fc->frange_T->tree_vec_val( &range, nullptr, fc->kd, j ); bool with_dy = sin->has_dy(); for ( int i=0; i<sin->size(); i++ ) { if ( range[i] ) { diff --git a/pub/lib/obj.hpp b/pub/lib/obj.hpp index 7a049a56..9a8e6f1a 100644 --- a/pub/lib/obj.hpp +++ b/pub/lib/obj.hpp @@ -172,7 +172,7 @@ class CObjVecInt : public CObjVecNum { public: vector<int> v; //!< The data. - CObjVecInt(int n = 0) : CObjVecNum(), v(n, -1) {} + CObjVecInt(int n=0, int val=0) : CObjVecNum(), v(n, val) {} CObjVecInt(const vector<int>& _v) : CObjVecNum(), v(_v) {} inline int size() const { return v.size(); } // PObj clone() const { return PObjVecInt( new CObjVecInt( *this ) ); } diff --git a/pub/lib/olf.cpp b/pub/lib/olf.cpp index 23008a1d..e403d608 100644 --- a/pub/lib/olf.cpp +++ b/pub/lib/olf.cpp @@ -127,8 +127,10 @@ void COlc::copy_meta_C_from_other(const COlc* other) kd = other->kd; weighing = other->weighing; plot_to_grid = other->plot_to_grid; - range_expr = other->range_expr; - range_T = other->range_T; + frange_expr = other->frange_expr; + frange_T = other->frange_T; + prange_expr = other->prange_expr; + prange_T = other->prange_T; chi2 = other->chi2; } @@ -637,14 +639,35 @@ RObjVec COlc::eval_curve(const vector<double>& vt, int k, int j, bool want_error RObj COlc::eval_curve_scalar(double arg, int k, int j, bool want_error) const { - vector<double> vt(1, arg); - RObjVec cu = eval_curve(vt, k, j, want_error); + RObjVec cu = eval_curve({arg}, k, j, want_error); if (cu->size() != 1) throw "BUG: vector has " + S(cu->size()) + " elements while exactly one was expected"; return cu->to_obj(0); } +//! Vectorial evaluation of a curve's prange given by an expression tree. + +RObjVecInt COlc::eval_prange(const vector<double>& vt, int k, int j) const +{ + if (!prange_T) + return RObjVecInt( new CObjVecInt(vt.size(), 1) ); + CContext ctx(k, j); + ctx.want_error = false; + RObj ret; + if (!prange_T->has_dummy()) { // curve does not depend on t + ret = prange_T->tree_val(ctx); + } else { + ctx.request_VT(&vt); + ret = prange_T->tree_val(ctx); + } + RObjVecInt ret2 = PCAST<const CObjVecInt>(ret); + if (!ret2) + throw S("BUG in eval_prange_expr: result is not an integer vector"); + return ret2; +} + + //************************************************************************************************** //* class COlc - inspect //************************************************************************************************** @@ -667,6 +690,10 @@ vector<string> COlc::info_settings() const txt += "conv file: " + S(kconv) + ", "; txt += "weighing: " + weight_str(); ret.push_back(txt); + if (frange_expr!="") + ret.push_back("fit range: " + frange_expr); + if (prange_expr!="") + ret.push_back("plot range: " + prange_expr); if (chi2 > 0) ret.push_back("global fit result: " + S(chi2)); return ret; diff --git a/pub/lib/olf.hpp b/pub/lib/olf.hpp index e343cb38..327b1f6d 100644 --- a/pub/lib/olf.hpp +++ b/pub/lib/olf.hpp @@ -118,8 +118,10 @@ public: 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. + string frange_expr; ///< Restricts points to be fitted. + string prange_expr; ///< Restricts points to be plotted. + RNode frange_T; ///< Parsed range_expr. + RNode prange_T; ///< Parsed range_expr. double chi2; ///< Global chi^2 COlc() @@ -130,7 +132,8 @@ public: , kd(-1) , weighing(_VAR) , plot_to_grid(false) - , range_expr("") + , frange_expr("") + , prange_expr("") , chi2(0) { } @@ -161,6 +164,7 @@ public: void curve_query(const string& quest); RObjVec eval_curve(const vector<double>& vt, int k, int j, bool want_error) const; RObj eval_curve_scalar(double arg, int k, int j, bool want_error) const; + RObjVecInt eval_prange(const vector<double>& vt, int k, int j) const; virtual string type() const { return "curve"; } }; diff --git a/pub/lib/plot.cpp b/pub/lib/plot.cpp index 6db000e2..68478e16 100644 --- a/pub/lib/plot.cpp +++ b/pub/lib/plot.cpp @@ -264,149 +264,56 @@ int plot_curve_equidist(CPlot* plot, const COlc* fc, int k, int j, int cstyle) return xp.size(); } +class CPt { +public: + double xd; // data point + double yd; + bool ok; + double xp; // plot point + double yp; +}; + //! Plots slice j of non-convolved curve file fc, refining the grid where necessary; //! return number of points plotted. int plot_curve_refine(CPlot* plot, const COlc* fc, int k, int j, int cstyle) { - // refinement cares to: - // - stop/start line when leaving/reentering/crossing(TODO) the frame - // - TODO interpolate when crossing the horizontal border - // - interpolate at discontinuities + auto x2p = [&](const vector<double>& x) -> vector<CPt> { + vector<double> y = PCAST<const CObjVecDbl>(fc->eval_curve(x, k, j, false))->v; + vector<int> inRange = fc->eval_prange(x, k, j)->v; + vector<CPt> ret(x.size()); + for (size_t i=0; i<x.size(); ++i) { + if (!plot->Y.contains(y[i]) || !inRange[i]) + ret[i] = {x[i], 0., false, 0., 0.}; + else + ret[i] = {x[i], y[i], true, plot->X.pc(x[i]), plot->Y.pc(y[i])}; + } + return ret; + }; - vector<double> xc, yc, xn, yn; - vector<double> novec; + vector<double> xc, yc; + vector<CPt> pc; // start with equidistant grid: int npts = plot->equipoints; plot->X.set_xgrid(xc, npts); + pc = x2p(xc); - // refinement loop: - for (int iref = 0;; ++iref) { - if (!xc.size()) { - if (!iref) - throw S("BUG: plot_curve_refine called with xc.size()=0"); - break; // regular exit - } - // evaluate curve for grid xc: - RObjVecDbl cu = PCAST<const CObjVecDbl>(fc->eval_curve(xc, k, j, false)); - for (int i = 0; i < xc.size(); ++i) - yc = cu->v; - - // merge xc,yc and xn,yn: - if (iref == 0) { - xn = xc; - yn = yc; - } else { - vector<double> xa, ya; - int ic = 0, in = 0; - for (; ic < xc.size() && in < xn.size();) { - if (plot->X.close_enough(xc[ic], xn[ic], 1e-7)) { - ++in; // skip new point - } else if (xc[ic] < xn[in]) { - xa.push_back(xc[ic]); - ya.push_back(yc[ic]); - ++ic; - } else { - xa.push_back(xn[in]); - ya.push_back(yn[in]); - ++in; - } - } - for (; ic < xc.size(); ++ic) { - xa.push_back(xc[ic]); - ya.push_back(yc[ic]); - } - for (; in < xn.size(); ++in) { - xa.push_back(xn[in]); - ya.push_back(yn[in]); - } - xn = xa; - yn = ya; - } - if (iref >= 10 || xn.size() >= plot->maxpoints) - break; // alternate exit: too many refinements or too many points - - // eliminate points outside y range (except border points): - vector<double> xa, ya; - xa.push_back(xn[0]); - ya.push_back(yn[0]); - for (int i = 1; i < xn.size() - 1; ++i) { - new_segment: - xa.push_back(xn[i]); - ya.push_back(yn[i]); - if (!plot->Y.contains(yn[i])) { - for (int ii = i + 1; ii < xn.size() - 1; ++ii) { - if (plot->Y.contains(yn[ii])) { - if (ii - 1 > i) { - xa.push_back(xn[ii - 1]); - ya.push_back(yn[ii - 1]); - } - i = ii; - goto new_segment; - } - } - } - } - xa.push_back(xn.back()); - ya.push_back(yn.back()); - xn = xa; - yn = ya; - - // set additional base points: - bool insert_next = false; - xc.clear(); - for (int i = 1; i < xn.size() - 1; ++i) { - if (i < xn.size() - 2) { - double yi = ((xn[i + 1] - xn[i]) * yn[i - 1] + (xn[i] - xn[i - 1]) * yn[i + 1]) - / (xn[i + 1] - xn[i - 1]); - if (!plot->Y.close_enough(yn[i], yi, 0.005)) { - xc.push_back((xn[i - 1] + xn[i]) / 2); - insert_next = true; - continue; - } - } - if (insert_next) { - xc.push_back((xn[i - 1] + xn[i]) / 2); - insert_next = false; - continue; - } - if ((plot->Y.contains(yn[i]) && !plot->Y.contains(yn[i - 1])) - || (!plot->Y.contains(yn[i]) && plot->Y.contains(yn[i - 1]))) { - xc.push_back((xn[i - 1] + xn[i]) / 2); - continue; - } + vector<double> xf, yf; + for (CPt p: pc) { + if (p.ok) { + xf.push_back(p.xd); + yf.push_back(p.yd); } - // temporary check - if (xc.size()) - for (int i = 0; i < xc.size() - 1; ++i) - if (xc[i + 1] <= xc[i]) - throw "BUG: new base points not sorted at " + S(i) + ": " + S(xc[i]) + " " - + S(xc[i + 1]); } - // divide into segments and plot: - vector<double> xa, ya; bool first_seg = true; - npts = 0; - for (int i = 0; i < xn.size(); ++i) { - if (plot->Y.contains(yn[i])) { - xa.push_back(xn[i]); - ya.push_back(yn[i]); - } - if (!plot->Y.contains(yn[i]) || i == xn.size() - 1) { - npts += xa.size(); - if (xa.size()) { - plot->add_spec( - true, first_seg, cstyle, xa, ya, novec, fc->V[j]->z_str(), fc->xco.str_std(), - fc->yco.str_std(), "curve file " + S(k) + " spectrum " + S(j)); - xa.clear(); - ya.clear(); - first_seg = false; - } - } - } - return npts; + if (xf.size()) + plot->add_spec( + true, first_seg, cstyle, xf, yf, vector<double>(), fc->V[j]->z_str(), fc->xco.str_std(), + fc->yco.str_std(), "curve file " + S(k) + " spectrum " + S(j)); + + return xf.size(); } -- GitLab