15 #include "nmrrelaxfit.h"
19 #include <gsl/gsl_multifit_nlin.h>
21 typedef int (exp_f) (
const gsl_vector * X,
void * PARAMS, gsl_vector * F);
22 typedef int (exp_df) (
const gsl_vector * X,
void * PARAMS, gsl_matrix * J);
23 typedef int (exp_fdf) (
const gsl_vector * X,
void * PARAMS, gsl_vector * F, gsl_matrix * J);
26 do_nlls(
int n,
int p,
double *param,
double *err,
double *det,
void *user, exp_f *ef, exp_df *edf, exp_fdf *efdf
29 #include <gsl/gsl_blas.h>
30 #include <gsl/gsl_ieee_utils.h>
53 virtual void relax(
double *f,
double *dfdt,
double t,
double it1) {
54 double rf = 0, rdf = 0;
57 for(
const Term *term = m_terms; term->p != 0; term++) {
58 double a = term->a * exp(x*term->p);
67 const struct Term *m_terms;
81 virtual void relax(
double *f,
double *dfdt,
double t,
double it1) {
82 it1 = std::max(0.0, it1);
83 double rt = pow(t * it1, m_pow);
86 *dfdt = t*rt/(t*it1)*m_pow * a;
102 {3, 3.0/7}, {10, 4.0/7}, {0, 0}
106 {3, 3.0/28}, {10, 25.0/28}, {0, 0}
110 {21,0.05303}, {10,0.64935}, {3,0.29762}, {0, 0}
114 {21,0.47727}, {10,0.41558}, {3,0.10714}, {0, 0}
118 {21,0.88384}, {10,0.10823}, {3,0.0079365}, {0, 0}
122 {3, 3.0/14}, {10, 50.0/77}, {21, 3.0/22}, {0, 0}
126 {3, 2.0/21}, {10, 25.0/154}, {21, 49.0/66}, {0, 0}
130 {3, 1.0/42}, {10, 18.0/77}, {21, 49.0/66}, {0, 0}
134 {3, 4.0/33}, {10, 80.0/143}, {21, 49.0/165}, {36, 16.0/715}, {0, 0}
138 {3, 9.0/132}, {10, 5.0/572}, {21, 441.0/660}, {36, 729.0/2860}, {0, 0}
142 {3, 1.0/33}, {10, 20.0/143}, {21, 4.0/165}, {36, 576.0/715}, {0, 0}
146 {3, 1.0/132}, {10, 45.0/572}, {21, 49.0/165}, {36, 441.0/715}, {0, 0}
154 {3,0.75}, {1,0.25}, {0, 0}
158 {1, 0.1}, {6, 0.9}, {0, 0}
161 {1, 0.4}, {6, 0.6}, {0, 0}
165 {1, 0.1}, {3, 0.5}, {6, 0.4}, {0, 0}
169 {1, 0.02857}, {6, 0.17778}, {15, 0.793667}, {0, 0}
172 {1, 0.25714}, {6, 0.266667}, {15, 0.4762}, {0, 0}
176 {1, 0.028571}, {3, 0.05357}, {6, 0.0249987}, {10, 0.4464187}, {15, 0.4463875}, {0, 0}
180 {1, 0.028571}, {3, 0.2143}, {6, 0.3996}, {10, 0.2857}, {15, 0.0714}, {0, 0}
184 {21,0.66288}, {15,0.14881}, {10,0.081169}, {6,0.083333}, {3,0.0059524}, {1,0.017857}, {0,0}
188 {21,0.23864}, {15,0.48214}, {10,0.20779}, {3,0.053571}, {1,0.017857}, {0,0}
192 {21,0.026515}, {15,0.14881}, {10,0.32468}, {6,0.33333}, {3,0.14881}, {1,0.017857}, {0,0}
196 {1, 0.0119}, {6, 0.06818}, {15, 0.20605}, {28, 0.7137375}, {0, 0}
200 {1, 0.01191}, {3, 0.05952}, {6, 0.030305}, {10, 0.17532}, {15, 0.000915}, {21, 0.26513}, {28, 0.45678}, {0, 0}
204 {28,0.11422}, {21,0.37121}, {15,0.3663}, {10,0.081169}, {6,0.0075758}, {3,0.047619}, {1,0.011905} , {0, 0}
208 {28,0.009324}, {21,0.068182}, {15,0.20604}, {10,0.32468}, {6,0.27273}, {3,0.10714}, {1,0.011905}, {0, 0}
212 {45,0.65306}, {28,0.215}, {15,0.092308}, {6,0.033566}, {1,0.0060606}, {0, 0}
216 {45,0.45352}, {36,0.30839}, {28,0.0033594}, {21,0.14848}, {15,0.016026}, {10,0.039336}, {6,0.021037}, {3,0.0037879}, {1,0.0060606}, {0, 0}
220 {45,0.14809}, {36,0.4028}, {28,0.28082}, {21,0.012121}, {15,0.064103}, {10,0.06993}, {6,0.0009324}, {3,0.015152}, {1,0.0060606}, {0, 0}
224 {45,0.020825}, {36,0.12745}, {28,0.30318}, {21,0.33409}, {15,0.14423}, {10,0.0043706}, {6,0.025699}, {3,0.034091}, {1,0.0060606}, {0, 0}
228 {45,0.0010284}, {36,0.011189}, {28,0.05375}, {21,0.14848}, {15,0.25641}, {10,0.27972}, {6,0.18275}, {3,0.060606}, {1,0.0060606}, {0, 0}
231 XRelaxFuncList::XRelaxFuncList(
const char *name,
bool runtime)
233 create<XRelaxFuncPoly>(
"NMR I=1/2",
true, s_relaxdata_nmr1);
234 create<XRelaxFuncPoly>(
"NMR I=1",
true, s_relaxdata_nmr2);
235 create<XRelaxFuncPoly>(
"NMR I=3/2 center a",
true, s_relaxdata_nmr3ca);
236 create<XRelaxFuncPoly>(
"NMR I=3/2 center b",
true, s_relaxdata_nmr3cb);
237 create<XRelaxFuncPoly>(
"NMR I=3/2 satellite",
true, s_relaxdata_nmr3s);
238 create<XRelaxFuncPoly>(
"NMR I=5/2 center a",
true, s_relaxdata_nmr5ca);
239 create<XRelaxFuncPoly>(
"NMR I=5/2 center b",
true, s_relaxdata_nmr5cb);
240 create<XRelaxFuncPoly>(
"NMR I=5/2 satellite 3/2-1/2",
true, s_relaxdata_nmr5s);
241 create<XRelaxFuncPoly>(
"NMR I=5/2 satellite 5/2-3/2",
true, s_relaxdata_nmr5s2);
242 create<XRelaxFuncPoly>(
"NMR I=3 1-0",
true, s_relaxdata_nmr6c);
243 create<XRelaxFuncPoly>(
"NMR I=3 2-1",
true, s_relaxdata_nmr6s1);
244 create<XRelaxFuncPoly>(
"NMR I=3 3-2",
true, s_relaxdata_nmr6s2);
245 create<XRelaxFuncPoly>(
"NMR I=7/2 center",
true, s_relaxdata_nmr7c);
246 create<XRelaxFuncPoly>(
"NMR I=7/2 satellite 3/2-1/2",
true, s_relaxdata_nmr7s1);
247 create<XRelaxFuncPoly>(
"NMR I=7/2 satellite 5/2-3/2",
true, s_relaxdata_nmr7s2);
248 create<XRelaxFuncPoly>(
"NMR I=7/2 satellite 7/2-5/2",
true, s_relaxdata_nmr7s3);
249 create<XRelaxFuncPoly>(
"NMR I=9/2 center",
true, s_relaxdata_nmr9c);
250 create<XRelaxFuncPoly>(
"NMR I=9/2 satellite 3/2-1/2",
true, s_relaxdata_nmr9s1);
251 create<XRelaxFuncPoly>(
"NMR I=9/2 satellite 5/2-3/2",
true, s_relaxdata_nmr9s2);
252 create<XRelaxFuncPoly>(
"NMR I=9/2 satellite 7/2-5/2",
true, s_relaxdata_nmr9s3);
253 create<XRelaxFuncPoly>(
"NMR I=9/2 satellite 9/2-7/2",
true, s_relaxdata_nmr9s4);
254 create<XRelaxFuncPoly>(
"NQR I=1",
true, s_relaxdata_nqr2);
255 create<XRelaxFuncPoly>(
"NQR I=3/2",
true, s_relaxdata_nqr3);
256 create<XRelaxFuncPoly>(
"NQR I=5/2 5/2-3/2",
true, s_relaxdata_nqr5_5);
257 create<XRelaxFuncPoly>(
"NQR I=5/2 3/2-1/2",
true, s_relaxdata_nqr5_3);
258 create<XRelaxFuncPoly>(
"NQR I=3 3-2",
true, s_relaxdata_nqr6_6);
259 create<XRelaxFuncPoly>(
"NQR I=3 2-1",
true, s_relaxdata_nqr6_4);
260 create<XRelaxFuncPoly>(
"NQR I=3 1-0",
true, s_relaxdata_nqr6_2);
261 create<XRelaxFuncPoly>(
"NQR I=7/2 7/2-5/2",
true, s_relaxdata_nqr7_7);
262 create<XRelaxFuncPoly>(
"NQR I=7/2 5/2-3/2",
true, s_relaxdata_nqr7_5);
263 create<XRelaxFuncPoly>(
"NQR I=7/2 3/2-2/1",
true, s_relaxdata_nqr7_3);
264 create<XRelaxFuncPoly>(
"NQR I=9/2 9/2-7/2",
true, s_relaxdata_nqr9_9);
265 create<XRelaxFuncPoly>(
"NQR I=9/2 7/2-5/2",
true, s_relaxdata_nqr9_7);
266 create<XRelaxFuncPoly>(
"NQR I=9/2 5/2-3/2",
true, s_relaxdata_nqr9_5);
267 create<XRelaxFuncPoly>(
"NQR I=9/2 3/2-2/1",
true, s_relaxdata_nqr9_3);
268 create<XRelaxFuncPowExp>(
"Pow.Exp.0.5: exp(-t^0.5)",
true, 0.5);
269 create<XRelaxFuncPowExp>(
"Pow.Exp.0.6: exp(-t^0.6)",
true, 0.6);
270 create<XRelaxFuncPowExp>(
"Pow.Exp.0.7: exp(-t^0.7)",
true, 0.7);
271 create<XRelaxFuncPowExp>(
"Pow.Exp.0.8: exp(-t^0.8)",
true, 0.7);
272 create<XRelaxFuncPowExp>(
"Gaussian: exp(-t^2)",
true, 2.0);
273 create<XRelaxFuncPowExp>(
"Exp.: exp(-t)",
true, 1.0);
277 XRelaxFunc::relax_f (
const gsl_vector * x,
void *params,
280 double iT1 = gsl_vector_get (x, 0);
281 double c = gsl_vector_get (x, 1);
284 if(data->is_minftyfit)
285 a = gsl_vector_get (x, 2);
287 a = data->fixed_minfty - c;
290 for(
auto it = data->pts->begin(); it != data->pts->end(); it++) {
291 if(it->isigma == 0)
continue;
293 double yi = 0, dydt = 0;
294 data->func->relax(&yi, &dydt, t, iT1);
296 gsl_vector_set (f, i, (c * yi + a - y) * it->isigma);
302 XRelaxFunc::relax_df (
const gsl_vector * x,
void *params,
306 double iT1 = gsl_vector_get (x, 0);
307 double c = gsl_vector_get (x, 1);
310 for(
auto it = data->pts->begin();
311 it != data->pts->end(); it++) {
312 if(it->isigma == 0)
continue;
314 double yi = 0, dydt = 0;
315 data->func->relax(&yi, &dydt, t, iT1);
316 gsl_matrix_set (J, i, 0, (c * dydt) * it->isigma);
317 gsl_matrix_set (J, i, 1, yi * it->isigma);
318 if(data->is_minftyfit)
319 gsl_matrix_set (J, i, 2, it->isigma);
325 XRelaxFunc::relax_fdf (
const gsl_vector * x,
void *params,
326 gsl_vector * f, gsl_matrix * J) {
328 double iT1 = gsl_vector_get (x, 0);
330 double c = gsl_vector_get (x, 1);
332 if(data->is_minftyfit)
333 a = gsl_vector_get (x, 2);
335 a = data->fixed_minfty - c;
338 for(
auto it = data->pts->begin();
339 it != data->pts->end(); it++) {
340 if(it->isigma == 0)
continue;
342 double yi = 0, dydt = 0;
343 data->func->relax(&yi, &dydt, t, iT1);
345 gsl_vector_set (f, i, (c * yi + a - y) * it->isigma);
346 gsl_matrix_set (J, i, 0, (c * dydt) * it->isigma);
347 gsl_matrix_set (J, i, 1, yi * it->isigma);
348 if(data->is_minftyfit)
349 gsl_matrix_set (J, i, 2, it->isigma);
359 double max_var = -1e90, min_var = 1e90;
360 for(
auto it = shot_this[ *
this].m_sumpts.begin(); it != shot_this[ *
this].m_sumpts.end(); it++) {
361 if(it->isigma > 0) n++;
362 max_var = std::max(max_var, it->var);
363 min_var = std::min(min_var, it->var);
366 &tr[ *
this].m_sumpts,
372 int p = nlls.is_minftyfit ? 3 : 2;
373 if(n <= p)
return formatString(
"%d",n) + i18n(
" points, more points needed.");
376 XTime firsttime = XTime::now();
378 status = do_nlls(n, p, tr[ *
this].m_params, tr[ *
this].m_errors, &norm,
379 &nlls, &XRelaxFunc::relax_f, &XRelaxFunc::relax_df, &XRelaxFunc::relax_fdf, itercnt);
380 if( !status && (fabs(tr[ *
this].m_params[1]) < (max_var - min_var) * 10))
382 if(XTime::now() - firsttime < 0.02)
continue;
383 if(XTime::now() - firsttime > 0.07)
break;
384 double p1max = shot_this[ *p1Max()];
385 double p1min = shot_this[ *
p1Min()];
386 tr[ *
this].m_params[0] = 1.0 / exp(log(p1max/p1min) * randMT19937() + log(p1min));
387 tr[ *
this].m_params[1] = (max_var - min_var) * (randMT19937() * 2.0 + 0.9) * ((randMT19937() < 0.5) ? 1 : -1);
388 tr[ *
this].m_params[2] = 0.0;
389 status = do_nlls(n, p, tr[ *
this].m_params, tr[ *
this].m_errors, &norm,
390 &nlls, &XRelaxFunc::relax_f, &XRelaxFunc::relax_df, &XRelaxFunc::relax_fdf, itercnt);
392 tr[ *
this].m_errors[0] *= norm / sqrt((
double)n);
393 tr[ *
this].m_errors[1] *= norm / sqrt((
double)n);
394 tr[ *
this].m_errors[2] *= norm / sqrt((
double)n);
396 if( !nlls.is_minftyfit)
397 tr[ *
this].m_params[2] = nlls.fixed_minfty - tr[ *
this].m_params[1];
399 double t1 = 0.001 / shot_this[ *
this].m_params[0];
400 double t1err = 0.001 / pow(shot_this[ *
this].m_params[0], 2.0) * shot_this[ *
this].m_errors[0];
402 switch(shot_this[ *
mode()]) {
405 buf += formatString(
"1/T1[1/s] = %.5g +- %.3g(%.2f%%)\n",
406 1000.0 * shot_this[ *
this].m_params[0],
407 1000.0 * shot_this[ *
this].m_errors[0],
408 fabs(100.0 * shot_this[ *
this].m_errors[0]/shot_this[ *
this].m_params[0]));
409 buf += formatString(
"T1[s] = %.5g +- %.3g(%.2f%%)\n",
410 t1, t1err, fabs(100.0 * t1err/t1));
413 buf += formatString(
"1/T2[1/ms] = %.5g +- %.3g(%.2f%%)\n",
414 1000.0 * shot_this[ *
this].m_params[0],
415 1000.0 * shot_this[ *
this].m_errors[0],
416 fabs(100.0 * shot_this[ *
this].m_errors[0]/shot_this[ *
this].m_params[0]));
417 buf += formatString(
"T2[ms] = %.5g +- %.3g(%.2f%%)\n",
418 t1, t1err, fabs(100.0 * t1err/t1));
421 buf += formatString(
"c[V] = %.5g +- %.3g(%.3f%%)\n",
422 shot_this[ *
this].m_params[1], shot_this[ *
this].m_errors[1],
423 fabs(100.0 * shot_this[ *
this].m_errors[1]/shot_this[ *
this].m_params[1]));
424 buf += formatString(
"a[V] = %.5g +- %.3g(%.3f%%)\n",
425 shot_this[ *
this].m_params[2], shot_this[ *
this].m_errors[2],
426 fabs(100.0 * shot_this[ *
this].m_errors[2]/shot_this[ *
this].m_params[2]));
427 buf += formatString(
"status = %s\n", gsl_strerror (status));
428 buf += formatString(
"rms of residuals = %.3g\n", norm / sqrt((
double)n));
429 buf += formatString(
"elapsed time = %.2f ms\n", 1000.0 * (XTime::now() - firsttime));
434 do_nlls(
int n,
int p,
double *param,
double *err,
double *det,
void *user, exp_f *ef, exp_df *edf, exp_fdf *efdf
436 const gsl_multifit_fdfsolver_type *T;
437 T = gsl_multifit_fdfsolver_lmsder;
438 gsl_multifit_fdfsolver *s;
443 gsl_multifit_function_fdf f;
445 gsl_ieee_env_setup ();
453 s = gsl_multifit_fdfsolver_alloc (T, n, p);
454 gsl_vector_view x = gsl_vector_view_array (param, p);
455 gsl_multifit_fdfsolver_set (s, &f, &x.vector);
460 status = gsl_multifit_fdfsolver_iterate (s);
465 status = gsl_multifit_test_delta (s->dx, s->x,
468 while (status == GSL_CONTINUE && iter < itercnt);
470 if(det) *det = gsl_blas_dnrm2 (s->f);
471 for(i = 0; i < p; i++)
472 param[i] = gsl_vector_get (s->x, i);
474 gsl_matrix *covar = gsl_matrix_alloc (p, p);
475 gsl_multifit_covar (s->J, 0.0, covar);
476 for(i = 0; i < p; i++) {
477 c = gsl_matrix_get(covar,i,i);
479 err[i] = (c > 0) ? sqrt(c) : -1.0;
481 gsl_matrix_free(covar);
482 gsl_multifit_fdfsolver_free (s);