diff --git a/ChangeLog b/ChangeLog index 6276e874..83ae22e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,11 @@ changes since 0.11.0 =================================== +NEW 2013-02-14 (i) adding t0 estimate for single histogram fits. The estimate + procedure is documented under doc/memos/estimateN0. + (ii) adding a more flexible preference handling in musredit. + Likely it will not ported anymore to musrgui. + (iii) adding 'recent files' to musredit. NEW 2013-01-15 adding an external spin valve related library, currently only containing a skewed Lorentzian. NEW 2013-01-07 print out the estimated time needed for the Minimize,Minos, etc. diff --git a/doc/examples/test-histo-PSI-BIN.msr b/doc/examples/test-histo-PSI-BIN.msr new file mode 100644 index 00000000..bd46acc3 --- /dev/null +++ b/doc/examples/test-histo-PSI-BIN.msr @@ -0,0 +1,76 @@ +FeSe 9p4 TF100 p107apr09_sample*1p02 +############################################################### +FITPARAMETER +# Nr. Name Value Step Pos_Error Boundaries + 1 Asy 0.2622 -0.0014 0.0014 0 0.33 + 2 Rate 0.3188 -0.0044 0.0044 + 3 Field 97.853 -0.056 0.056 0 200 + 4 Phase_L 178.95 -0.41 0.41 + 5 Phase_R 1.75 -0.40 0.39 + 6 N0_L 1097.90 -1.00 1.00 + 7 N0_R 1159.7 -1.0 1.0 + 8 Bkg_L 54.47 -0.20 0.20 + 9 Bkg_R 46.70 -0.19 0.19 + +############################################################### +THEORY +asymmetry 1 +simplExpo 2 (rate) +TFieldCos map1 fun1 (phase frequency) + +############################################################### +FUNCTIONS +fun1 = par3 * gamma_mu + +############################################################### +RUN data/deltat_pta_gpd_0423 PIE1 PSI PSI-BIN (name beamline institute data-file-format) +fittype 0 (single histogram fit) +norm 6 +backgr.fit 8 +lifetimecorrection +map 4 0 0 0 0 0 0 0 0 0 +forward 1 +#background 30 152 # estimated bkg: 49.2393 +data 165 7965 +t0 162.0 +fit 0 8.2 +packing 25 + +RUN data/deltat_pta_gpd_0423 PIE1 PSI PSI-BIN (name beamline institute data-file-format) +fittype 0 (single histogram fit) +norm 7 +backgr.fit 9 +lifetimecorrection +map 5 0 0 0 0 0 0 0 0 0 +forward 2 +#background 30 152 # estimated bkg: 43.1545 +data 205 7965 +t0 202.0 +fit 0 8.2 +packing 25 + +############################################################### +COMMANDS +SCALE_N0_BKG TRUE +MINIMIZE +MINOS +SAVE + +############################################################### +PLOT 0 (single histo plot) +runs 1 2 +range 0 7 -0.3 0.3 + +############################################################### +FOURIER +units Gauss # units either 'Gauss', 'MHz', or 'Mc/s' +fourier_power 12 +apodization NONE # NONE, WEAK, MEDIUM, STRONG +plot POWER # REAL, IMAG, REAL_AND_IMAG, POWER, PHASE +phase 8.5 +#range_for_phase_correction 50.0 70.0 +range 0.0 200.0 + +############################################################### +STATISTIC --- 2013-02-12 13:15:32 + chisq = 663.9, NDF = 515, chisq/NDF = 1.289169 diff --git a/doc/memos/estimateN0/PSI_Logo_narrow_blau.jpg b/doc/memos/estimateN0/PSI_Logo_narrow_blau.jpg new file mode 100644 index 00000000..aa253979 Binary files /dev/null and b/doc/memos/estimateN0/PSI_Logo_narrow_blau.jpg differ diff --git a/doc/memos/estimateN0/PSI_Logo_wide_blau.pdf b/doc/memos/estimateN0/PSI_Logo_wide_blau.pdf new file mode 100644 index 00000000..13482e93 Binary files /dev/null and b/doc/memos/estimateN0/PSI_Logo_wide_blau.pdf differ diff --git a/doc/memos/estimateN0/estimateN0.tex b/doc/memos/estimateN0/estimateN0.tex new file mode 100644 index 00000000..e8356c53 --- /dev/null +++ b/doc/memos/estimateN0/estimateN0.tex @@ -0,0 +1,177 @@ +% $Id$ +\documentclass[twoside]{article} + +\usepackage[english]{babel} +\usepackage{a4} +\usepackage{amssymb} +\usepackage{graphicx} +\usepackage{fancyhdr} +\usepackage{array} +\usepackage{float} +\usepackage{hyperref} +\usepackage{xspace} +\usepackage{rotating} +\usepackage{dcolumn} + +\setlength{\topmargin}{10mm} +\setlength{\topmargin}{-13mm} +% \setlength{\oddsidemargin}{0.5cm} +% \setlength{\evensidemargin}{0cm} +\setlength{\oddsidemargin}{1cm} +\setlength{\evensidemargin}{1cm} +\setlength{\textwidth}{14.5cm} +\setlength{\textheight}{23.8cm} + +\def\mathbi#1{\textbf{\em #1}} + +\pagestyle{fancyplain} +\addtolength{\headwidth}{0.6cm} +\fancyhead{}% +\fancyhead[RE,LO]{\bf Estimate $\mathbi{N}_0$}% +\fancyhead[LE,RO]{\thepage} +\cfoot{--- Andreas Suter -- \today ---} +\rfoot{\includegraphics[width=6.4cm]{PSI_Logo_wide_blau.pdf}} + +\DeclareMathAlphabet{\bi}{OML}{cmm}{b}{it} + +\newcommand{\mean}[1]{\langle #1 \rangle} +\newcommand{\lem}{LE-$\mu$SR\xspace} +\newcommand{\musr}{$\mu$SR\xspace} +\newcommand{\etal}{\emph{et al.\xspace}} +\newcommand{\ie}{\emph{i.e.\xspace}} +\newcommand{\eg}{\emph{e.g.\xspace}} + +\newcolumntype{d}[1]{D{.}{.}{#1}} + +\begin{document} + +% Header info -------------------------------------------------- +\thispagestyle{empty} +\noindent +\begin{tabular}{@{\hspace{-0.7cm}}l@{\hspace{6cm}}r} +\noindent\includegraphics[width=3.4cm]{PSI_Logo_narrow_blau.jpg} & + {\Huge\sf Memorandum} +\end{tabular} +% +\vskip 1cm +% +\begin{tabular}{@{\hspace{-0.5cm}}ll@{\hspace{4cm}}ll} +Datum: & \today & & \\[3ex] +Von: & Andreas Suter & An: & \\ +Telefon: & +41\, (0)56\, 310\, 4238 & & \\ +Raum: & WLGA / 119 & cc: & \\ +e-mail: & \verb?andreas.suter@psi.ch? & & \\ +\end{tabular} +% +\vskip 0.3cm +\noindent\hrulefill +\vskip 1cm +% + +\noindent The \musr decay histogram can be described by + +\begin{equation}\label{eq:decay} + N(t) = N_0\, e^{-t/\tau_\mu} \left[ 1 + A P(t) \right] + \mathrm{Bkg} +\end{equation} + +\noindent For single histogram fits a good initial estimate for $N_0$ is needed +in order that \textsc{Minuit2} has a chance to converge. +Here I summaries how $N_0$ can be reasonably well estimates. For all estimates, +it is assumed that rather to take Eq.(\ref{eq:decay}), +the following ansatz will be used + +\begin{equation}\label{eq:N0ansatz} + T(t) = N_0\, e^{-t/\tau_\mu} + \mathrm{Bkg}, +\end{equation} + +\noindent \ie the asymmetry is ignored all together. + + +\section*{Estimate $\mathbi{N}_0$ with free Background} + +We would like to minimize $\chi^2$, which is + +\begin{equation}\label{eq:chisq} + \chi^2 = \sum_i \frac{(D_i - T_i)^2}{\sigma_i^2} = \sum_i \frac{(D_i - +T_i)^2}{D_i}, +\end{equation} + +\noindent where $D_i$ is a histogram entry of the measured data, $T_i$ the +evaluation of Eq.(\ref{eq:N0ansatz}) at $t_i = \Delta t \cdot i$, with $\Delta +t$ the histogram time resolution. In the last step Poisson statistics is used, +\ie $\sigma_i^2 = D_i$. +In order to minimize Eq.(\ref{eq:N0ansatz}), it is sufficient that $\nabla +\chi^2 = 0 \Longrightarrow$ + +\begin{eqnarray*} + \frac{\partial \chi^2}{\partial N_0} &=& \sum_i \left[ \frac{2 (D_i - +T_i)}{D_i}\, e^{-t_i/\tau_\mu} \right] = 0 \\ + \frac{\partial \chi^2}{\partial \mathrm{Bkg}} &=& \sum_i \left[ \frac{2 (D_i - +T_i)}{D_i} \right] = 0 +\end{eqnarray*} + +\noindent With the following abbreviations + +\begin{eqnarray}\label{eq:abbrv} + x_i &=& e^{-t_i/\tau_\mu} \\ + \Delta &=& \sum_i 1/D_i \nonumber \\ + S &=& \sum_i 1 \nonumber +\end{eqnarray} + +\noindent ($S$ is the number of bins in the histogram) the background can be +written as + +\begin{equation}\label{eq:bkgEstimate} + \mathrm{Bkg} = \frac{1}{\Delta}\, \sum_i \left[ 1 - \frac{N_0}{D_i}\, x_i +\right] +\end{equation} + +\noindent and using this result, $N_0$ is + +\begin{equation}\label{eq:N0estimate} + N_0 = \frac{\displaystyle\sum_i \left[x_i \left(1-\frac{S}{D_i +\Delta}\right)\right]}{\displaystyle\sum_j \left[\frac{x_j}{D_j}\left(x_j - +\frac{1}{\Delta} \sum_k \frac{x_k}{D_k}\right)\right]}. +\end{equation} + +\noindent Eqs.(\ref{eq:bkgEstimate}) \& (\ref{eq:N0estimate}) allow to estimate +$N_0$ and Bkg. However, the results are mostly unsatisfactory since typically +$N_0$ is underestimate whereas Bkg is grossly overestimated. The reason is the +missing asymmetry term. + +\section*{Estimate $\mathbi{N}_0$ with linked Background} + +A much more robust ansatz is to link the background to $N_0$, \ie + +\begin{equation}\label{eq:N0ansatz_with_linked_bkg} + T(t) = N_0\, e^{-t/\tau_\mu} + \mathrm{Bkg} = N_0\, e^{-t/\tau_\mu} + \alpha +N_0, +\end{equation} + +\noindent where $\alpha$ is typically $0.01$ are smaller. The practical tests +show that it is mostly save to set $\alpha=0$. From + +$$ \frac{\partial \chi^2}{\partial N_0} = 0 $$ + +\noindent it follows + +\begin{equation}\label{eq:N0estimate_with_linked_bkg} + N_0 = \frac{\displaystyle\sum_i (\alpha + +x_i)}{\displaystyle\sum_i\frac{(\alpha + x_i)^2}{D_i}}. +\end{equation} + +\noindent Eq.(\ref{eq:N0estimate_with_linked_bkg}) with $\alpha < 0.01$ leads typically to +very good results. + +A closer look at Eq.(\ref{eq:N0estimate_with_linked_bkg}) reveals that there is +a principle problem. How should one deal with $D_i = 0$? There are two +possibilities: + +\begin{enumerate} + \item if $D_i = 0$, set it to $D_i = 1$. This implicitly assumes that an empty bin has an uncertainty of 1. + \item if $D_i = 0$, ignore it! +\end{enumerate} + +\noindent Currently \texttt{musrfit} ignores empty bins. + +\end{document} diff --git a/src/classes/PMsrHandler.cpp b/src/classes/PMsrHandler.cpp index 8342167c..f0e90195 100644 --- a/src/classes/PMsrHandler.cpp +++ b/src/classes/PMsrHandler.cpp @@ -52,9 +52,9 @@ using namespace std; * * \param fileName name of a msr-file. */ -PMsrHandler::PMsrHandler(const Char_t *fileName, const Bool_t writeExpectedChisq) : - fWriteExpectedChisq(writeExpectedChisq), fFileName(fileName) -{ +PMsrHandler::PMsrHandler(const Char_t *fileName, PStartupOptions *startupOptions) : + fStartupOptions(startupOptions), fFileName(fileName) +{ // init variables fMsrBlockCounter = 0; @@ -1056,8 +1056,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) if (fStatistic.fMinExpected != 0.0) { str.Form(" expected chisq = %.1lf, NDF = %d, expected chisq/NDF = %lf", fStatistic.fMinExpected, fStatistic.fNdf, fStatistic.fMinExpected/fStatistic.fNdf); - if (fWriteExpectedChisq) - fout << str.Data() << endl; + if (fStartupOptions) { + if (fStartupOptions->writeExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << endl << str.Data() << endl; @@ -1065,8 +1067,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) if (fStatistic.fNdfPerHisto[i] > 0) { str.Form(" run block %d: (NDF/red.chisq/red.chisq_e) = (%d/%lf/%lf)", i+1, fStatistic.fNdfPerHisto[i], fStatistic.fMinPerHisto[i]/fStatistic.fNdfPerHisto[i], fStatistic.fMinExpectedPerHisto[i]/fStatistic.fNdfPerHisto[i]); - if (fWriteExpectedChisq) - fout << str.Data() << endl; + if (fStartupOptions) { + if (fStartupOptions->writeExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -1076,8 +1080,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) for (UInt_t i=0; iwriteExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -1107,8 +1113,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) if (fStatistic.fMinExpected != 0.0) { str.Form(" expected chisq = %.1lf, NDF = %d, expected chisq/NDF = %lf", fStatistic.fMinExpected, fStatistic.fNdf, fStatistic.fMinExpected/fStatistic.fNdf); - if (fWriteExpectedChisq) - fout << str.Data() << endl; + if (fStartupOptions) { + if (fStartupOptions->writeExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -1116,8 +1124,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) if (fStatistic.fNdfPerHisto[i] > 0) { str.Form(" run block %d: (NDF/red.chisq/red.chisq_e) = (%d/%lf/%lf)", i+1, fStatistic.fNdfPerHisto[i], fStatistic.fMinPerHisto[i]/fStatistic.fNdfPerHisto[i], fStatistic.fMinExpectedPerHisto[i]/fStatistic.fNdfPerHisto[i]); - if (fWriteExpectedChisq) - fout << str.Data() << endl; + if (fStartupOptions) { + if (fStartupOptions->writeExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -1127,8 +1137,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) for (UInt_t i=0; iwriteExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -1180,8 +1192,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) if (fStatistic.fMinExpected != 0.0) { str.Form(" expected chisq = %.1lf, NDF = %d, expected chisq/NDF = %lf", fStatistic.fMinExpected, fStatistic.fNdf, fStatistic.fMinExpected/fStatistic.fNdf); - if (fWriteExpectedChisq) - fout << str.Data() << endl; + if (fStartupOptions) { + if (fStartupOptions->writeExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -1189,8 +1203,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) if (fStatistic.fNdfPerHisto[i] > 0) { str.Form(" run block %d: (NDF/red.chisq/red.chisq_e) = (%d/%lf/%lf)", i+1, fStatistic.fNdfPerHisto[i], fStatistic.fMinPerHisto[i]/fStatistic.fNdfPerHisto[i], fStatistic.fMinExpectedPerHisto[i]/fStatistic.fNdfPerHisto[i]); - if (fWriteExpectedChisq) - fout << str.Data() << endl; + if (fStartupOptions) { + if (fStartupOptions->writeExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -1200,8 +1216,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) for (UInt_t i=0; iwriteExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -1237,8 +1255,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) if (fStatistic.fMinExpected != 0.0) { str.Form(" expected chisq = %.1lf, NDF = %d, expected chisq/NDF = %lf", fStatistic.fMinExpected, fStatistic.fNdf, fStatistic.fMinExpected/fStatistic.fNdf); - if (fWriteExpectedChisq) - fout << str.Data() << endl; + if (fStartupOptions) { + if (fStartupOptions->writeExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -1246,8 +1266,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) if (fStatistic.fNdfPerHisto[i] > 0) { str.Form(" run block %d: (NDF/red.chisq/red.chisq_e) =(%d/%lf/%lf)", i+1, fStatistic.fNdfPerHisto[i], fStatistic.fMinExpectedPerHisto[i]/fStatistic.fNdfPerHisto[i], fStatistic.fMinExpectedPerHisto[i]/fStatistic.fNdfPerHisto[i]); - if (fWriteExpectedChisq) - fout << str.Data() << endl; + if (fStartupOptions) { + if (fStartupOptions->writeExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -1257,8 +1279,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages) for (UInt_t i=0; iwriteExpectedChisq) + fout << str.Data() << endl; + } if (messages) cout << str.Data() << endl; @@ -5127,6 +5151,34 @@ void PMsrHandler::GetGroupingString(Int_t runNo, TString detector, TString &grou grouping.clear(); } +//-------------------------------------------------------------------------- +// EstimateN0 (public) +//-------------------------------------------------------------------------- +/** + *

