File: LSQNumObj.h

package info (click to toggle)
objcryst-fox 2022.1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 7,040 kB
  • sloc: cpp: 70,656; xml: 43,909; ansic: 467; python: 170; makefile: 21; sh: 12
file content (280 lines) | stat: -rw-r--r-- 13,897 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*  ObjCryst++ Object-Oriented Crystallographic Library
    (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net
        2000-2001 University of Geneva (Switzerland)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/*   LSQNumObj.h
*  header file for Least-Squares refinement witn Numerical derivatives Objects
*
*/
#ifndef _LSQOBJNUM_H
#define _LSQOBJNUM_H

#include "ObjCryst/CrystVector/CrystVector.h"
#include "ObjCryst/RefinableObj/RefinableObj.h"
#include <string>
#include <map>
#include <list>

namespace ObjCryst
{
/** \brief (Quick & dirty) Least-Squares Refinement Object with Numerical derivatives
*
* This is still highly experimental !
*/
class LSQNumObj
{
   public:
      LSQNumObj(std::string objName="Unnamed LSQ object");
      ~LSQNumObj();
      /// Fix one parameter.
      ///
      /// LSQNumObj::PrepareRefParList() must be called first!
      void SetParIsFixed(const std::string& parName,const bool fix);
      /// Fix one family of parameters
      ///
      /// LSQNumObj::PrepareRefParList() must be called first!
      void SetParIsFixed(const RefParType *type,const bool fix);
      /** Fix one parameter
      *
      * Note that this will fix the copied parameter, not the one
      * in the original object. The supplied RefinablePar
      * may be either the copied one or the original.
      *
      * LSQNumObj::PrepareRefParList() must be called first!
      **/
      void SetParIsFixed(RefinablePar &par,const bool fix);
      /** Fix all parameters within an object
      *
      * Note that this will fix the copied parameters, not the one
      * in the original objects.
      *
      * LSQNumObj::PrepareRefParList() must be called first!
      **/
      void SetParIsFixed(RefinableObj &obj,const bool fix);
      /// UnFix All parameters
      ///
      /// LSQNumObj::PrepareRefParList() must be called first!
      void UnFixAllPar();
      /// Set a parameter to be used
      ///
      /// LSQNumObj::PrepareRefParList() must be called first!
      void SetParIsUsed(const std::string& parName,const bool use);
      /// Set a family of parameters to be used
      ///
      /// LSQNumObj::PrepareRefParList() must be called first!
      void SetParIsUsed(const RefParType *type,const bool use);
      /** Do the refinement
      *
      * \param nbCycle: number of LSQ cycles - if negative, the algorithm will continue
      * until it reaches (-nbcycle) or until the relative variation in Chi2 is less
      * than minChi2var
      * \param useLevenbergMarquardt: enable Levenberg-Marquardt algorithm
      * to ensure that a decrease of Chi^2 will be obtained (actually a 1%
      * increase is allowed)
      * \param callBeginEndOptimization: if true, will call RefinableObj::BeginOptimization(true,...)
      * and RefinableObj::EndOptimization(). You may not want this if the LSQ is done during another
      * (e.g. monte-carlo) optimization - but then the calling function \b must ensure
      * that approximations are disabled (using RefinableObj::SetApproximationFlag)
      * for objects where that would render derivative calculations imprecise.
      * \param minChi2var: used for termination of the refinement if the relative variation
      * of Chi2 between two successive cyles is less than minChi2var
      */
      void Refine (int nbCycle=1,bool useLevenbergMarquardt=false,
                   const bool silent=false, const bool callBeginEndOptimization=true,
                   const float minChi2var=0.01);
      /** Run a refinement in a 'safe' way: if the Chi2 value increases by more that a given factor
      * the parameters are reverted to their initial values. Moreover, the listed 'new' parameters
      * or parameter types are then fixed.
      * \param vnewpar: list of parameters added for this optimization, which will be unfixed at the
      * beginning, and will be fixed at the end if Chi2 increases. This can be empty.
      * \param vnewpartype: list of parameter types, which will be unfixed at the
      * beginning, and will be fixed at the end if Chi2 increases. This can be empty.
      * \param maxChi2factor: if Chi2_end> maxChi2factor * Chi2_begin, parameters are reverted to their
      * initial value, and new parameters are fixed.
      * All the other parameters are the same as in LSQNumObj::Refine.
      * \return: true if the minimization was succesful, false otherwise.
      */
      bool SafeRefine(std::list<RefinablePar*> vnewpar, std::list<const RefParType*> vnewpartype,
                      REAL maxChi2factor=1.01,
                      int nbCycle=1, bool useLevenbergMarquardt=false,
                      const bool silent=false, const bool callBeginEndOptimization=true,
                      const float minChi2var=0.01);
      CrystVector_REAL Sigma()const;
      CrystMatrix_REAL CorrelMatrix()const;
      void CalcRfactor()const;
      REAL Rfactor()const;
      void CalcRwFactor()const;
      REAL RwFactor()const;
      void CalcChiSquare() const;
      REAL ChiSquare()const;   //uses the weight if specified
      /** Choose the object to refine. The minimization will be done
      * against its LSQ function and its parameters, as well as the LSQ functions
      * and parameters of its sub-objects (if recursive==true)
      *
      * \param LSQFuncIndex: one object can have a choice of several LSQ
      * functions to minimize- this allows to choose which one to minimize.
      *
      * \param init: if true, the list of refined objects is first cleared. otherwise
      * the new object (and its sub-objects) is just added to the list.
      *
      * \param recursive: if false, only the supplied object is added, and not its sub-objects
      */
      void SetRefinedObj(RefinableObj &obj, const unsigned int LSQFuncIndex=0, const bool init=true, const bool recursive=false);
      // Access to the full list of refined objects. The list is initially built
      // recursively from one object. This function allows to modify the list
      // of sub-objects before refinement (such as for removing certain types
      // of objects).
      //ObjRegistry<RefinableObj> &GetRefinedObjList();
      /** Get the map of refined objects - this is a recursive list of all the objects
      * that are taken into account for the refinement. The key is a pointer to the
      * object and the value is the LSQ function index for that object.
      */
      const std::map<RefinableObj*,unsigned int>& GetRefinedObjMap() const;
      /** Get the map of refined objects - this is a recursive list of all the objects
      * that are taken into account for the refinement. The key is a pointer to the
      * object and the value is the LSQ function index for that object.
      */
      std::map<RefinableObj*,unsigned int>& GetRefinedObjMap();
      /** Access to the RefinableObj which is the compilation of all parameters
      * from the object supplied for optimization and its sub-objects.
      *
      * Since this compilation is only updated from the suplied refinableobj and
      * its sub-objects when SetRefinedObj() and PrepareRefParList() are called,
      * it is possible to alter the fixed/limited status of parameters
      * here without affecting the parameters in the refined objects.
      */
      RefinableObj& GetCompiledRefinedObj();
      /** Access to the RefinableObj which is the compilation of all parameters
      * from the object supplied for optimization and its sub-objects.
      *
      * Since this compilation is only updated from the suplied refinableobj and
      * its sub-objects when SetRefinedObj() and PrepareRefParList() are called,
      * it is possible to alter the fixed/limited status of parameters
      * here without affecting the parameters in the refined objects.
      */
      const RefinableObj& GetCompiledRefinedObj()const;
      void SetUseSaveFileOnEachCycle(bool yesOrNo=true);
      void SetSaveFile(std::string fileName="refine.save");
      void PrintRefResults()const;
      void SetDampingFactor(const REAL newDampFact);
      void PurgeSaveFile();
      void WriteReportToFile()const;

      void OptimizeDerivativeSteps();
      const std::map<pair<const RefinablePar*,const RefinablePar*>,REAL > &GetVarianceCovarianceMap()const;
      /** Prepare the full parameter list for the refinement
      * \param copy_param: if false (the default), then the lsq algorithm will work directly
      * on the parameters of the refined object and sub-object. So that any modification
      * to the fixed/used/limited status applies permanently to the parameters.
      * if true, then the parameters are copied and therefore only the value of the
      * parameter is changed (and the clocks are ticked).
      *
      * \note: if copy_param==true, then any modification to the parameters (fixed, limited, used
      * status) only affects the copy and not the original. Also, calling again PrepareRefParList
      * cancels any such modification.
      *
      * \note This will be called automatically before starting the refinement only if
      * the parameter list is empty. Otherwise it should be called before refinement.
      */
      void PrepareRefParList(const bool copy_param=false);

      /// Get the LSQ calc vector (using either only the top or the hierarchy of object)
      const CrystVector_REAL& GetLSQCalc() const;
      /// Get the LSQ obs vector (using either only the top or the hierarchy of object)
      const CrystVector_REAL& GetLSQObs() const;
      /// Get the LSQ weight vector (using either only the top or the hierarchy of object)
      const CrystVector_REAL& GetLSQWeight() const;
      /// Get the LSQ deriv vector (using either only the top or the hierarchy of object)
      const CrystVector_REAL& GetLSQDeriv(RefinablePar&par);
      const std::map<RefinablePar*,CrystVector_REAL>& GetLSQ_FullDeriv();
      /** Tell all refined object that the refinement is beginning
      */
      void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false);
      /** Tell all refined object that the refinement is finished
      */
      void EndOptimization();
   protected:
   private:
      // Refined object
         /// The recursive list of all refined sub-objects
         ObjRegistry<RefinableObj> mRecursiveRefinedObjList;
      /** The refinable par list used during refinement. It is only a compilation
      * of the parameters in RefinableObj and its sub-objects
      *
      * This list is only updated from the suplied refinableobj and
      * its sub-objects when SetRefinedObj() and PrepareRefParList() are called,
      * so it is possible to alter the fixed/limited status of parameters
      * here without affecting the parameters in the refined objects.
      */
      mutable RefinableObj mRefParList;
      /// Damping factor for the refinement (unused yet...)
      REAL mDampingFactor;
      ///Save result to file after each cycle ?
      bool mSaveReportOnEachCycle;
      /// Name of the refined object
      std::string mName;
      /// File name where refinement info is saved
      std::string mSaveFileName;
      mutable REAL mR,mRw,mChiSq;
      /// Correlation matrix between all refined parameters.
      CrystMatrix_REAL mCorrelMatrix;
      ///Variance-Covariance matrix, as a std::map
      std::map<pair<const RefinablePar*,const RefinablePar*>,REAL > mvVarCovar;
      /// Observed values.
      CrystVector_REAL mObs;
      /// Weight corresponding to all observed values.
      CrystVector_REAL mWeight;
      /// Index of the set of saved values for all refinable parameters, before refinement
      /// and before the last cycle.
      int mIndexValuesSetInitial, mIndexValuesSetLast;
      /// If true, then stop at the end of the cycle. Used in multi-threading environment
      bool mStopAfterCycle;
      // The optimized object
      //RefinableObj *mpRefinedObj;
      // The index of the LSQ function in the refined object (if there are several...)
      //unsigned int mLSQFuncIndex;

      /** Map of the recursive list of the objects to be refined. The key is the pointer
      * to the object and the value the LSQ function index
      *
      * Individual LSQ functions can be changed using GetRefinedObjMap().
      */
      std::map<RefinableObj*,unsigned int> mvRefinedObjMap;
      /// Size of each object LSQ data. This is initialized in LSQNumObj::GetLSQObs()
      mutable std::map<RefinableObj*,unsigned int> mvRefinedObjLSQSize;

      /// If true, then parameters to be refined will be copied instead of referenced.
      /// Therefore only their values and the parameter's clocks are affected when
      /// working on the copy.
      bool mCopyRefPar;
      /// Temporary arrays for LSQ functions evaluation - used when
      /// using recursive LSQ function
      mutable CrystVector_REAL mLSQObs,mLSQCalc,mLSQWeight,mLSQDeriv;
      mutable std::map<RefinablePar*,CrystVector_REAL> mLSQ_FullDeriv;
#ifdef __WX__CRYST__
   public:
      virtual WXCrystObjBasic* WXCreate(wxWindow* parent);
      WXCrystObjBasic* WXGet();
      void WXDelete();
      void WXNotifyDelete();
   protected:
      WXCrystObjBasic *mpWXCrystObj;
#endif
};

}//namespace
#endif //_LSQOBJNUM_H