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
|