00001 #include "message.h"
00002 #include "parametermap.h"
00003 #include "constants.h"
00004 #include "utils.h"
00005 #include "linalg.h"
00006 #include "lsqrinvert.h"
00007 #include "bspline_imager1d.h"
00008
00009 using namespace TNT;
00010 using namespace std;
00011
00012 #define __USE_GSL__
00013
00014 #define __IMAGER_EPSILON 1e-10
00015 #define __TYPICAL_SOURCE_SCALE__ 1e-4 //in fm^-3
00016
00017
00018
00019 bool CBasisSplineImager1d::Read( const parameterMap& m ){
00020
00021 CBasisFuncImager1d::Read( m );
00022 qscale = parameter::getD(m,"qscale",50.);
00023
00024 knot_tolerance = parameter::getD(m,"knot_tolerance",1e-2);
00025 knot_init_scheme = parameter::getS(m,"knot_init_scheme","default");
00026 optimize_knots = parameter::getB(m,"optimize_knots",false);
00027 if (optimize_knots) {
00028 optimize_knots_max_iter = parameter::getB(m,"optimize_knots_max_iter",optimize_knots_max_iter);
00029 optimize_knots_minimizer_func_weight = parameter::getB(m,"optimize_knots_minimizer_func_weight",optimize_knots_minimizer_func_weight);
00030 optimize_knots_coellesce_knot_tol = parameter::getB(m,"optimize_knots_coellesce_knot_tol",optimize_knots_coellesce_knot_tol);
00031 optimize_knots_simplex_min_size = parameter::getB(m,"optimize_knots_simplex_min_size",optimize_knots_simplex_min_size);
00032 }
00033 vector< double > empty_vec(0);
00034 if (knot_init_scheme == "user_defined_collocation_points") {
00035 colloc_pts = parameter::getV(m,"user_collocation_points",empty_vec);
00036 }
00037 if (knot_init_scheme == "user_defined_knots") {
00038 user_knots = parameter::getV(m,"user_knots",empty_vec);
00039 }
00040 return true;
00041 }
00042
00043
00044
00045 bool CBasisSplineImager1d::Write( parameterMap& m ){
00046
00047 CBasisFuncImager1d::Write( m );
00048 parameter::set(m,"qscale",qscale);
00049
00050 parameter::set(m,"knot_tolerance",knot_tolerance);
00051 parameter::set(m,"knot_init_scheme",knot_init_scheme);
00052 parameter::set(m,"optimize_knots",optimize_knots);
00053 parameter::set(m,"optimize_knots_max_iter",optimize_knots_max_iter);
00054 parameter::set(m,"optimize_knots_minimizer_func_weight",optimize_knots_minimizer_func_weight);
00055 parameter::set(m,"optimize_knots_coellesce_knot_tol",optimize_knots_coellesce_knot_tol);
00056 parameter::set(m,"optimize_knots_simplex_min_size",optimize_knots_simplex_min_size);
00057 parameter::set(m,"user_collocation_points",colloc_pts);
00058 parameter::set(m,"user_knots",user_knots);
00059 return true;
00060 }
00061
00062
00064 bool CBasisSplineImager1d::convertCorrelationToSource( const CCorrFtn1dHisto& corrin, CSourceFtnBase& souout, const parameterMap& m, const CKernel* _kernelPtr ){
00065
00066 CBasisSpline1d* souPtr = dynamic_cast<CBasisSpline1d*>(&souout);
00067 if (souPtr==NULL) throw MESSAGE<<"Source argument must derive from CBasisSpline1d"<<ENDM_FATAL;
00068 bool result = CBasisFuncImager1d::convertCorrelationToSource( corrin, souout, m, _kernelPtr );
00069 if (optimize_knots && result) do_optimal_knots( *souPtr );
00070 return result;
00071 }
00072
00073
00075 bool CBasisSplineImager1d::convertSourceToCorrelation( const CSourceFtnBase& souin, CCorrFtn1dHisto& corrout, const parameterMap& m, const CKernel* _kernelPtr ){
00076
00077 return CBasisFuncImager1d::convertSourceToCorrelation( souin, corrout, m, _kernelPtr );
00078 }
00079
00080
00082 double CBasisSplineImager1d::imageit(CBasisFunctionExpansion1d& souout){
00083
00084 CBasisSpline1d* souPtr = dynamic_cast<CBasisSpline1d*>(&souout);
00085 if (souPtr==NULL) throw MESSAGE<<"Source argument must derive from CBasisSpline1d"<<ENDM_FATAL;
00086
00087
00088 double chi2 = CBasisFuncImager1d::imageit( *souPtr );
00089
00090
00091 double relerr=0.0;
00092 for (int i=0;i<souout.ndata;++i){relerr+=abs(souout.data[i]/sqrt(souout.covmtx[i][i]));}
00093
00094
00095 return chi2 + optimize_knots_minimizer_func_weight * relerr;
00096 }
00097
00098
00099 double CBasisSplineImager1d::do_optimal_knots(CBasisSpline1d& souout){
00100 #ifdef __USE_GSL__
00101
00102
00103
00104
00105
00106 cout << " Performing knot optimization"<<endl;
00107 size_t nVarKnots = ndata_sou-(spline_degree+1);
00108 const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex;
00109 gsl_multimin_fminimizer *s = NULL;
00110 gsl_vector *ss, *x;
00111 gsl_multimin_function minex_func;
00112 size_t iter = 1, i;
00113 int status;
00114 double size;
00115
00116
00117 ss = gsl_vector_alloc (nVarKnots);
00118
00119
00120 double dxKnots=(rmax)/(nVarKnots+1);
00121 gsl_vector_set_all (ss, 0.75*dxKnots);
00122
00123
00124 x = gsl_vector_alloc (nVarKnots);
00125 for (unsigned int i=0;i<nVarKnots;++i) gsl_vector_set(x, i, souout.knots[i+spline_degree+1]);
00126 cout << " Variable knots initialized"<<endl;
00127
00128
00129 minex_func.f = &static_imageit;
00130 minex_func.n = nVarKnots;
00131 minex_func.params = (void *)this;
00132 s = gsl_multimin_fminimizer_alloc (T, nVarKnots);
00133 gsl_multimin_fminimizer_set (s, &minex_func, x, ss);
00134 cout << " Simplex minimizer initialized"<<endl;
00135
00136
00137 do {
00138 iter++;
00139 status = gsl_multimin_fminimizer_iterate(s);
00140
00141 if (status) break;
00142
00143 size = gsl_multimin_fminimizer_size (s);
00144 status = gsl_multimin_test_size (size, 1e-2);
00145
00146 if (status == GSL_SUCCESS) printf ("converged to minimum at\n");
00147
00148 printf ("%5d ", int(iter));
00149 for (i = 0; i < nVarKnots; i++) printf ("%12.5e ", gsl_vector_get (s->x, i));
00150
00151 printf ("f() = %7.3f size = %.3f\n", s->fval, size);
00152 } while (status == GSL_CONTINUE && iter < 200);
00153
00154 gsl_vector_free(x);
00155 gsl_vector_free(ss);
00156 gsl_multimin_fminimizer_free (s);
00157
00158 souout.CopyState(souWork);
00159 return (double)(status);
00160
00161 #else
00162
00163 return imageit(souout);
00164
00165 #endif
00166 }
00167
00168
00173 double CBasisSplineImager1d::static_imageit(const gsl_vector *variableKnots, void* classPtr){
00174
00175 #ifdef __USE_GSL__
00176 CBasisSplineImager1d *cls = (CBasisSplineImager1d*)classPtr;
00177
00178
00179
00180 int nVarKnots=cls->ndata_sou-(cls->spline_degree+1);
00181
00182
00183 vector<double> myKnots(cls->ndata_sou+cls->spline_degree+1);
00184 for (int i=0;i<cls->spline_degree+1;++i) {
00185 myKnots[i]=cls->rmin;
00186 myKnots[cls->ndata_sou+cls->spline_degree-i]=cls->rmax;
00187 }
00188 for (int i=0;i<nVarKnots;++i) {
00189 while( (myKnots[cls->spline_degree+1+i]>cls->rmax) || (myKnots[cls->spline_degree+1+i]<cls->rmin) ) {
00190 myKnots[cls->spline_degree+1+i] =
00191 mod( abs(gsl_vector_get(variableKnots,i)), cls->rmax-cls->rmin ) + cls->rmin;
00192 }
00193 }
00194 sort(myKnots.begin(),myKnots.end());
00195
00196
00197 cls->souWork.setDim( myKnots.size() - cls->souWork.spline_degree - 1 );
00198
00199
00200 cls->souWork.knots = stl2tntVec(myKnots);
00201
00202
00203 parameterMap dummyMap;
00204 cls->set_kmtx(cls->corrwork,cls->souWork,dummyMap);
00205
00206
00207 return cls->imageit(cls->souWork);
00208
00209 #else
00210
00211 return 0.;
00212
00213 #endif
00214
00215 }
00216
00217
00219 void CBasisSplineImager1d::set_knots(CBasisSpline1d& souout){
00220
00221
00222 if (knot_init_scheme=="sampling_thm") {
00223 if (spline_degree == 0){
00224 MESSAGE << "Requesting Spline degree = 0, so using default knots\n" <<ENDM_WARN;
00225 knot_init_scheme="default";
00226 ndata_sou=std::max(std::min(ndata_corr,ndata_sou),spline_degree+1);
00227 }
00228 else if (kernel_particle1!=kernel_particle2){
00229 MESSAGE << "Sampling theorem doen't work on unlike pairs" <<ENDM_WARN;
00230 knot_init_scheme="default";
00231 }
00232 }
00233
00234
00235 if (knot_init_scheme=="default")
00236 set_knots_default(souout);
00237 else if (knot_init_scheme=="user_defined_knots")
00238 set_knots_user_defined(souout);
00239
00240 else if (knot_init_scheme=="sampling_thm") {
00241 set_colloc_sampling_thm();
00242 set_knots_from_colloc_points(souout);
00243 }
00244 else if (knot_init_scheme=="user_defined_collocation_points")
00245 set_knots_from_colloc_points(souout);
00246
00247 else
00248 set_knots_default(souout);
00249 }
00250
00251
00252 void CBasisSplineImager1d::set_knots_default( CBasisSpline1d& souout ){
00253
00254 cout << " Default source knot initialization\n";
00255
00256 ndata_sou=std::min(static_cast<int>(ndata_corr/1.5),souout.ndata);
00257 if (ndata_sou != souout.ndata){
00258 MESSAGE << "Number of coefficients requested is too big, lowering to "<<ndata_sou<<ENDM_WARN;
00259 souout.setDim( ndata_sou );
00260 }
00261 rmin = souout.xmin;
00262 rmax = souout.xmax;
00263 souout.setDefaultKnots();
00264 }
00265
00266
00267 void CBasisSplineImager1d::set_colloc_sampling_thm( void ){
00268
00269 static int maxnumzeros=40;
00270
00271 cout << " Using Sampling theorem to guess collocation points\n";
00272 cout << " Getting zeroes from kernel\n";
00273
00274
00275 vector<double> zeros(get_zeros(qscale,maxnumzeros,l));
00276
00277
00278 vector<double> tmp_rcolloc(1,rmin);
00279
00280
00281 for (int i=0;i<static_cast<int>(zeros.size());i++) {
00282 if ((zeros[i]<rmax)&&(zeros[i]>rmin)) tmp_rcolloc.push_back(zeros[i]);
00283 }
00284
00285
00286 tmp_rcolloc.push_back(rmax);
00287
00288
00289 sort(tmp_rcolloc.begin(),tmp_rcolloc.end());
00290
00291
00292 colloc_pts = tmp_rcolloc;
00293 }
00294
00295
00296 void CBasisSplineImager1d::set_knots_from_colloc_points( CBasisSpline1d& souout ){
00297
00298 cout << endl;
00299 cout << " Converting collocation points into knots\n";
00300 cout << " Pre-thin collocation points:\n";
00301 for (int i=0;i<static_cast<int>(colloc_pts.size());++i){
00302 cout <<" "<< i << " " << colloc_pts[i]<<endl;
00303 }
00304
00305
00306 vector<double> rcolloc(1,colloc_pts[0]);
00307 int nave=1;
00308 for (int i=1;i<static_cast<int>(colloc_pts.size());++i) {
00309 if (abs(colloc_pts[i]-rcolloc.back())<knot_tolerance) {
00310 rcolloc.back() = (nave/(nave+1))*(rcolloc.back()+colloc_pts[i]/nave);
00311 nave++;
00312 } else {
00313 rcolloc.push_back(colloc_pts[i]);
00314 nave=1;
00315 }
00316 }
00317 cout << " Post-thin collocation points:\n";
00318 for (int i=0;i<static_cast<int>(rcolloc.size());i++){
00319 cout << " "<<i << " " << rcolloc[i]<<endl;
00320 }
00321
00322
00323 souout.setOptimalKnots(stl2tntVec(rcolloc));
00324
00325
00326 ndata_sou = souout.ndata;
00327 }
00328
00329
00330 void CBasisSplineImager1d::set_knots_user_defined( CBasisSpline1d& souout ){
00331
00332
00333 souout.setDim(user_knots.size()-souout.spline_degree-1);
00334
00335 souout.knots = stl2tntVec(user_knots);
00336
00337
00338
00339 ndata_sou = souout.ndata;
00340 }
00341
00342
00343 bool CBasisSplineImager1d::set_no_data( CSourceFtnBase& souout ){
00344
00345 CBasisFuncImager1d::set_no_data( souout );
00346 CBasisSpline1d* souPtr = dynamic_cast<CBasisSpline1d*>(&souout);
00347 if (souPtr==NULL) throw MESSAGE<<"Source argument must derive from CBasisSpline1d"<<ENDM_FATAL;
00348 souPtr->setDefaultKnots();
00349 return true;
00350 }
00351
00352
00353 bool CBasisSplineImager1d::initialize_source( const CCorrFtn1dHisto& corrin, CSourceFtnBase& souout, const parameterMap& m ){
00354
00355 bool result = CBasisFuncImager1d::initialize_source(corrin,souout,m);
00356 CBasisSpline1d* souPtr = dynamic_cast<CBasisSpline1d*>(&souout);
00357 if (souPtr==NULL) throw MESSAGE<<"Source argument must derive from CBasisSpline1d"<<ENDM_FATAL;
00358 souPtr->Read(m);
00359 spline_degree=souPtr->spline_degree;
00360 set_knots(*souPtr);
00361 return result;
00362 }
00363
00364
00366 vector< double > CBasisSplineImager1d::get_zeros(double q, int nZeros, int l, double eps){
00367
00368 vector<double> zeros;
00369
00370
00371 double xstep=0.5/(2.0*q/HBARC);
00372
00373 double xmin = eps;
00374 double testlo;
00375 double testhi;
00376
00377 zero_struct azero;
00378
00379 while (static_cast<int>(zeros.size())<nZeros){
00380 testlo = kernelPtr->GetValue(l,q,xmin);
00381 testhi = kernelPtr->GetValue(l,q,xmin+xstep);
00382
00383
00384 if ( abs(testlo) <= eps ) {
00385 zeros.push_back(xmin);
00386 xmin+=xstep/2.0;
00387
00388 } else {
00389
00390
00391 if ( abs(testhi) <= eps ) {
00392 testlo = kernelPtr->GetValue(l,q,xmin);
00393 testhi = kernelPtr->GetValue(l,q,xmin+xstep/2.0);
00394 }
00395
00396
00397 if ( testlo*testhi <= 0.) {
00398 azero=find_zero(xmin,xmin+xstep,q,l,eps);
00399 if (azero.iszero) zeros.push_back(azero.result);
00400 }
00401 }
00402
00403
00404 xmin+=xstep;
00405 }
00406 return zeros;
00407 }
00408
00409
00412 zero_struct CBasisSplineImager1d::find_zero(double xmin, double xmax, double q, int l, double eps){
00413 int nsteps=10;
00414 double stepsize=(xmax-xmin)/nsteps,xleft,xright;
00415 zero_struct ans;
00416 for (int i=0;i<nsteps;++i){
00417 xleft=xmin+i*stepsize;
00418 xright=xleft+stepsize;
00419 if (kernelPtr->GetValue(l,q,xleft)*kernelPtr->GetValue(l,q,xright)<=0.){
00420 if (abs(xleft-xright)<eps) {
00421 ans.iszero = true;
00422 ans.result = (xleft+xright)/2.;
00423 return ans;
00424 }
00425 else return find_zero(xleft,xright,q,l,eps);
00426 }
00427 }
00428
00429
00430 ans.result=rmax;
00431 ans.iszero=false;
00432 return ans;
00433 }
00434