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