FOX/ObjCryst++  1.10.X (development)
LSQNumObj.cpp
1 /* ObjCryst++ Object-Oriented Crystallographic Library
2  (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net
3  2000-2001 University of Geneva (Switzerland)
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include "ObjCryst/Quirks/VFNStreamFormat.h"
20 
21 #include "ObjCryst/RefinableObj/LSQNumObj.h"
22 
23 #ifdef __WX__CRYST__
24  #include "ObjCryst/wxCryst/wxLSQ.h"
25 #endif
26 
27 #include "newmat/newmatap.h" //for SVD decomposition
28 #include "newmat/newmatio.h"
29 
30 #ifdef use_namespace
31 using namespace NEWMAT;
32 #endif
33 using namespace std;
34 
35 #include <iomanip>
36 
37 namespace ObjCryst
38 {
39 
40 LSQNumObj::LSQNumObj(string objName)
41 #ifdef __WX__CRYST__
42 :mpWXCrystObj(0)
43 #endif
44 {
45  mDampingFactor=1.;
46  mSaveReportOnEachCycle=false;
47  mName=objName;
48  mSaveFileName="LSQrefinement.save";
49  mR=0;
50  mRw=0;
51  mChiSq=0;
52  mStopAfterCycle=false;
53 }
54 
55 LSQNumObj::~LSQNumObj()
56 {
57  #ifdef __WX__CRYST__
58  this->WXDelete();
59  #endif
60 }
61 
62 void LSQNumObj::SetParIsFixed(const string& parName,const bool fix)
63 {
64  if(mRefParList.GetNbPar()==0) this->PrepareRefParList();
65  mRefParList.SetParIsFixed(parName,fix);
66 }
67 void LSQNumObj::SetParIsFixed(const RefParType *type,const bool fix)
68 {
69  if(mRefParList.GetNbPar()==0) this->PrepareRefParList();
70  mRefParList.SetParIsFixed(type,fix);
71 }
72 
73 void LSQNumObj::SetParIsFixed(RefinablePar &par,const bool fix)
74 {
75  if(mRefParList.GetNbPar()==0) this->PrepareRefParList();
76  mRefParList.GetPar(par.GetPointer()).SetIsFixed(fix);
77 }
78 
79 void LSQNumObj::SetParIsFixed(RefinableObj &obj,const bool fix)
80 
81 {
82  if(mRefParList.GetNbPar()==0) this->PrepareRefParList();
83  for(unsigned int i=0;i<obj.GetNbPar();++i)
84  this->SetParIsFixed(obj.GetPar(i),fix);
85 }
86 
87 void LSQNumObj::UnFixAllPar()
88 {
89  if(mRefParList.GetNbPar()==0) this->PrepareRefParList();
90  mRefParList.UnFixAllPar();
91 }
92 
93 void LSQNumObj::SetParIsUsed(const string& parName,const bool use)
94 {
95  if(mRefParList.GetNbPar()==0) this->PrepareRefParList();
96  mRefParList.SetParIsUsed(parName,use);
97 }
98 void LSQNumObj::SetParIsUsed(const RefParType *type,const bool use)
99 {
100  if(mRefParList.GetNbPar()==0) this->PrepareRefParList();
101  mRefParList.SetParIsUsed(type,use);
102 }
103 
104 void LSQNumObj::Refine (int nbCycle,bool useLevenbergMarquardt,
105  const bool silent, const bool callBeginEndOptimization,
106  const float minChi2var)
107 {
108  TAU_PROFILE("LSQNumObj::Refine()","void ()",TAU_USER);
109  TAU_PROFILE_TIMER(timer1,"LSQNumObj::Refine() 1 - Init","", TAU_FIELD);
110  TAU_PROFILE_TIMER(timer2,"LSQNumObj::Refine() 2 - LSQ Deriv","", TAU_FIELD);
111  TAU_PROFILE_TIMER(timer3,"LSQNumObj::Refine() 3 - LSQ MB","", TAU_FIELD);
112  TAU_PROFILE_TIMER(timer4,"LSQNumObj::Refine() 4 - LSQ Singular Values","", TAU_FIELD);
113  TAU_PROFILE_TIMER(timer5,"LSQNumObj::Refine() 5 - LSQ Newmat, eigenvalues...","", TAU_FIELD);
114  TAU_PROFILE_TIMER(timer6,"LSQNumObj::Refine() 6 - LSQ Apply","", TAU_FIELD);
115  TAU_PROFILE_TIMER(timer7,"LSQNumObj::Refine() 7 - LSQ Finish","", TAU_FIELD);
116  TAU_PROFILE_START(timer1);
117  if(callBeginEndOptimization) this->BeginOptimization();
118  mObs=this->GetLSQObs();
119  mWeight=this->GetLSQWeight();
120 
121  bool terminateOnDeltaChi2=false;
122  if(nbCycle<0)
123  {
124  nbCycle=-nbCycle;
125  terminateOnDeltaChi2=true;
126  }
127 
128  if(!silent) cout << "LSQNumObj::Refine():Beginning "<<endl;
129  //Prepare for refinement (get non-fixed parameters)
130  if(mRefParList.GetNbPar()==0) this->PrepareRefParList();
131  mRefParList.PrepareForRefinement();
132  //if(!silent) mRefParList.Print();
133  if(mRefParList.GetNbPar()==0) throw ObjCrystException("LSQNumObj::Refine():no parameter to refine !");
134 
135  //variables
136  long nbVar=mRefParList.GetNbParNotFixed();
137  const long nbObs=mObs.numElements();
138  CrystVector_REAL calc,calc0,calc1,tmpV1,tmpV2;
139  CrystMatrix_REAL M(nbVar,nbVar);
140  CrystMatrix_REAL N(nbVar,nbVar);
141  CrystVector_REAL B(nbVar);
142  CrystMatrix_REAL designMatrix(nbVar,nbObs);
143  CrystVector_REAL deltaVar(nbVar);
144  long i,j,k;
145  REAL R_ini,Rw_ini;
146  REAL *pTmp1,*pTmp2;
147 
148  REAL marquardt=1e-2;
149  const REAL marquardtMult=4.;
150  //initial Chi^2, needed for Levenberg-Marquardt
151  {
152  calc=this->GetLSQCalc();
153  tmpV1 = mObs;
154  tmpV1 -= calc;
155  tmpV1 *= tmpV1;
156  tmpV1 *= mWeight;
157  mChiSq=tmpV1.sum();
158  }
159  //store old values
160  mIndexValuesSetInitial=mRefParList.CreateParamSet("LSQ Refinement-Initial Values");
161  mIndexValuesSetLast=mRefParList.CreateParamSet("LSQ Refinement-Last Cycle Values");
162  TAU_PROFILE_STOP(timer1);
163  //refine
164  for(int cycle=1 ; cycle <=nbCycle;cycle++)
165  {
166  TAU_PROFILE_START(timer2);
167  const REAL ChisSqPreviousCycle=mChiSq;
168  mRefParList.SaveParamSet(mIndexValuesSetLast);// end of last cycle
169  if(!silent) cout << "LSQNumObj::Refine():Cycle#"<< cycle <<endl;
170  //initial value of function
171  calc0=this->GetLSQCalc();
172  //R
173  tmpV1 = mObs;
174  tmpV1 -= calc0;
175  tmpV1 *= tmpV1;
176  tmpV2 = mObs;
177  tmpV2 *= mObs;
178  R_ini=sqrt(tmpV1.sum()/tmpV2.sum());
179  //Rw
180  tmpV1 *= mWeight;
181  tmpV2 *= mWeight;
182  Rw_ini=sqrt(tmpV1.sum()/tmpV2.sum());
183  //derivatives
184  //designMatrix=0.;
185  pTmp2=designMatrix.data();
186  //cout <<"obs:"<<FormatHorizVector<REAL>(calc0,10,8);
187  //cout <<"calc:"<<FormatHorizVector<REAL>(mObs,10,8);
188  //cout <<"weight:"<<FormatHorizVector<REAL>(mWeight,10,8);
189  #if 1
190  for(i=0;i<nbVar;i++)
191  {
192  //:NOTE: Real design matrix is the transposed of the one computed here
193  //if(!silent) cout << "........." << mRefParList.GetParNotFixed(i).GetName() <<endl;
194 
195  tmpV1=this->GetLSQDeriv(mRefParList.GetParNotFixed(i));
196  pTmp1=tmpV1.data();
197  //cout <<"deriv#"<<i<<":"<<FormatHorizVector<REAL>(tmpV1,10,8);
198  for(j=0;j<nbObs;j++) *pTmp2++ = *pTmp1++;
199  }
200  #else
201  this->GetLSQ_FullDeriv();
202  for(i=0;i<nbVar;i++)
203  {
204  pTmp1=mLSQ_FullDeriv[&(mRefParList.GetParNotFixed(i))].data();
205  //if(i>=(nbVar-2)) cout<<__FILE__<<":"<<__LINE__<<":"<<(mRefParList.GetParNotFixed(i)).GetName()<<"size="<<mLSQ_FullDeriv[&(mRefParList.GetParNotFixed(i))].size()<<":"<<mLSQ_FullDeriv[&(mRefParList.GetParNotFixed(i))]<<endl;
206  for(j=0;j<nbObs;j++) *pTmp2++ = *pTmp1++;
207  }
208  #endif
209  //cout << designMatrix;
210 
211  TAU_PROFILE_STOP(timer2);
212  LSQNumObj_Refine_Restart: //Used in case of singular matrix
213  TAU_PROFILE_START(timer3);
214 
215  //Calculate M and B matrices
216  tmpV1.resize(nbObs);
217  tmpV2.resize(nbObs);
218  for(i=0;i<nbVar;i++)
219  {
220  #if 1
221  {
222  const register REAL * RESTRICT pD=designMatrix.data()+i*designMatrix.cols();
223  const register REAL * RESTRICT pW=mWeight.data();
224  REAL * RESTRICT p=tmpV1.data();
225  for(k=0;k<nbObs;k++) *p++ = *pD++ * *pW++;
226  }
227  const register REAL * pD=designMatrix.data();
228  for(j=0;j<nbVar;j++)
229  {
230  const register REAL * p1=tmpV1.data();
231  REAL v2=0;
232  for(k=0;k<nbObs;k++) v2+= *pD++ * *p1++;
233  M(j,i)=v2;
234  }
235  REAL b=0;
236  const register REAL * pObs=mObs.data();
237  const register REAL * pCalc=calc0.data();
238  const register REAL * p1=tmpV1.data();
239  for(k=0;k<nbObs;k++) b+= (*pObs++ - *pCalc++)* *p1++;
240  B(i)=b;
241  #else
242  for(k=0;k<nbObs;k++) tmpV1(k)=designMatrix(i,k);
243  tmpV1 *= mWeight;
244  for(j=0;j<nbVar;j++)
245  {
246  for(k=0;k<nbObs;k++) tmpV2(k)=designMatrix(j,k);
247  tmpV2 *= tmpV1;
248  M(j,i)= tmpV2.sum();
249  //M(i,j)=total(designMatrix.row(i)*designMatrix.row(j)*weight);
250  }
251  tmpV2=mObs;
252  tmpV2 -= calc0;
253  tmpV2 *= tmpV1;
254  B(i)=tmpV2.sum();//total((obs-calc0)*weight*designMatrix.row(i))
255  #endif
256 
257  }
258  TAU_PROFILE_STOP(timer3);
259  bool increaseMarquardt=false;
260  LSQNumObj_Refine_RestartMarquardt: //Used in case of singular matrix or for Marquardt
261  TAU_PROFILE_START(timer4);
262 
263  //Apply LevenBerg-Marquardt factor
264  if(true==useLevenbergMarquardt)
265  {
266  const REAL marquardtOLD=marquardt;
267  if(increaseMarquardt) marquardt=marquardt*marquardtMult;
268  const REAL lmfact=(1+marquardt)/(1+marquardtOLD);
269  for(i=0;i<nbVar;i++) M(i,i) *= lmfact;
270  }
271  // Check for singular values
272  for(i=0;i<nbVar;i++)
273  {
274  //cout<<__FILE__<<":"<<__LINE__<<":"<<i<<":"<<mRefParList.GetParNotFixed(i).GetName()<<":"<<mRefParList.GetParNotFixed(i).GetPointer()<<":"<<M(i,i)<<endl;
275  if( (M(i,i) < 1e-20)||(ISNAN_OR_INF(M(i,i)))) //:TODO: Check what value to use as a limit
276  {
277  if(!silent) cout << "LSQNumObj::Refine() Singular parameter !"
278  << "(null derivate in all points) : "<<M(i,i)<<":"
279  << mRefParList.GetParNotFixed(i).GetName() << endl;
280  /*
281  if(!silent)
282  {
283  for(i=0;i<nbVar;i++)
284  {
285  tmpV1=this->GetLSQDeriv(mRefParList.GetParNotFixed(i));
286  cout <<"deriv#"<<i<<":"<<FormatHorizVector<REAL>(tmpV1,10,8);
287  }
288  }
289  */
290  if(!silent) cout << "LSQNumObj::Refine(): Automatically fixing parameter";
291  if(!silent) cout << " and re-start cycle..";
292  if(!silent) cout << endl;
293  mRefParList.GetParNotFixed(i).SetIsFixed(true);
294  mRefParList.PrepareForRefinement();
295  nbVar=mRefParList.GetNbParNotFixed();
296  if(nbVar<=1)
297  {
298  mRefParList.RestoreParamSet(mIndexValuesSetInitial);
299  if(callBeginEndOptimization) this->EndOptimization();
300  if(!silent) mRefParList.Print();
301  throw ObjCrystException("LSQNumObj::Refine(): not enough (1) parameters after fixing one...");
302  }
303  N.resize(nbVar,nbVar);
304  deltaVar.resize(nbVar);
305 
306  //Just remove the ith line in the design matrix
307  REAL *p1=designMatrix.data();
308  const REAL *p2=designMatrix.data();
309  p1 += i*nbObs;
310  p2 += i*nbObs+nbObs;
311  for(long j=i*nbObs+nbObs;j<nbObs*nbVar;j++) *p1++ = *p2++;
312  designMatrix.resizeAndPreserve(nbVar,nbObs);
313 
314  //:TODO: Make this work...
315  /*
316  //Remove ith line &Column in M & ith element in B
317  p1=M.data();
318  p2=M.data();
319  for(long j=0;j<=nbVar;j++)
320  {
321  if( (j>=i) && (j<nbVar) ) B(j)=B(j+1);
322  for(long k=0;k<=nbVar;k++)
323  {
324  if((j==i) || (k==i)) p2++;
325  else *p1++ = *p2++;
326  }
327  }
328  M.resizeAndPreserve(nbVar,nbVar);
329  B.resizeAndPreserve(nbVar);
330  */
331  M.resize(nbVar,nbVar);
332  B.resize(nbVar);
333  TAU_PROFILE_STOP(timer4);
334  goto LSQNumObj_Refine_Restart;
335  }
336  }
337  TAU_PROFILE_STOP(timer4);
338 
339 /*
340  //Solve with Singular value Decomposition on design matrix (using newmat)
341  {
342  cout << "LSQNumObj::Refine():Performing SVD on design matrix..." << endl;
343  Matrix newmatA(nbObs,nbVar), newmatU(nbObs,nbVar), newmatV(nbVar,nbVar);
344  DiagonalMatrix newmatW(nbVar);
345  ColumnVector newmatB(nbObs);
346 
347  CrystMatrix_REAL U(nbVar,nbObs), V(nbVar,nbVar);
348  CrystVector_REAL W(nbVar),invW(nbVar);
349  for(long i=0;i<nbVar;i++)
350  {
351  for(long j=0;j<nbObs;j++)
352  newmatA(j+1,i+1) = designMatrix(i,j);//design matrix (need to transpose)
353  }
354 
355  for(long j=0;j<nbObs;j++) newmatB(j+1)=mObs(j)-calc0(j);
356 
357  SVD(newmatA,newmatW,newmatU,newmatV);
358 
359  ColumnVector newmatDelta(nbVar);
360  DiagonalMatrix newmatInvW(nbVar);
361  REAL max=newmatW.MaximumAbsoluteValue();
362  REAL minAllowedValue=1e-16*max;// :TODO: Check if reasonable !
363  //Avoid singular values,following 'Numerical Recipes in C'
364  for(long i=0;i<nbVar;i++)
365  if(newmatW(i+1,i+1) > minAllowedValue) newmatInvW(i+1,i+1) = 1./newmatW(i+1,i+1);
366  else
367  {
368  cout << "LSQNumObj::Refine():SVD: fixing singular value "<< i <<endl;
369  newmatInvW(i+1,i+1) = 0.;
370  }
371  newmatDelta=newmatV * newmatInvW * newmatU.t() * newmatB;
372 
373  for(long i=0;i<nbVar;i++)
374  {
375  W(i)=newmatW(i+1,i+1);
376  invW(i)=newmatInvW(i+1,i+1);
377  deltaVar(i)=newmatDelta(i+1);
378  }
379  cout << newmatW << endl;
380  }
381 */
382  TAU_PROFILE_START(timer5);
383  //Perform "Eigenvalue Filtering" on normal matrix (using newmat library)
384  {
385  //if(!silent) cout << "LSQNumObj::Refine():Eigenvalue Filtering..." <<endl;
386  CrystMatrix_REAL V(nbVar,nbVar);
387  CrystVector_REAL invW(nbVar);//diagonal matrix, in fact
388  //if(!silent) cout << "LSQNumObj::Refine():Eigenvalue Filtering...1" <<endl;
389  {
390  SymmetricMatrix newmatA(nbVar);
391  Matrix newmatV(nbVar,nbVar),
392  newmatN(nbVar,nbVar);
393  DiagonalMatrix newmatW(nbVar);
394  ColumnVector newmatB(nbVar);
395  //'Derivative scaling' matrix
396  DiagonalMatrix newmatDscale(nbVar);
397  for(long i=0;i<nbVar;i++)
398  newmatDscale(i+1,i+1) = 1./sqrt(M(i,i));
399  for(long i=0;i<nbVar;i++)
400  {
401  newmatB(i+1)=B(i);//NOT scaled
402  for(long j=0;j<nbVar;j++)
403  newmatA(i+1,j+1) = M(i,j) * newmatDscale(i+1,i+1) * newmatDscale(j+1,j+1);
404  }
405  //if(!silent) cout << "LSQNumObj::Refine():Eigenvalue Filtering...2" <<endl;
406 
407  //cout << newmatA.SubMatrix(1,3,1,3) <<endl;
408  //if(!silent) cout << "LSQNumObj::Refine():Eigenvalue Filtering...3" <<endl;
409 
410  //Jacobi(newmatA,newmatW,newmatV);
411  try
412  {
413  EigenValues(newmatA,newmatW,newmatV);
414  }
415  catch(...)
416  {
417  cout<<"Caught a Newmat exception :"<<BaseException::what()<<endl;
418  cout<<"A:"<<endl<<newmatA<<endl<<"W:"<<endl<<newmatW<<endl<<"V:"<<endl<<newmatV<<endl<<"Dscale:"<<newmatDscale*1e6<<endl;
419  cout<<setw(5)<<"B:"<<endl;
420  for(unsigned int i=0;i<B.size();i++) cout<<B(i)<<" ";
421  cout<<endl<<endl<<"M:"<<endl;
422  for(unsigned int i=0;i<M.rows();i++)
423  {
424  for(unsigned int j=0;j<M.cols();j++) cout<<M(i,j)<<" ";
425  cout<<endl;
426  }
427  cout<<endl<<endl<<"D:"<<endl;
428  for(unsigned int i=0;i<designMatrix.rows();i++)
429  {
430  for(unsigned int j=0;j<designMatrix.cols();j++) cout<<designMatrix(i,j)<<" ";
431  cout<<endl;
432  }
433  exit(0);
434  //throw ObjCrystException("LSQNumObj::Refine():caught a newmat exception during Eigenvalues computing !");
435  }
436  ColumnVector newmatDelta(nbVar);
437  DiagonalMatrix newmatInvW(nbVar);
438  //if(!silent) cout << "LSQNumObj::Refine():Eigenvalue Filtering...4" <<endl;
439  //Avoid singular values
440  {
441  REAL max=newmatW.MaximumAbsoluteValue();
442  REAL minAllowedValue=1e-5*max;// :TODO: Check if reasonable !
443  for(long i=0;i<nbVar;i++)
444  if(newmatW(i+1,i+1) > minAllowedValue)
445  newmatInvW(i+1,i+1)= 1./newmatW(i+1,i+1);
446  else
447  {
448  if(!silent) cout << "LSQNumObj::Refine():fixing ill-cond EigenValue "<< i <<endl;
449  newmatInvW(i+1,i+1) = 0.;
450  }
451 
452  /*
453  REAL max;
454  int maxIndex;
455  const REAL minRatio=1e-6;
456  for(long i=0;i<nbVar;i++)
457  {
458  max=fabs(newmatW(1)*newmatV(1,i+1)*newmatV(1,i+1));
459  maxIndex=0;
460  for(long j=1;j<nbVar;j++)
461  if( fabs(newmatW(j+1)*newmatV(j+1,i+1)*newmatV(j+1,i+1)) > max )
462  {
463  max = fabs(newmatW(j+1)*newmatV(j+1,i+1)*newmatV(j+1,i+1));
464  maxIndex=j;
465  }
466 
467  cout << FormatFloat(newmatW(i+1,i+1),36,2) << " " ;
468  cout << FormatFloat(max,36,2);
469  cout << FormatFloat(newmatW(maxIndex+1,maxIndex+1),36,2) << " " ;
470  cout << FormatFloat(newmatV(i+1,maxIndex+1)*100,8,2) ;
471  //cout << endl;
472 
473  if(newmatW(i+1,i+1) > (max*minRatio))
474  {
475  newmatInvW(i+1,i+1) = 1./newmatW(i+1,i+1);
476  cout << endl;
477  }
478  else
479  {
480  cout << "LSQNumObj::Refine():fixing ill-cond EigenValue "<< i <<endl;
481  newmatInvW(i+1,i+1) = 0.;
482  }
483  }
484  */
485  }
486  newmatN=newmatV * newmatInvW * newmatV.t();
487 
488  //Back 'Derivative Scaling' :TODO:
489  newmatN = newmatDscale * newmatN * newmatDscale;
490  newmatDelta = newmatN * newmatB;
491 
492  for(long i=0;i<nbVar;i++)
493  {
494  invW(i)=newmatInvW(i+1,i+1);
495  deltaVar(i)=newmatDelta(i+1);
496  for(long j=0;j<nbVar;j++)
497  {
498  N(i,j) = newmatN(i+1,j+1);
499  V(i,j) = newmatV(i+1,j+1);
500  }
501  }
502  //cout << invW <<endl << U << endl << V << endl << B << endl << deltaVar << endl;
503  //cout<<setw(10)<<setprecision(4)<< newmatV*100. << endl;
504  //cout << newmatA/1e15 << endl;
505  //cout << newmatW << endl;
506  //cout << newmatDscale*1e20 << endl;
507  //cout << newmatB <<endl;
508  }
509  }//End EigenValue filtering
510  TAU_PROFILE_STOP(timer5);
511 /*
512 */
513 /*
514  //Perform Singular value Decomposition normalon normal matrix (using newmat library)
515  {
516  cout << "LSQNumObj::Refine():Performing SVD on normal matrix" <<endl;
517  CrystMatrix_REAL U(nbVar,nbVar),V(nbVar,nbVar);
518  CrystVector_REAL invW(nbVar);//diagonal matrix, in fact
519  {
520  Matrix newmatA(nbVar,nbVar),
521  newmatU(nbVar,nbVar),
522  newmatV(nbVar,nbVar),
523  newmatN(nbVar,nbVar);
524  DiagonalMatrix newmatW(nbVar);
525  ColumnVector newmatB(nbVar);
526  for(long i=0;i<nbVar;i++)
527  {
528  newmatB(i+1)=B(i);
529  for(long j=0;j<nbVar;j++) newmatA(i+1,j+1) = M(i,j);
530  }
531  SVD(newmatA,newmatW,newmatU,newmatV);
532  ColumnVector newmatDelta(nbVar);
533  DiagonalMatrix newmatInvW(nbVar);
534  REAL max=newmatW.MaximumAbsoluteValue();
535  REAL minAllowedValue=1e-10*max;// :TODO: Check if reasonable !
536  //Avoid singular values,following 'Numerical Recipes in C'
537  for(long i=0;i<nbVar;i++)
538  if(newmatW(i+1,i+1) > minAllowedValue) newmatInvW(i+1,i+1) = 1./newmatW(i+1,i+1);
539  else
540  {
541  cout << "LSQNumObj::Refine():SVD: fixing ill-cond value "<< i <<endl;
542  newmatInvW(i+1,i+1) = 0.;
543  }
544  newmatN=newmatV * newmatInvW * newmatU.t();
545  newmatDelta = newmatN * newmatB;
546 
547 
548  for(long i=0;i<nbVar;i++)
549  {
550  invW(i)=newmatInvW(i+1,i+1);
551  deltaVar(i)=newmatDelta(i+1);
552  for(long j=0;j<nbVar;j++)
553  {
554  N(i,j) = newmatN(i+1,j+1);
555  U(i,j) = newmatU(i+1,j+1);
556  V(i,j) = newmatV(i+1,j+1);
557  }
558  }
559  //cout << invW <<endl << U << endl << V << endl << B << endl << deltaVar << endl;
560  }
561  }//End SVD
562 */
563 /*
564  //OLD VERSION USING GAUS INVERSION
565  //Calculate new values for variables
566  cout << "LSQNumObj::Refine():Computing new values for variables" <<endl;
567  try { N=InvertMatrix(M);}
568  catch(long svix)
569  {
570  cout << "LSQNumObj::Refine(): WARNING : Singular Matrix !!!";
571  cout << "With refinable parameter: " << mRefParList.GetParNotFixed(svix).Name() <<endl;
572  cout << "LSQNumObj::Refine(): Automatically fixing parameter and re-start cycle.."; cout << endl;
573  {
574  CrystMatrix_REAL Mtmp;
575  Mtmp=M;
576  Mtmp /= 1e14;
577  cout << Mtmp << endl << endl;
578  }
579  mRefParList.GetParNotFixed(svix).IsFixed()=true;
580  mRefParList.PrepareForRefinement();
581  nbVar=mRefParList.NbGetParNotFixed();
582  M.resize(nbVar,nbVar);
583  N.resize(nbVar,nbVar);
584  B.resize(nbVar);
585  designMatrix.resize(nbVar,nbObs);
586  deltaVar.resize(nbVar);
587  goto LSQNumObj_Refine_Restart;
588  }
589  deltaVar=0;
590  for(i=0;i<nbVar;i++)
591  for(j=0;j<nbVar;j++) deltaVar(i) += N(i,j) * B(j);
592 */
593  /*
594  {
595  CrystMatrix_REAL Mtmp,Ntmp;
596  Mtmp=M;
597  Ntmp=N;
598  Mtmp /= 1e20;
599  Ntmp *= 1e20;
600  //cout << Mtmp << endl << endl;
601  cout << Ntmp << endl << endl;
602  //cout << B <<endl;
603  //cout << deltaVar << endl;
604  }
605  */
606  TAU_PROFILE_START(timer6);
608  for(i=0;i<nbVar;i++)
609  {
610  //const REAL oldvalue=mRefParList.GetParNotFixed(i).GetValue();
611  //const REAL expected=oldvalue+deltaVar(i);
612  mRefParList.GetParNotFixed(i).Mutate(deltaVar(i));
613  //const REAL newvalue=mRefParList.GetParNotFixed(i).GetValue();
614  }
615 
616  //for statistics...
617  //mRefParList.Print();
618  calc=this->GetLSQCalc();
619  //Chi^2
620  {
621  REAL oldChiSq=mChiSq;
622  tmpV1 = mObs;
623  tmpV1 -= calc;
624  tmpV1 *= tmpV1;
625  tmpV1 *= mWeight;
626  mChiSq=tmpV1.sum();
627  if(true==useLevenbergMarquardt)
628  {
629  if(mChiSq > (oldChiSq*1.0001))
630  {
631  mRefParList.RestoreParamSet(mIndexValuesSetLast);
632  increaseMarquardt=true;
633  if(!silent)
634  {
635  cout << "LSQNumObj::Refine(Chi^2="<<oldChiSq<<"->"<<mChiSq
636  <<")=>Increasing Levenberg-Marquardt factor :"
637  << FormatFloat(marquardt*marquardtMult,18,14) <<endl;
638  }
639  mChiSq=oldChiSq;
640  if(marquardt>1e4)
641  {
642  // :TODO: Revert to previous parameters. Or initial ?
643  mRefParList.RestoreParamSet(mIndexValuesSetLast);
644  if(callBeginEndOptimization) this->EndOptimization();
645  //if(!silent) mRefParList.Print();
646  return;
647  //throw ObjCrystException("LSQNumObj::Refine():Levenberg-Marquardt diverging !");
648  }
649  TAU_PROFILE_STOP(timer6);
650  goto LSQNumObj_Refine_RestartMarquardt;
651  }
652  else
653  {
654  if(!silent && (marquardt>1e-2))
655  {
656  cout << "LSQNumObj::Refine(Chi^2="<<oldChiSq<<"->"<<mChiSq
657  <<")=>Decreasing Levenberg-Marquardt factor :" << FormatFloat(marquardt/marquardtMult,18,14) <<endl;
658  }
659  marquardt /= marquardtMult;
660  if(marquardt<1e-2) marquardt=1e-2;
661  }
662  }
663  }
664  TAU_PROFILE_STOP(timer6);
665  TAU_PROFILE_START(timer7);
666 
667  //Sigmas
668  if(nbObs==nbVar)
669  for(i=0;i<nbVar;i++) mRefParList.GetParNotFixed(i).SetSigma(0);
670  else
671  for(i=0;i<nbVar;i++) mRefParList.GetParNotFixed(i).SetSigma(sqrt(N(i,i)*mChiSq/(nbObs-nbVar)));
672  //Correlations :TODO: re-compute M and N if using Levenberg-Marquardt
673  mCorrelMatrix.resize(nbVar,nbVar);
674  mvVarCovar.clear();
675 
676  for(i=0;i<nbVar;i++)
677  {
678  RefinablePar *pi=&(mRefParList.GetParNotFixed(i));
679  for(j=0;j<nbVar;j++)
680  {
681  RefinablePar *pj=&(mRefParList.GetParNotFixed(j));
682  mCorrelMatrix(i,j)=sqrt(N(i,j)*N(i,j)/N(i,i)/N(j,j));
683  if(nbObs!=nbVar)
684  mvVarCovar[make_pair(pi,pj)]=N(i,j)*mChiSq/(nbObs-nbVar);
685  }
686  }
687  //R-factor
688  tmpV1 = mObs;
689  tmpV1 -= calc;
690  tmpV1 *= tmpV1;
691  tmpV2 = mObs;
692  tmpV2 *= tmpV2;
693  mR=sqrt(tmpV1.sum()/tmpV2.sum());
694  //Rw-factor
695  tmpV1 *= mWeight;
696  tmpV2 *= mWeight;
697  mRw=sqrt(tmpV1.sum()/tmpV2.sum());
698  //OK, finished
699  if(!silent) cout << "finished cycle #"<<cycle <<"/"<<nbCycle <<". Rw="<<Rw_ini<<"->"<<mRw<<", Chi^2="<<ChisSqPreviousCycle<<"->"<<mChiSq<<endl;
700  if (mSaveReportOnEachCycle) this->WriteReportToFile();
701 
702  if(!silent) this->PrintRefResults();
703  TAU_PROFILE_STOP(timer7);
704  if( terminateOnDeltaChi2 && (minChi2var>( (ChisSqPreviousCycle-mChiSq)/abs(ChisSqPreviousCycle+1e-6) ) ) ) break;
705  }
706  if(callBeginEndOptimization) this->EndOptimization();
707 }
708 
709 CrystMatrix_REAL LSQNumObj::CorrelMatrix()const{return mCorrelMatrix;};
710 
711 REAL LSQNumObj::Rfactor()const{return mR;};
712 
713 REAL LSQNumObj::RwFactor()const{return mRw;};
714 
715 REAL LSQNumObj::ChiSquare()const{return mChiSq;};
716 
717 
718 void RecursiveMapFunc(RefinableObj &obj,map<RefinableObj*,unsigned int> &themap, const unsigned int value)
719 {
720  themap[&obj]=value;
721  ObjRegistry<RefinableObj> *pObjReg=&(obj.GetSubObjRegistry());
722  for(int i=0;i<pObjReg->GetNb();i++)
723  RecursiveMapFunc(pObjReg->GetObj(i),themap,value);
724  return;
725 }
726 
727 void LSQNumObj::SetRefinedObj(RefinableObj &obj, const unsigned int LSQFuncIndex, const bool init, const bool recursive)
728 
729 {
730  if(init)
731  {
732  mvRefinedObjMap.clear();
733  }
734  if(recursive) RecursiveMapFunc(obj,mvRefinedObjMap,LSQFuncIndex);
735  else mvRefinedObjMap[&obj]=LSQFuncIndex;
736 }
737 
738 //ObjRegistry<RefinableObj> &LSQNumObj::GetRefinedObjList(){return mRecursiveRefinedObjList;}
739 
740 const map<RefinableObj*,unsigned int>& LSQNumObj::GetRefinedObjMap() const
741 {
742  return mvRefinedObjMap;
743 }
744 
745 map<RefinableObj*,unsigned int>& LSQNumObj::GetRefinedObjMap()
746 {
747  return mvRefinedObjMap;
748 }
749 
750 
751 RefinableObj& LSQNumObj::GetCompiledRefinedObj(){return mRefParList;}
752 
753 const RefinableObj& LSQNumObj::GetCompiledRefinedObj()const{return mRefParList;}
754 
755 void LSQNumObj::SetUseSaveFileOnEachCycle(bool yesOrNo)
756 {
757  mSaveReportOnEachCycle=yesOrNo;
758 }
759 
760 void LSQNumObj::SetSaveFile(string fileName)
761 {
762  mSaveFileName=fileName;
763 }
764 
765 void LSQNumObj::PrintRefResults() const
766 {
767  //:TODO:
768  //this->PrepareRefParList(); activate this when PrepareRefParList() will be more savy
769  cout << "Results after last refinement :(" ;
770  cout << mRefParList.GetNbParNotFixed()<< " non-fixed parameters)"<<endl;
771  cout << "Variable information : Initial, last cycle , current values and sigma"<<endl;
772  for (int i=0;i<mRefParList.GetNbPar();i++)
773  {
774  if( (true==mRefParList.GetPar(i).IsFixed())
775  || (false == mRefParList.GetPar(i).IsUsed()) ) continue;
776  cout << FormatString(mRefParList.GetPar(i).GetName(),30) << " " ;
777  cout << FormatFloat((mRefParList.GetParamSet(mIndexValuesSetInitial))(i)*mRefParList.GetPar(i).GetHumanScale(),15,8) << " " ;
778  cout << FormatFloat((mRefParList.GetParamSet(mIndexValuesSetLast))(i)*mRefParList.GetPar(i).GetHumanScale(),15,8) << " " ;
779  cout << FormatFloat(mRefParList.GetPar(i).GetHumanValue(),15,8) << " " ;
780  cout << FormatFloat(mRefParList.GetPar(i).GetHumanSigma(),15,8) << " " ;
781  //cout << FormatFloat(mRefParList(i).DerivStep(),16,12) << " ";
782  //cout << varNames[i] << " " << var0(i) << " " << varLast(i)
783  //cout<< " " << varCurrent(i)<< " " << sigmaValues(i)<<endl;
784  cout << endl;
785  }
786  cout << "R-factor : " << mR<<endl;
787  cout << "Rw-factor : " << mRw<<endl;
788  cout << "Chi-Square: " << mChiSq<<endl;
789  cout << "GoF: " << mChiSq/this->GetLSQWeight().numElements()<<endl;
790  cout <<endl;
791 }
792 
793 void LSQNumObj::SetDampingFactor(const REAL newDampFact)
794 {
795  mDampingFactor=newDampFact;
796 }
797 
798 void LSQNumObj::PurgeSaveFile()
799 {
800  //:TODO:
801 }
802 
803 void LSQNumObj::WriteReportToFile() const
804 {
805  //:TODO:
806 }
807 
808 void LSQNumObj::OptimizeDerivativeSteps()
809 {
810  //:TODO:
811 }
812 
813 const std::map<pair<const RefinablePar*,const RefinablePar*>,REAL > & LSQNumObj::GetVarianceCovarianceMap()const
814 { return mvVarCovar;}
815 
816 void LSQNumObj::PrepareRefParList(const bool copy_param)
817 {
818  mRefParList.ResetParList();
819  for(map<RefinableObj*,unsigned int>::iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos)
820  {
821  VFN_DEBUG_MESSAGE("LSQNumObj::PrepareRefParList():"<<pos->first->GetName(),4);
822  //mRecursiveRefinedObjList.GetObj(i).Print();
823  mRefParList.AddPar(*(pos->first),copy_param);
824  }
825  //mRefParList.Print();
826  if(copy_param) mRefParList.SetDeleteRefParInDestructor(true);
827  else mRefParList.SetDeleteRefParInDestructor(false);
828 }
829 
830 const CrystVector_REAL& LSQNumObj::GetLSQCalc() const
831 {
832  const CrystVector_REAL *pV;
833  long nb=0;
834  for(map<RefinableObj*,unsigned int>::const_iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos)
835  {
836  if(pos->first->GetNbLSQFunction()==0) continue;
837  pV=&(pos->first->GetLSQCalc(pos->second));
838  const long n2 = pV->numElements();
839  if((nb+n2)>mLSQCalc.numElements()) mLSQCalc.resizeAndPreserve(nb+pV->numElements());
840  const REAL *p1=pV->data();
841  REAL *p2=mLSQCalc.data()+nb;
842  for(long j = 0; j < n2; ++j) *p2++ = *p1++;
843  nb+=n2;
844  }
845  if(mLSQCalc.numElements()>nb) mLSQCalc.resizeAndPreserve(nb);
846  return mLSQCalc;
847 }
848 
849 const CrystVector_REAL& LSQNumObj::GetLSQObs() const
850 {
851  const CrystVector_REAL *pV;
852  long nb=0;
853  for(map<RefinableObj*,unsigned int>::const_iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos)
854  {
855  if(pos->first->GetNbLSQFunction()==0) continue;
856  pV=&(pos->first->GetLSQObs(pos->second));
857  const long n2 = pV->numElements();
858  mvRefinedObjLSQSize[pos->first]=n2;
859  if((nb+n2)>mLSQObs.numElements()) mLSQObs.resizeAndPreserve(nb+pV->numElements());
860  const REAL *p1=pV->data();
861  REAL *p2=mLSQObs.data()+nb;
862  for(long j = 0; j < n2; ++j) *p2++ = *p1++;
863  nb+=n2;
864  }
865  if(mLSQObs.numElements()>nb) mLSQObs.resizeAndPreserve(nb);
866  return mLSQObs;
867 }
868 
869 const CrystVector_REAL& LSQNumObj::GetLSQWeight() const
870 {
871  const CrystVector_REAL *pV;
872  long nb=0;
873  for(map<RefinableObj*,unsigned int>::const_iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos)
874  {
875  if(pos->first->GetNbLSQFunction()==0) continue;
876  pV=&(pos->first->GetLSQWeight(pos->second));
877  const long n2 = pV->numElements();
878  if((nb+n2)>mLSQWeight.numElements()) mLSQWeight.resizeAndPreserve(nb+pV->numElements());
879  const REAL *p1=pV->data();
880  REAL *p2=mLSQWeight.data()+nb;
881  for(long j = 0; j < n2; ++j) *p2++ = *p1++;
882  nb+=n2;
883  }
884  if(mLSQWeight.numElements()>nb) mLSQWeight.resizeAndPreserve(nb);
885  return mLSQWeight;
886 }
887 
888 const CrystVector_REAL& LSQNumObj::GetLSQDeriv(RefinablePar&par)
889 {
890  const CrystVector_REAL *pV;
891  long nb=0;
892  for(map<RefinableObj*,unsigned int>::iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos)
893  {
894  if(pos->first->GetNbLSQFunction()==0) continue;
895  pV=&(pos->first->GetLSQDeriv(pos->second,par));
896  const long n2 = pV->numElements();
897  if((nb+n2)>mLSQDeriv.numElements()) mLSQDeriv.resizeAndPreserve(nb+pV->numElements());
898  const REAL *p1=pV->data();
899  REAL *p2=mLSQDeriv.data()+nb;
900  for(long j = 0; j < n2; ++j) *p2++ = *p1++;
901  nb+=n2;
902  }
903  if(mLSQDeriv.numElements()>nb) mLSQDeriv.resizeAndPreserve(nb);
904  return mLSQDeriv;
905 }
906 
907 const std::map<RefinablePar*,CrystVector_REAL>& LSQNumObj::GetLSQ_FullDeriv()
908 {
909  long nbVar=mRefParList.GetNbParNotFixed();
910  std::set<RefinablePar*> vPar;
911  for(unsigned int i=0;i<nbVar;++i)
912  vPar.insert(&(mRefParList.GetParNotFixed(i)));
913  mLSQ_FullDeriv.clear();
914  unsigned long nb=0;// full length of derivative vector
915  for(map<RefinableObj*,unsigned int>::iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos)
916  {
917  if(pos->first->GetNbLSQFunction()==0) continue;
918  const unsigned long n2=mvRefinedObjLSQSize[pos->first];
919  if(n2==0) continue;//this object does not have an LSQ function
920 
921  const std::map<RefinablePar*,CrystVector_REAL> *pvV=&(pos->first->GetLSQ_FullDeriv(pos->second,vPar));
922  for(std::map<RefinablePar*,CrystVector_REAL>::const_iterator d=pvV->begin();d!=pvV->end();d++)
923  {
924  if(mLSQ_FullDeriv[d->first].size()==0) mLSQ_FullDeriv[d->first].resize(mLSQObs.size());
925  REAL *p2=mLSQ_FullDeriv[d->first].data()+nb;
926  if(d->second.size()==0)
927  { //derivative can be null and then the vector missing
928  // But we must still fill in zeros
929  cout<<__FILE__<<":"<<__LINE__<<":"<<pos->first->GetClassName()<<":"<<pos->first->GetName()<<":"<<d->first->GetName()<<" (all deriv=0)"<<endl;
930  for(unsigned long j=0;j<n2;++j) *p2++ = 0;
931  }
932  else
933  {
934  const REAL *p1=d->second.data();
935  for(unsigned long j=0;j<n2;++j) *p2++ = *p1++;
936  }
937  }
938  nb+=n2;
939  }
940  return mLSQ_FullDeriv;
941 }
942 
943 void LSQNumObj::BeginOptimization(const bool allowApproximations, const bool enableRestraints)
944 {
945  for(map<RefinableObj*,unsigned int>::iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos)
946  pos->first->BeginOptimization(allowApproximations, enableRestraints);
947 }
948 
949 void LSQNumObj::EndOptimization()
950 {
951  for(map<RefinableObj*,unsigned int>::iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos)
952  pos->first->EndOptimization();
953 }
954 
955 #ifdef __WX__CRYST__
956 WXCrystObjBasic* LSQNumObj::WXCreate(wxWindow* parent)
957 {
958  this->WXDelete();
959  mpWXCrystObj=new WXLSQ(parent,this);
960  return mpWXCrystObj;
961 }
962 WXCrystObjBasic* LSQNumObj::WXGet()
963 {
964  return mpWXCrystObj;
965 }
966 void LSQNumObj::WXDelete()
967 {
968  if(0!=mpWXCrystObj)
969  {
970  VFN_DEBUG_MESSAGE("LSQNumObj::WXDelete()",5)
971  delete mpWXCrystObj;
972  }
973  mpWXCrystObj=0;
974 }
975 void LSQNumObj::WXNotifyDelete()
976 {
977  VFN_DEBUG_MESSAGE("LSQNumObj::WXNotifyDelete():"<<mName,5)
978  mpWXCrystObj=0;
979 }
980 #endif
981 
982 }//namespace
const REAL * GetPointer() const
Access to a const pointer to the refined value.
bool ISNAN_OR_INF(REAL r)
Test if the value is a NaN.
Definition: ObjCryst/IO.cpp:97
long GetNbPar() const
Total number of refinable parameter in the object.
long GetNbParNotFixed() const
Total number of non-fixed parameters. Is initialized by PrepareForRefinement()
RefinablePar & GetPar(const long i)
Access all parameters in the order they were inputted.
Generic Refinable Object.
Definition: RefinableObj.h:752
Abstract base class for all objects in wxCryst.
Definition: wxCryst.h:127
output a number as a formatted float:
output a string with a fixed length (adding necessary space or removing excess characters) : ...
Exception class for ObjCryst++ library.
Definition: General.h:119
The namespace which includes all objects (crystallographic and algorithmic) in ObjCryst++.
Definition: Atom.cpp:47
Generic class for parameters of refinable objects.
Definition: RefinableObj.h:223
class of refinable parameter types.
Definition: RefinableObj.h:78