returns if N0 shall be estimated + */ +Bool_t PMsrHandler::EstimateN0() +{ + if (fStartupOptions == 0) + return true; + + return fStartupOptions->estimateN0; +} + +//-------------------------------------------------------------------------- +// GetAlphaEstimateN0 (public) +//-------------------------------------------------------------------------- +/** + *

returns alpha to estimate N0 + */ +Double_t PMsrHandler::GetAlphaEstimateN0() +{ + if (fStartupOptions == 0) + return 0.0; + + return fStartupOptions->alphaEstimateN0; +} + //-------------------------------------------------------------------------- // NeededPrecision (private) //-------------------------------------------------------------------------- diff --git a/src/classes/PRunSingleHisto.cpp b/src/classes/PRunSingleHisto.cpp index dd249dd8..bb56e158 100644 --- a/src/classes/PRunSingleHisto.cpp +++ b/src/classes/PRunSingleHisto.cpp @@ -37,6 +37,7 @@ #include #endif +#include #include #include using namespace std; @@ -810,6 +811,10 @@ Bool_t PRunSingleHisto::PrepareData() */ Bool_t PRunSingleHisto::PrepareFitData(PRawRunData* runData, const UInt_t histoNo) { + if (fMsrInfo->EstimateN0()) { + EstimateN0(); + } + // transform raw histo data. This is done the following way (for details see the manual): // for the single histo fit, just the rebinned raw data are copied @@ -1398,6 +1403,68 @@ Bool_t PRunSingleHisto::PrepareViewData(PRawRunData* runData, const UInt_t histo return true; } +//-------------------------------------------------------------------------- +// EstimateN0 (private) +//-------------------------------------------------------------------------- +/** + *

Estimate the N0 for the given run. + */ +void PRunSingleHisto::EstimateN0() +{ + // check that 'norm' in the msr-file run block is indeed a parameter number. + // in case it is a function, nothing will be done. + UInt_t paramNo = fRunInfo->GetNormParamNo(); + if (paramNo > 10000) // i.e. fun or map + return; + + // still missing: set this value in the parameters + PMsrParamList *param = fMsrInfo->GetMsrParamList(); + assert(param); + + if (paramNo > param->size()) { + cerr << endl << ">> PRunSingleHisto::EstimateN0: **ERROR** found parameter number " << paramNo << ", which is larger than the number of parameters = " << param->size() << endl; + return; + } + + // estimate N0 + Double_t dt = fTimeResolution; + Double_t tau = PMUON_LIFETIME; + + UInt_t t0 = (UInt_t)round(fT0s[0]); + Double_t alpha = fMsrInfo->GetAlphaEstimateN0(); + Double_t dval = 0.0; + Double_t nom = 0.0; + Double_t denom = 0.0; + Double_t xx = 0.0; + + // calc nominator + for (UInt_t i=t0; i 0) + denom += xx*xx/dval; + } + Double_t N0 = nom/denom; + + if (fScaleN0AndBkg) { + N0 /= fTimeResolution*1.0e3; + } else { + N0 *= fRunInfo->GetPacking(); + } + + cout << ">> PRunSingleHisto::EstimateN0: found N0=" << param->at(paramNo-1).fValue << ", will set it to N0=" << N0 << endl; + fMsrInfo->SetMsrParamValue(paramNo-1, N0); + fMsrInfo->SetMsrParamStep(paramNo-1, sqrt(fabs(N0))); +} + //-------------------------------------------------------------------------- // EstimatBkg (private) //-------------------------------------------------------------------------- diff --git a/src/classes/PStartupHandler.cpp b/src/classes/PStartupHandler.cpp index aeedcb48..d22ccf36 100644 --- a/src/classes/PStartupHandler.cpp +++ b/src/classes/PStartupHandler.cpp @@ -166,7 +166,9 @@ void PStartupHandler::OnStartDocument() fFourierDefaults.fPlotRange[1] = -1.0; fFourierDefaults.fPhaseIncrement = 1.0; - fWritePerRunBlockChisq = false; + fStartupOptions.writeExpectedChisq = false; + fStartupOptions.estimateN0 = true; + fStartupOptions.alphaEstimateN0 = 0.0; } //-------------------------------------------------------------------------- @@ -197,6 +199,10 @@ void PStartupHandler::OnStartElement(const Char_t *str, const TList *attributes) fKey = eDataPath; } else if (!strcmp(str, "write_per_run_block_chisq")) { fKey = eWritePerRunBlockChisq; + } else if (!strcmp(str, "estimate_n0")) { + fKey = eEstimateN0; + } else if (!strcmp(str, "alpha_estimate_n0")) { + fKey = eAlphaEstimateN0; } else if (!strcmp(str, "marker")) { fKey = eMarker; } else if (!strcmp(str, "color")) { @@ -254,7 +260,17 @@ void PStartupHandler::OnCharacters(const Char_t *str) case eWritePerRunBlockChisq: tstr = TString(str); if (tstr.BeginsWith("y") || tstr.BeginsWith("Y")) - fWritePerRunBlockChisq = true; + fStartupOptions.writeExpectedChisq = true; + break; + case eEstimateN0: + tstr = TString(str); + if (tstr.BeginsWith("n") || tstr.BeginsWith("N")) + fStartupOptions.estimateN0 = false; + break; + case eAlphaEstimateN0: + tstr = TString(str); + if (tstr.IsFloat()) + fStartupOptions.alphaEstimateN0 = tstr.Atof(); break; case eMarker: // check that str is a number diff --git a/src/external/MagProximity/PMagProximity.pdf b/src/external/MagProximity/PMagProximity.pdf new file mode 100644 index 00000000..91f122f2 Binary files /dev/null and b/src/external/MagProximity/PMagProximity.pdf differ diff --git a/src/include/PMsrHandler.h b/src/include/PMsrHandler.h index f18f92c0..5741085d 100644 --- a/src/include/PMsrHandler.h +++ b/src/include/PMsrHandler.h @@ -47,7 +47,7 @@ class PMsrHandler { public: - PMsrHandler(const Char_t *fileName, const Bool_t writeExpectedChisq=false); + PMsrHandler(const Char_t *fileName, PStartupOptions *startupOptions=0); virtual ~PMsrHandler(); virtual Int_t ReadMsrFile(); @@ -106,9 +106,11 @@ class PMsrHandler virtual void CheckMaxLikelihood(); virtual void GetGroupingString(Int_t runNo, TString detector, TString &groupingStr); + virtual Bool_t EstimateN0(); + virtual Double_t GetAlphaEstimateN0(); private: - Bool_t fWriteExpectedChisq; ///< flag shows if expected chisq shall be written to the msr-file + PStartupOptions *fStartupOptions; ///< contains information about startup options from the musrfit_startup.xml TString fFileName; ///< file name of the msr-file TString fMsrFileDirectoryPath; ///< msr-file directory path diff --git a/src/include/PMusr.h b/src/include/PMusr.h index f6785a08..800f014b 100644 --- a/src/include/PMusr.h +++ b/src/include/PMusr.h @@ -738,4 +738,14 @@ typedef struct { UInt_t idf; ///< IDF version for NeXus files. } PAny2ManyInfo; +//------------------------------------------------------------- +/** + *

Holds the informations for the any2many converter program + */ +typedef struct { + Bool_t writeExpectedChisq; ///< if set to true, expected chisq per block will be written + Bool_t estimateN0; ///< if set to true, for single histogram fits N0 will be estimated + Double_t alphaEstimateN0; ///< relates the Bkg to N0, i.e. Bkg = alpha*N0 +} PStartupOptions; + #endif // _PMUSR_H_ diff --git a/src/include/PRunSingleHisto.h b/src/include/PRunSingleHisto.h index 02c2d345..8c114cd6 100644 --- a/src/include/PRunSingleHisto.h +++ b/src/include/PRunSingleHisto.h @@ -69,6 +69,7 @@ class PRunSingleHisto : public PRunBase PDoubleVector fForward; ///< forward histo data + virtual void EstimateN0(); virtual Bool_t EstimateBkg(UInt_t histoNo); virtual Bool_t IsScaleN0AndBkg(); }; diff --git a/src/include/PStartupHandler.h b/src/include/PStartupHandler.h index da442176..36a94832 100644 --- a/src/include/PStartupHandler.h +++ b/src/include/PStartupHandler.h @@ -75,14 +75,16 @@ class PStartupHandler : public TObject, public TQObject virtual void CheckLists(); - virtual const Bool_t GetWritePerRunBlockChisq() { return fWritePerRunBlockChisq; } ///< returns the write_per_run_block_chisq flag - virtual PMsrFourierStructure GetFourierDefaults() { return fFourierDefaults; } ///< returns the Fourier defaults - virtual const PStringVector GetDataPathList() const { return fDataPathList; } ///< returns the search data path list - virtual const PIntVector GetMarkerList() const { return fMarkerList; } ///< returns the marker list - virtual const PIntVector GetColorList() const { return fColorList; } ///< returns the color list + virtual PStartupOptions* GetStartupOptions() { return &fStartupOptions; } ///< returns the startup options + virtual PMsrFourierStructure GetFourierDefaults() { return fFourierDefaults; } ///< returns the Fourier defaults + virtual const PStringVector GetDataPathList() const { return fDataPathList; } ///< returns the search data path list + virtual const PIntVector GetMarkerList() const { return fMarkerList; } ///< returns the marker list + virtual const PIntVector GetColorList() const { return fColorList; } ///< returns the color list + + virtual void SetStartupOptions(const PStartupOptions opt) { fStartupOptions = opt; } private: - enum EKeyWords {eEmpty, eComment, eDataPath, eWritePerRunBlockChisq, + enum EKeyWords {eEmpty, eComment, eDataPath, eOptions, eWritePerRunBlockChisq, eEstimateN0, eAlphaEstimateN0, eFourierSettings, eUnits, eFourierPower, eApodization, ePlot, ePhase, ePhaseIncrement, eRootSettings, eMarkerList, eMarker, eColorList, eColor}; @@ -90,11 +92,11 @@ class PStartupHandler : public TObject, public TQObject Bool_t fStartupFileFound; ///< startup file found flag TString fStartupFilePath; ///< full musrfit_startup.xml startup file paths - Bool_t fWritePerRunBlockChisq; ///< flag showing if per run block chisq and the expected chisq shall be written to the msr-file PMsrFourierStructure fFourierDefaults; ///< Fourier defaults PStringVector fDataPathList; ///< search data path list PIntVector fMarkerList; ///< marker list PIntVector fColorList; ///< color list + PStartupOptions fStartupOptions; ///< collects all startup options which will be requested by PMsrFileHandler Bool_t StartupFileExists(Char_t *fln); diff --git a/src/musredit/PAdmin.cpp b/src/musredit/PAdmin.cpp index 7bed800f..4c0b4198 100644 --- a/src/musredit/PAdmin.cpp +++ b/src/musredit/PAdmin.cpp @@ -30,8 +30,14 @@ ***************************************************************************/ #include +#include +using namespace std; #include +#include +#include +#include +#include #include "PAdmin.h" @@ -83,6 +89,18 @@ bool PAdminXMLParser::startElement( const QString&, const QString&, fKeyWord = eTitleFromDataFile; } else if (qName == "enable_musrt0") { fKeyWord = eEnableMusrT0; + } else if (qName == "keep_minuit2_output") { + fKeyWord = eKeepMinuit2Output; + } else if (qName == "dump_ascii") { + fKeyWord = eDumpAscii; + } else if (qName == "dump_root") { + fKeyWord = eDumpRoot; + } else if (qName == "estimate_n0") { + fKeyWord = eEstimateN0; + } else if (qName == "chisq_per_run_block") { + fKeyWord = eChisqPreRunBlock; + } else if (qName == "path_file_name") { + fKeyWord = eRecentFile; } else if (qName == "beamline") { fKeyWord = eBeamline; } else if (qName == "institute") { @@ -231,6 +249,45 @@ bool PAdminXMLParser::characters(const QString& str) flag = false; fAdmin->setEnableMusrT0Flag(flag); break; + case eKeepMinuit2Output: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->fMsr2DataParam.keepMinuit2Output = flag; + fAdmin->setKeepMinuit2OutputFlag(flag); + break; + case eDumpAscii: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setDumpAsciiFlag(flag); + break; + case eDumpRoot: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setDumpRootFlag(flag); + break; + case eEstimateN0: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setEstimateN0Flag(flag); + break; + case eChisqPreRunBlock: + if (str == "y") + flag = true; + else + flag = false; + fAdmin->setChisqPerRunBlockFlag(flag); + break; + case eRecentFile: + fAdmin->addRecentFile(QString(str.toLatin1()).trimmed()); + break; case eBeamline: fAdmin->setBeamline(QString(str.toLatin1()).trimmed()); break; @@ -304,13 +361,6 @@ bool PAdminXMLParser::characters(const QString& str) flag = false; fAdmin->fMsr2DataParam.ignoreDataHeaderInfo = flag; break; - case eKeepMinuit2Output: - if (str == "y") - flag = true; - else - flag = false; - fAdmin->fMsr2DataParam.keepMinuit2Output = flag; - break; case eWriteColumnData: if (str == "y") flag = true; @@ -534,7 +584,7 @@ QString PAdminXMLParser::expandPath(const QString &str) *

Initializes that PAdmin object, and calls the XML parser which feeds * the object variables. */ -PAdmin::PAdmin() +PAdmin::PAdmin() : QObject() { fTimeout = 3600; @@ -553,6 +603,8 @@ PAdmin::PAdmin() fTitleFromDataFile = false; fEnableMusrT0 = false; fLifetimeCorrection = true; + fEstimateN0 = true; + fChisqPreRunBlock = false; fMsr2DataParam.firstRun = -1; fMsr2DataParam.lastRun = -1; @@ -592,28 +644,18 @@ PAdmin::PAdmin() fln = path + "/musredit_startup.xml"; } #endif - if (QFile::exists(fln)) { // administration file present - PAdminXMLParser handler(this); - QFile xmlFile(fln); - QXmlInputSource source( &xmlFile ); - QXmlSimpleReader reader; - reader.setContentHandler( &handler ); - reader.setErrorHandler( &handler ); - if (!reader.parse( source )) { - QMessageBox::critical(0, "ERROR", - "Error parsing musredit_startup.xml settings file.\nProbably a few things will not work porperly.\nPlease fix this first.", - QMessageBox::Ok, QMessageBox::NoButton); - } - } else { - QMessageBox::critical(0, "ERROR", - "Couldn't find the musredit_startup.xml settings file.\nProbably a few things will not work porperly.\nPlease fix this first.", - QMessageBox::Ok, QMessageBox::NoButton); - } + + loadPrefs(fln); } //-------------------------------------------------------------------------- -// implementation of PAdmin class -//-------------------------------------------------------------------------- +/** + *

Destructor + */ +PAdmin::~PAdmin() +{ + saveRecentFiles(); +} //-------------------------------------------------------------------------- /** @@ -641,6 +683,21 @@ PTheory* PAdmin::getTheoryItem(const unsigned int idx) return &fTheory[idx]; } +//-------------------------------------------------------------------------- +/** + *

returns the recent path-file name at position idx. If idx is out of scope, + * an empty string is returned. + * + * \param idx index of the recent path-file name to be retrieved. + */ +QString PAdmin::getRecentFile(int idx) +{ + if (idx >= fRecentFile.size()) + return QString(""); + + return fRecentFile[idx]; +} + //-------------------------------------------------------------------------- /** *

set the help url, addressed via a tag. At the moment the following tags should be present: @@ -654,6 +711,241 @@ void PAdmin::setHelpUrl(const QString tag, const QString url) fHelpUrl[tag] = url; } +//-------------------------------------------------------------------------- +/** + *

Loads the preference file fln. + * + * return: 1 on success, 0 otherwise + * + * \param fln path-file name of the preference file to be loaded. + */ +int PAdmin::loadPrefs(QString fln) +{ + if (QFile::exists(fln)) { // administration file present + PAdminXMLParser handler(this); + QFile xmlFile(fln); + QXmlInputSource source( &xmlFile ); + QXmlSimpleReader reader; + reader.setContentHandler( &handler ); + reader.setErrorHandler( &handler ); + if (!reader.parse( source )) { + QMessageBox::critical(0, "ERROR", + "Error parsing musredit_startup.xml settings file.\nProbably a few things will not work porperly.\nPlease fix this first.", + QMessageBox::Ok, QMessageBox::NoButton); + return 0; + } + } else { + QMessageBox::critical(0, "ERROR", + "Couldn't find the musredit_startup.xml settings file.\nProbably a few things will not work porperly.\nPlease fix this first.", + QMessageBox::Ok, QMessageBox::NoButton); + return 0; + } + return 1; +} + +//-------------------------------------------------------------------------- +/** + *

Save the preference file pref_fln. + * + * return: 1 on success, 0 otherwise + * + * \param pref_fln preference path-file name + */ +int PAdmin::savePrefs(QString pref_fln) +{ + // check if musredit_startup.xml is present in the current directory, and if yes, use this file to + // save the recent file names otherwise use the "master" musredit_startup.xml + + QString str; + QString fln = "musredit_startup.xml"; + // check if it is a MacOSX +#ifdef Q_WS_MAC + fln = "./musredit_startup.xml"; + if (!QFile::exists(fln)) { + fln = "/Applications/musredit.app/Contents/Resources/musredit_startup.xml"; + } +#else + fln = "./musredit_startup.xml"; + if (!QFile::exists(fln)) { + QString path = std::getenv("MUSRFITPATH"); + QString rootsys = std::getenv("ROOTSYS"); + if (path.isEmpty()) + path = rootsys + "/bin"; + fln = path + "/musredit_startup.xml"; + } +#endif + if (QFile::exists(fln)) { // administration file present + QVector data; + QFile file(fln); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + cerr << endl << ">> PAdmin::savePrefs: **ERROR** Cannot open " << fln.toLatin1().data() << " for reading." << endl; + return 1; + } + QTextStream fin(&file); + while (!fin.atEnd()) { + data.push_back(fin.readLine()); + } + file.close(); + + // replace all the prefs + for (int i=0; i") && data[i].contains("")) { + data[i] = " " + QString("%1").arg(fTimeout) + ""; + } + if (data[i].contains("") && data[i].contains("")) { + if (fKeepMinuit2Output) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fDumpAscii) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fDumpRoot) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fTitleFromDataFile) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fChisqPreRunBlock) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fEstimateN0) + data[i] = " y"; + else + data[i] = " n"; + } + if (data[i].contains("") && data[i].contains("")) { + if (fEnableMusrT0) + data[i] = " y"; + else + data[i] = " n"; + } + } + + // write prefs + file.setFileName(pref_fln); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + cerr << endl << ">> PAdmin::savePrefs: **ERROR** Cannot open " << fln.toLatin1().data() << " for writing." << endl; + return 0; + } + fin.setDevice(&file); + for (int i=0; iAdd recent path-file name to the internal ring-buffer. + * + * \param str recent path-file name to be added + */ +void PAdmin::addRecentFile(const QString str) +{ + // check if file name is not already present + for (int i=0; i MAX_RECENT_FILES) + fRecentFile.resize(MAX_RECENT_FILES); +} + +//-------------------------------------------------------------------------- +/** + *

Merges the recent file ring buffer into musredit_startup.xml and saves it. + * If a local copy is present it will be saved there, otherwise the master file + * will be used. + */ +void PAdmin::saveRecentFiles() +{ + // check if musredit_startup.xml is present in the current directory, and if yes, use this file to + // save the recent file names otherwise use the "master" musredit_startup.xml + + QString str; + QString fln = "musredit_startup.xml"; + // check if it is a MacOSX +#ifdef Q_WS_MAC + fln = "./musredit_startup.xml"; + if (!QFile::exists(fln)) { + fln = "/Applications/musredit.app/Contents/Resources/musredit_startup.xml"; + } +#else + fln = "./musredit_startup.xml"; + if (!QFile::exists(fln)) { + QString path = std::getenv("MUSRFITPATH"); + QString rootsys = std::getenv("ROOTSYS"); + if (path.isEmpty()) + path = rootsys + "/bin"; + fln = path + "/musredit_startup.xml"; + } +#endif + if (QFile::exists(fln)) { // administration file present + QVector data; + QFile file(fln); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + cerr << endl << ">> PAdmin::saveRecentFile: **ERROR** Cannot open " << fln.toLatin1().data() << " for reading." << endl; + return; + } + QTextStream fin(&file); + while (!fin.atEnd()) { + data.push_back(fin.readLine()); + } + file.close(); + + // remove from data + for (QVector::iterator it = data.begin(); it != data.end(); ++it) { + if (it->contains("")) + it = data.erase(it); + } + + // add recent files + int i; + for (i=0; i")) + break; + } + + if (i == data.size()) { + cerr << endl << ">> PAdmin::saveRecentFile: **ERROR** " << fln.toLatin1().data() << " seems to be corrupt." << endl; + return; + } + i++; + for (int j=0; j"; + data.insert(i++, str); + } + + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + cerr << endl << ">> PAdmin::saveRecentFile: **ERROR** Cannot open " << fln.toLatin1().data() << " for reading." << endl; + return; + } + fin.setDevice(&file); + for (int i=0; i fRecentFile; ///< keep vector of recent path-file names + + bool fKeepMinuit2Output; ///< flag indicating if the Minuit2 output shall be kept (default: no) + bool fDumpAscii; ///< flag indicating if musrfit shall make an ascii-dump file (for debugging purposes, default: no). + bool fDumpRoot; ///< flag indicating if musrfit shall make an root-dump file (for debugging purposes, default: no). + bool fTitleFromDataFile; ///< flag indicating if the title should be extracted from the data file (default: yes). + bool fChisqPreRunBlock; ///< flag indicating if musrfit shall write 'per run block' chisq to the msr-file (default: no). + bool fEstimateN0; ///< flag indicating if musrfit shall estimate N0 for single histogram fits (default: yes). + bool fEnableMusrT0; ///< flag indicating if musrT0 shall be enabled at startup from within musredit (default: yes). QString fBeamline; ///< name of the beamline. Used to generate default run header lines. QString fInstitute; ///< name of the institute. Used to generate default run header lines. @@ -174,6 +200,8 @@ class PAdmin QMap fHelpUrl; ///< maps tag to help url QVector fTheory; ///< stores all known theories. Needed when generating theory blocks from within musredit. + + void saveRecentFiles(); ///< save recent file list }; #endif // _PADMIN_H_ diff --git a/src/musredit/PPrefsDialog.cpp b/src/musredit/PPrefsDialog.cpp index 65caf976..5cc88ce5 100644 --- a/src/musredit/PPrefsDialog.cpp +++ b/src/musredit/PPrefsDialog.cpp @@ -35,30 +35,23 @@ /** *

Constructor. * - * \param keep_mn2_output if true, keep the minuit2 output for each fitted msr-file, i.e. - * MINUIT2.OUTPUT -> -mn2.output, and MINUIT2.root -> -mn2.root. - * See the '-k' option of musrfit. - * \param dump_tag tag telling if dumps ('ascii' == 1, 'root' == 2) are wanted. See '--dump' option of musrfit. - * \param title_from_data_file flag telling if musrfit shall, by default, take the title from the data file. - * See the '-t' option of musrfit. - * \param enable_musrt0 if true, musrt0 is enabled from within musredit. + * \param fAdmin keeps all the needed flags */ -PPrefsDialog::PPrefsDialog(const bool keep_mn2_output, const int dump_tag, const bool title_from_data_file, - const bool enable_musrt0, const int timeout) +PPrefsDialog::PPrefsDialog(PAdmin *admin) : fAdmin(admin) { + if (!fAdmin) + return; + setupUi(this); setModal(true); - if (keep_mn2_output) - fKeepMn2Output_checkBox->setChecked(true); - else - fKeepMn2Output_checkBox->setChecked(false); + fKeepMn2Output_checkBox->setChecked(fAdmin->getKeepMinuit2OutputFlag()); - if (dump_tag == 1) { + if (fAdmin->getDumpAsciiFlag() && !fAdmin->getDumpRootFlag()) { fDumpAscii_checkBox->setChecked(true); fDumpRoot_checkBox->setChecked(false); - } else if (dump_tag == 2) { + } else if (!fAdmin->getDumpAsciiFlag() && fAdmin->getDumpRootFlag()) { fDumpAscii_checkBox->setChecked(false); fDumpRoot_checkBox->setChecked(true); } else { @@ -66,12 +59,12 @@ PPrefsDialog::PPrefsDialog(const bool keep_mn2_output, const int dump_tag, const fDumpRoot_checkBox->setChecked(false); } - fTitleFromData_checkBox->setChecked(title_from_data_file); - fEnableMusrT0_checkBox->setChecked(enable_musrt0); + fTitleFromData_checkBox->setChecked(fAdmin->getTitleFromDataFileFlag()); + fEnableMusrT0_checkBox->setChecked(fAdmin->getEnableMusrT0Flag()); + fPerRunBlockChisq_checkBox->setChecked(fAdmin->getChisqPerRunBlockFlag()); + fEstimateN0_checkBox->setChecked(fAdmin->getEstimateN0Flag()); - QString numStr; - numStr.setNum(timeout); - fTimeout_lineEdit->setText(numStr); + fTimeout_lineEdit->setText(QString("%1").arg(fAdmin->getTimeout())); fTimeout_lineEdit->setValidator(new QIntValidator(fTimeout_lineEdit)); } diff --git a/src/musredit/PPrefsDialog.h b/src/musredit/PPrefsDialog.h index 0fa08fcf..fc53f77c 100644 --- a/src/musredit/PPrefsDialog.h +++ b/src/musredit/PPrefsDialog.h @@ -34,6 +34,8 @@ #include +#include + #include "ui_PPrefsDialog.h" /** @@ -44,18 +46,22 @@ class PPrefsDialog : public QDialog, private Ui::PPrefsDialog Q_OBJECT public: - PPrefsDialog(const bool keep_mn2_output, const int dump_tag, const bool title_from_data_file, - const bool enable_musrt0, const int timeout); + PPrefsDialog(PAdmin *admin); bool getKeepMinuit2OutputFlag() { return fKeepMn2Output_checkBox->isChecked(); } bool getTitleFromDataFileFlag() { return fTitleFromData_checkBox->isChecked(); } bool getEnableMusrT0Flag() { return fEnableMusrT0_checkBox->isChecked(); } - int getDump(); + bool getKeepRunPerBlockChisqFlag() { return fPerRunBlockChisq_checkBox->isChecked(); } + bool getEstimateN0Flag() { return fEstimateN0_checkBox->isChecked(); } + int getDump(); int getTimeout() { return fTimeout_lineEdit->text().toInt(); } public slots: void dumpAscii(); void dumpRoot(); + + private: + PAdmin *fAdmin; }; #endif // _PPREFSDIALOG_H_ diff --git a/src/musredit/PTextEdit.cpp b/src/musredit/PTextEdit.cpp index ccd04a64..ef930364 100644 --- a/src/musredit/PTextEdit.cpp +++ b/src/musredit/PTextEdit.cpp @@ -10,7 +10,7 @@ *****************************************************************************/ /*************************************************************************** - * Copyright (C) 2010 by Andreas Suter * + * Copyright (C) 2010-2013 by Andreas Suter * * andreas.suter@psi.ch * * * * This program is free software; you can redistribute it and/or modify * @@ -102,11 +102,6 @@ PTextEdit::PTextEdit( QWidget *parent, Qt::WindowFlags f ) fMsr2DataParam = 0; fFindReplaceData = 0, - fKeepMinuit2Output = false; - fTitleFromDataFile = fAdmin->getTitleFromDataFileFlag(); - fEnableMusrT0 = fAdmin->getEnableMusrT0Flag(); - fDump = 0; // 0 = no dump, 1 = ascii dump, 2 = root dump - // setup menus setupFileActions(); setupEditActions(); @@ -140,9 +135,10 @@ PTextEdit::PTextEdit( QWidget *parent, Qt::WindowFlags f ) //---------------------------------------------------------------------------------------------------- /** - *

Destructor + *

This slot is called if the main application is on the way to quit. This ensures that allocated + * memory indeed can be free'd. */ -PTextEdit::~PTextEdit() +void PTextEdit::aboutToQuit() { if (fAdmin) { delete fAdmin; @@ -160,12 +156,6 @@ PTextEdit::~PTextEdit() delete fFindReplaceData; fFindReplaceData = 0; } -/* - if (fFileWatcher) { - delete fFileWatcher; - fFileWatcher = 0; - } -*/ } //---------------------------------------------------------------------------------------------------- @@ -197,6 +187,15 @@ void PTextEdit::setupFileActions() tb->addAction(a); menu->addAction(a); + fRecentFilesMenu = menu->addMenu( tr("Recent Files") ); + for (int i=0; isetVisible(false); + connect( fRecentFilesAction[i], SIGNAL(triggered()), this, SLOT(fileOpenRecent())); + fRecentFilesMenu->addAction(fRecentFilesAction[i]); + } + fillRecentFiles(); + a = new QAction( QIcon( QPixmap(":/images/filereload.xpm") ), tr( "Reload..." ), this ); a->setShortcut( tr("F5") ); a->setStatusTip( tr("Reload msr-file") ); @@ -204,6 +203,10 @@ void PTextEdit::setupFileActions() tb->addAction(a); menu->addAction(a); + a = new QAction( tr( "Open Prefs..." ), this); + connect( a, SIGNAL( triggered() ), this, SLOT( fileOpenPrefs() ) ); + menu->addAction(a); + menu->addSeparator(); a = new QAction( QIcon( QPixmap(":/images/filesave.xpm") ), tr( "&Save..." ), this ); @@ -218,6 +221,10 @@ void PTextEdit::setupFileActions() connect( a, SIGNAL( triggered() ), this, SLOT( fileSaveAs() ) ); menu->addAction(a); + a = new QAction( tr( "Save Prefs..." ), this ); + connect( a, SIGNAL( triggered() ), this, SLOT( fileSavePrefs() ) ); + menu->addAction(a); + menu->addSeparator(); a = new QAction( QIcon( QPixmap(":/images/fileprint.xpm") ), tr( "&Print..." ), this ); @@ -446,7 +453,6 @@ void PTextEdit::setupTextActions() this, SLOT( textFamily( const QString & ) ) ); QLineEdit *edit = fComboFont->lineEdit(); if (edit == 0) { -// qDebug() << endl << "**ERROR** PTextEdit::setupTextActions(): cannot edit fComboFont" << endl; return; } edit->setText( fAdmin->getFontName() ); @@ -462,7 +468,6 @@ void PTextEdit::setupTextActions() this, SLOT( textSize( const QString & ) ) ); edit = fComboSize->lineEdit(); if (edit == 0) { -// qDebug() << endl << "**ERROR** PTextEdit::setupTextActions(): cannot edit fComboSize" << endl; return; } edit->setText( QString("%1").arg(fAdmin->getFontSize()) ); @@ -545,7 +550,7 @@ void PTextEdit::setupMusrActions() connect( fMusrT0Action, SIGNAL( triggered() ), this, SLOT( musrT0() ) ); tb->addAction(fMusrT0Action); menu->addAction(fMusrT0Action); - fMusrT0Action->setEnabled(fEnableMusrT0); + fMusrT0Action->setEnabled(fAdmin->getEnableMusrT0Flag()); a = new QAction( QIcon( QPixmap( ":/images/musrprefs.xpm" ) ), tr( "&Preferences" ), this ); a->setStatusTip( tr("Show Preferences") ); @@ -615,6 +620,10 @@ void PTextEdit::load( const QString &f, const int index ) if ( !file.open( QIODevice::ReadOnly ) ) return; + // add file name to recent file names + fAdmin->addRecentFile(f); // keep it in admin + fillRecentFiles(); // update menu + // add the msr-file to the file system watchersssss fFileSystemWatcher->addPath(f); @@ -853,7 +862,6 @@ void PTextEdit::fileOpen() finfo1.setFile(*it); for (int i=0; icount(); i++) { tabFln = *fFilenames.find( dynamic_cast(fTabWidget->widget(i))); - // qDebug() << endl << "tabFln=" << tabFln; finfo2.setFile(tabFln); if (finfo1.absoluteFilePath() == finfo2.absoluteFilePath()) { alreadyOpen = true; @@ -871,6 +879,37 @@ void PTextEdit::fileOpen() } } +//---------------------------------------------------------------------------------------------------- +/** + *

This slot will open the file from the recent file list. If already open, it will reload it. + */ +void PTextEdit::fileOpenRecent() +{ + QAction *action = qobject_cast(sender()); + if (action) { + // check if this file is already open and if so, switch the tab + QFileInfo finfo1, finfo2; + QString tabFln; + bool alreadyOpen = false; + finfo1.setFile(action->text()); + + for (int i=0; icount(); i++) { + tabFln = *fFilenames.find( dynamic_cast(fTabWidget->widget(i))); + finfo2.setFile(tabFln); + if (finfo1.absoluteFilePath() == finfo2.absoluteFilePath()) { + alreadyOpen = true; + fTabWidget->setCurrentIndex(i); + break; + } + } + + if (!alreadyOpen) + load(action->text()); + else + fileReload(); + } +} + //---------------------------------------------------------------------------------------------------- /** *

Will reload the currently selected msr-file. @@ -887,6 +926,20 @@ void PTextEdit::fileReload() } } +//---------------------------------------------------------------------------------------------------- +/** + *

Will save the currently selected file. + */ +void PTextEdit::fileOpenPrefs() +{ + QString fln = QFileDialog::getOpenFileName( this, tr("Open Prefs"), + fLastDirInUse, + tr( "xml-Files (*.xml);; All Files (*)" )); + + if (fAdmin->loadPrefs(fln)) + QMessageBox::information(0, "Prefs", "Prefs Loaded."); +} + //---------------------------------------------------------------------------------------------------- /** *

Will save the currently selected file. @@ -940,6 +993,21 @@ void PTextEdit::fileSaveAs() fileSystemWatcherActivation(); // delayed activation of fFileSystemWatcherActive } +//---------------------------------------------------------------------------------------------------- +/** + *

Will save the current preferences. + */ +void PTextEdit::fileSavePrefs() +{ + QString fn = QFileDialog::getSaveFileName( this, + tr( "Save Prefs As" ), "musredit_startup.xml", + tr( "xml-Files (*.xml);;All Files (*)" ) ); + + if ( !fn.isEmpty() ) { + fAdmin->savePrefs(fn); + } +} + //---------------------------------------------------------------------------------------------------- /** *

Will call a print dialog and print the msr-file. @@ -1349,18 +1417,22 @@ void PTextEdit::editFindAndReplace() delete dlg; dlg = 0; - editFindNext(); + if (fFindReplaceData->promptOnReplace) { + editFindNext(); - PReplaceConfirmationDialog confirmDlg(this); + PReplaceConfirmationDialog confirmDlg(this); - // connect all the necessary signals/slots - QObject::connect(confirmDlg.fReplace_pushButton, SIGNAL(clicked()), this, SLOT(replace())); - QObject::connect(confirmDlg.fReplaceAndClose_pushButton, SIGNAL(clicked()), this, SLOT(replaceAndClose())); - QObject::connect(confirmDlg.fReplaceAll_pushButton, SIGNAL(clicked()), this, SLOT(replaceAll())); - QObject::connect(confirmDlg.fFindNext_pushButton, SIGNAL(clicked()), this, SLOT(editFindNext())); - QObject::connect(this, SIGNAL(close()), &confirmDlg, SLOT(accept())); + // connect all the necessary signals/slots + QObject::connect(confirmDlg.fReplace_pushButton, SIGNAL(clicked()), this, SLOT(replace())); + QObject::connect(confirmDlg.fReplaceAndClose_pushButton, SIGNAL(clicked()), this, SLOT(replaceAndClose())); + QObject::connect(confirmDlg.fReplaceAll_pushButton, SIGNAL(clicked()), this, SLOT(replaceAll())); + QObject::connect(confirmDlg.fFindNext_pushButton, SIGNAL(clicked()), this, SLOT(editFindNext())); + QObject::connect(this, SIGNAL(close()), &confirmDlg, SLOT(accept())); - confirmDlg.exec(); + confirmDlg.exec(); + } else { + replaceAll(); + } } //---------------------------------------------------------------------------------------------------- @@ -1667,25 +1739,39 @@ void PTextEdit::musrFit() cmd.append(QFileInfo(*fFilenames.find( currentEditor())).fileName() ); // check if keep minuit2 output is wished - if (fKeepMinuit2Output) + if (fAdmin->getKeepMinuit2OutputFlag()) cmd.append("--keep-mn2-output"); // check if title of the data file should be used to replace the msr-file title - if (fTitleFromDataFile) + if (fAdmin->getTitleFromDataFileFlag()) cmd.append("--title-from-data-file"); // check if dump files are wished - switch (fDump) { - case 1: // ascii dump - cmd.append("--dump"); - cmd.append("ascii"); - break; - case 2: // root dump - cmd.append("--dump"); - cmd.append("root"); - break; - default: - break; + if (fAdmin->getDumpAsciiFlag()) { + cmd.append("--dump"); + cmd.append("ascii"); + } + if (fAdmin->getDumpRootFlag()) { + cmd.append("--dump"); + cmd.append("root"); + } + + // check estimate N0 flag + if (fAdmin->getEstimateN0Flag()) { + cmd.append("--estimateN0"); + cmd.append("yes"); + } else { + cmd.append("--estimateN0"); + cmd.append("no"); + } + + // check per-run-block-chisq flag + if (fAdmin->getChisqPerRunBlockFlag()) { + cmd.append("--per-run-block-chisq"); + cmd.append("yes"); + } else { + cmd.append("--per-run-block-chisq"); + cmd.append("no"); } // add timeout @@ -1756,8 +1842,8 @@ void PTextEdit::musrMsr2Data() } // init fMsr2DataParam - fMsr2DataParam->keepMinuit2Output = fKeepMinuit2Output; - fMsr2DataParam->titleFromDataFile = fTitleFromDataFile; + fMsr2DataParam->keepMinuit2Output = fAdmin->getKeepMinuit2OutputFlag(); + fMsr2DataParam->titleFromDataFile = fAdmin->getTitleFromDataFileFlag(); PMsr2DataDialog *dlg = new PMsr2DataDialog(fMsr2DataParam, fAdmin->getHelpUrl("msr2data")); @@ -1775,8 +1861,8 @@ void PTextEdit::musrMsr2Data() int i, end; fMsr2DataParam = dlg->getMsr2DataParam(); - fKeepMinuit2Output = fMsr2DataParam->keepMinuit2Output; - fTitleFromDataFile = fMsr2DataParam->titleFromDataFile; + fAdmin->setKeepMinuit2OutputFlag(fMsr2DataParam->keepMinuit2Output); + fAdmin->setTitleFromDataFileFlag(fMsr2DataParam->titleFromDataFile); // analyze parameters switch (dlg->getRunTag()) { @@ -1943,8 +2029,6 @@ void PTextEdit::musrMsr2Data() cmd.append("new"); } -// qDebug() << endl << ">> " << cmd << endl; - PFitOutputHandler fitOutputHandler(QFileInfo(*fFilenames.find( currentEditor() )).absolutePath(), cmd); fitOutputHandler.setModal(true); fFileSystemWatcherActive = false; @@ -2145,19 +2229,31 @@ void PTextEdit::musrT0() */ void PTextEdit::musrPrefs() { - PPrefsDialog *dlg = new PPrefsDialog(fKeepMinuit2Output, fDump, fTitleFromDataFile, fEnableMusrT0, fAdmin->getTimeout()); + PPrefsDialog *dlg = new PPrefsDialog(fAdmin); + if (dlg == 0) { QMessageBox::critical(this, "**ERROR** musrPrefs", "Couldn't invoke Preferences Dialog."); return; } if (dlg->exec() == QDialog::Accepted) { - fKeepMinuit2Output = dlg->getKeepMinuit2OutputFlag(); - fTitleFromDataFile = dlg->getTitleFromDataFileFlag(); - fEnableMusrT0 = dlg->getEnableMusrT0Flag(); - fMusrT0Action->setEnabled(fEnableMusrT0); - fDump = dlg->getDump(); + fAdmin->setKeepMinuit2OutputFlag(dlg->getKeepMinuit2OutputFlag()); + fAdmin->setTitleFromDataFileFlag(dlg->getTitleFromDataFileFlag()); + fAdmin->setEnableMusrT0Flag(dlg->getEnableMusrT0Flag()); + fMusrT0Action->setEnabled(fAdmin->getEnableMusrT0Flag()); + if (dlg->getDump() == 1) { + fAdmin->setDumpAsciiFlag(true); + fAdmin->setDumpRootFlag(false); + } else if (dlg->getDump() == 2) { + fAdmin->setDumpAsciiFlag(false); + fAdmin->setDumpRootFlag(true); + } else { + fAdmin->setDumpAsciiFlag(false); + fAdmin->setDumpRootFlag(false); + } fAdmin->setTimeout(dlg->getTimeout()); + fAdmin->setChisqPerRunBlockFlag(dlg->getKeepRunPerBlockChisqFlag()); + fAdmin->setEstimateN0Flag(dlg->getEstimateN0Flag()); } delete dlg; @@ -2463,7 +2559,7 @@ void PTextEdit::fileChanged(const QString &fileName) //---------------------------------------------------------------------------------------------------- /** - *

.Delayed reactivation of file system watcher, needed when saving files. At the moment the delay + *

Delayed reactivation of file system watcher, needed when saving files. At the moment the delay * is set to 2000 ms. */ void PTextEdit::fileSystemWatcherActivation() @@ -2476,7 +2572,7 @@ void PTextEdit::fileSystemWatcherActivation() //---------------------------------------------------------------------------------------------------- /** - *

.slot needed to reactivate the file system watcher. It is called by PTextEdit::fileSystemWatcherActivation() + *

slot needed to reactivate the file system watcher. It is called by PTextEdit::fileSystemWatcherActivation() * after some given timeout. */ void PTextEdit::setFileSystemWatcherActive() @@ -2484,6 +2580,18 @@ void PTextEdit::setFileSystemWatcherActive() fFileSystemWatcherActive = true; } +//---------------------------------------------------------------------------------------------------- +/** + *

fill the recent file list in the menu. + */ +void PTextEdit::fillRecentFiles() +{ + for (int i=0; igetNumRecentFiles(); i++) { + fRecentFilesAction[i]->setText(fAdmin->getRecentFile(i)); + fRecentFilesAction[i]->setVisible(true); + } +} + //---------------------------------------------------------------------------------------------------- // END //---------------------------------------------------------------------------------------------------- diff --git a/src/musredit/PTextEdit.h b/src/musredit/PTextEdit.h index 579d53f8..6a3e9b2e 100644 --- a/src/musredit/PTextEdit.h +++ b/src/musredit/PTextEdit.h @@ -35,6 +35,11 @@ #include #include #include +#include +#include + +#include + #include "musredit.h" @@ -57,7 +62,10 @@ class PTextEdit : public QMainWindow public: PTextEdit( QWidget *parent = 0, Qt::WindowFlags f = 0 ); - virtual ~PTextEdit(); + virtual ~PTextEdit() {} + +public slots: + void aboutToQuit(); signals: void close(); @@ -90,9 +98,12 @@ private slots: void fileNew(); void fileOpen(); + void fileOpenRecent(); void fileReload(); + void fileOpenPrefs(); void fileSave(); void fileSaveAs(); + void fileSavePrefs(); void filePrint(); void fileClose( const bool check = true ); void fileCloseAll(); @@ -151,11 +162,6 @@ private: QAction *fMusrT0Action; - bool fKeepMinuit2Output; ///< 'global' flag, if set to true, musrfit calls will keep the minuit2 output files. - bool fTitleFromDataFile; ///< 'global' flag, if set to true, musrfit will take the title from the data file instead of the msr-file. - bool fEnableMusrT0; ///< 'global' flag, if set to true, musrt0 will be enabled - int fDump; ///< 'global' tag for musrfit calls: 0 == no dump, 1 == ascii dump, 2 == root dump - PMsr2DataParam *fMsr2DataParam; ///< structure holding the necessary input information for msr2data PFindReplaceData *fFindReplaceData; ///< structure holding the ncessary input for find/replace @@ -165,6 +171,11 @@ private: QTabWidget *fTabWidget; ///< tab widget in which the text editor(s) are placed QMap fFilenames; ///< mapper between tab widget object and filename + + QMenu *fRecentFilesMenu; ///< recent file menu + QAction *fRecentFilesAction[MAX_RECENT_FILES]; ///< array of the recent file actions + + void fillRecentFiles(); }; diff --git a/src/musredit/forms/PPrefsDialog.ui b/src/musredit/forms/PPrefsDialog.ui index 753b0d3a..c77f5d71 100644 --- a/src/musredit/forms/PPrefsDialog.ui +++ b/src/musredit/forms/PPrefsDialog.ui @@ -33,13 +33,13 @@ - 0 + 1 general - + 10 @@ -131,6 +131,32 @@ take title from data file + + + + 170 + 35 + 191 + 22 + + + + keep per run block chisq + + + + + + 170 + 60 + 161 + 22 + + + + estimate N0 + + diff --git a/src/musredit/main.cpp b/src/musredit/main.cpp index 3742d01c..053f43bb 100644 --- a/src/musredit/main.cpp +++ b/src/musredit/main.cpp @@ -39,7 +39,7 @@ using namespace std; /** *

musredit is a simple editor based interface to the musrfit programs. It is based on Qt 4.6 - * of Nokia (http://qt.nokia.com). + * of Digia (http://qt.digia.com and http://qt-project.org/). * *

musredit is free software liensenced under GPL 2 or later (for detail license informations see * http://www.gnu.org/licenses). @@ -64,11 +64,12 @@ int main( int argc, char ** argv ) QApplication a( argc, argv ); - PTextEdit * mw = new PTextEdit(); + PTextEdit *mw = new PTextEdit(); mw->setWindowTitle( "MusrFit Editor" ); mw->resize( 800, 800 ); mw->show(); a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) ); + a.connect( &a, SIGNAL( aboutToQuit() ), mw, SLOT( aboutToQuit() ) ); return a.exec(); } diff --git a/src/musredit/musredit.h b/src/musredit/musredit.h index 528b8412..42b06152 100644 --- a/src/musredit/musredit.h +++ b/src/musredit/musredit.h @@ -34,6 +34,8 @@ #include +#define MAX_RECENT_FILES 5 + //------------------------------------------------------------------------------------------------- /** *

This structure is used in conjunction to msr2data. It stores the necessary diff --git a/src/musrfit.cpp b/src/musrfit.cpp index 7b335fac..f15c33b2 100644 --- a/src/musrfit.cpp +++ b/src/musrfit.cpp @@ -89,6 +89,7 @@ void* musrfit_timeout(void *args) void musrfit_syntax() { cout << endl << "usage: musrfit [ [-k, --keep-mn2-ouput] [-c, --chisq-only] [-t, --title-from-data-file]"; + cout << endl << " [-e, --estimateN0 ] [-p, --per-run-block-chisq ]"; cout << endl << " [--dump ] [--timeout ] | --version | --help"; cout << endl << " : msr input file"; cout << endl << " 'musrfit ' will execute musrfit"; @@ -104,6 +105,9 @@ void musrfit_syntax() cout << endl << " -t, --title-from-data-file: will replace the run title by the"; cout << endl << " run title of the FIRST run of the run block, if a run title"; cout << endl << " is present in the data file."; + cout << endl << " -e, --estimateN0: estimate N0 for single histogram fits flag. can have the values 'yes' or 'no'."; + cout << endl << " -p, --per-run-block-chisq: will write per run block chisq to the msr-file."; + cout << endl << " can have the values 'yes' or 'no'."; cout << endl << " --dump is writing a data file with the fit data and the theory"; cout << endl << " can be 'ascii', 'root'"; cout << endl << " --timeout : overwrites to predefined timeout of " << timeout << " (sec)."; @@ -387,6 +391,10 @@ int main(int argc, char *argv[]) bool chisq_only = false; bool title_from_data_file = false; bool timeout_enabled = true; + PStartupOptions startup_options; + startup_options.writeExpectedChisq = false; + startup_options.estimateN0 = true; + startup_options.alphaEstimateN0 = 0.0; TString dump(""); char filename[1024]; @@ -432,6 +440,41 @@ int main(int argc, char *argv[]) dump = TString(argv[i+1]); i++; } else { + cerr << endl << "musrfit: **ERROR** found option --dump without " << endl; + show_syntax = true; + break; + } + } else if (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--estimateN0")) { + if (i with unsupported = " << argv[i+1] << endl; + show_syntax = true; + break; + } + i++; + } else { + cerr << endl << "musrfit: **ERROR** found option --estimateN0 without " << endl; + show_syntax = true; + break; + } + } else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--per-run-block-chisq")) { + if (i with unsupported = " << argv[i+1] << endl; + show_syntax = true; + break; + } + i++; + } else { + cerr << endl << "musrfit: **ERROR** found option --per-run-block-chisq without " << endl; show_syntax = true; break; } @@ -445,11 +488,13 @@ int main(int argc, char *argv[]) cout << endl << ">> musrfit: timeout disabled." << endl; } } else { + cerr << endl << "musrfit: **ERROR** found option --timeout with unsupported = " << argv[i+1] << endl; show_syntax = true; break; } i++; } else { + cerr << endl << "musrfit: **ERROR** found option --timeout without " << endl; show_syntax = true; break; } @@ -474,6 +519,7 @@ int main(int argc, char *argv[]) if (!dump.IsNull()) { dump.ToLower(); if (!dump.Contains("ascii") && !dump.Contains("root")) { + cerr << endl << "musrfit: **ERROR** found option --dump with unsupported = " << dump << endl; musrfit_syntax(); return PMUSR_WRONG_STARTUP_SYNTAX; } @@ -517,9 +563,10 @@ int main(int argc, char *argv[]) } } } + startupHandler->SetStartupOptions(startup_options); // read msr-file - PMsrHandler *msrHandler = new PMsrHandler(filename, startupHandler->GetWritePerRunBlockChisq()); + PMsrHandler *msrHandler = new PMsrHandler(filename, startupHandler->GetStartupOptions()); status = msrHandler->ReadMsrFile(); if (status != PMUSR_SUCCESS) { switch (status) { diff --git a/src/musrfit_startup.xml b/src/musrfit_startup.xml index b06da4e7..c2d6650a 100644 --- a/src/musrfit_startup.xml +++ b/src/musrfit_startup.xml @@ -14,7 +14,11 @@ /afs/psi.ch/project/bulkmusr/data/ltf /afs/psi.ch/project/bulkmusr/data/alc /afs/psi.ch/project/bulkmusr/data/hifi - n + + n + yes + 0.0 + Gauss 0