FOX/ObjCryst++  1.10.X (development)
wxPowderPattern.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 <sstream> //for stringstream
20 #include <fstream>
21 #include <algorithm>
22 
23 #include "cctbx/sgtbx/space_group.h"
24 
25 // wx headers, with or without precompilation
26 #include "wx/wxprec.h"
27 #ifdef __BORLANDC__
28  #pragma hdrstop
29 #endif
30 #ifndef WX_PRECOMP
31  #include "wx/wx.h"
32 #endif
33 #include "wx/dcbuffer.h"
34 #include "wx/config.h"
35 #include "wx/notebook.h"
36 #include "wx/progdlg.h"
37 #include "wx/filename.h"
38 
39 #include "ObjCryst/wxCryst/wxPowderPattern.h"
40 #include "ObjCryst/wxCryst/wxRadiation.h"
41 #include "ObjCryst/RefinableObj/Simplex.h"
42 #include "ObjCryst/RefinableObj/LSQNumObj.h"
43 #include "ObjCryst/ObjCryst/PowderPatternBackgroundBayesianMinimiser.h"
44 #include "ObjCryst/Quirks/VFNStreamFormat.h"
45 #include "ObjCryst/Quirks/Chronometer.h"
46 
47 //Fixes for Cygwin; where do those stupid macros come from ? Somewhere in wxMSW headers
48 #ifdef max
49 #undef max
50 #endif
51 #ifdef min
52 #undef min
53 #endif
54 #ifdef DrawText
55 #undef DrawText
56 #endif
57 
58 //#define USE_BACKGROUND_MAXLIKE_ERROR
59 
60 namespace ObjCryst
61 {
63 //
64 // WXRadiation
65 //
67 BEGIN_EVENT_TABLE(WXRadiation, wxWindow)
68  EVT_UPDATE_UI(ID_CRYST_UPDATEUI, WXRadiation::OnUpdateUI)
69 END_EVENT_TABLE()
70 
71 WXRadiation::WXRadiation(wxWindow *parent, Radiation* rad):
72 WXCrystObjBasic(parent),mpRadiation(rad)
73 {
74  VFN_DEBUG_ENTRY("WXRadiation::WXRadiation()",6)
75  // :TODO: Add a choice for the wavlength type, with 'monochromatic', and a list
76  // of X-Ray tubes.
77  mpSizer=new wxBoxSizer(wxHORIZONTAL);
78 
79  mpFieldRadType= new WXFieldOption(this,-1,&(mpRadiation->mRadiationType));
80  mpSizer->Add(mpFieldRadType,0);
81  mList.Add(mpFieldRadType);
82 
83  mpFieldWavelengthType= new WXFieldOption(this,-1,&(mpRadiation->mWavelengthType));
84  mpSizer->Add(mpFieldWavelengthType,0);
85  mList.Add(mpFieldWavelengthType);
86 
87  WXCrystObjBasic* pFieldWavelength
88  =mpRadiation->GetPar(mpRadiation->mWavelength.data()).WXCreate(this);
89  mpSizer->Add(pFieldWavelength,0);
90  mList.Add(pFieldWavelength);
91 
92  WXFieldPar<REAL> *polarRate=new WXFieldPar<REAL>(this,"Linear Polar Rate:",-1,
93  &(mpRadiation->mLinearPolarRate));
94  mpSizer->Add(polarRate,0,wxALIGN_LEFT);
95  mList.Add(polarRate);
96 
97  WXFieldPar<REAL> *xRayTubeDlambda=new WXFieldPar<REAL>(this,"Tube-DeltaLambda:",-1,
98  &(mpRadiation->mXRayTubeDeltaLambda));
99  mpSizer->Add(xRayTubeDlambda,0,wxALIGN_LEFT);
100  mList.Add(xRayTubeDlambda);
101 
102  WXFieldPar<REAL> *xRayTubeAlpha2Alpha1=new WXFieldPar<REAL>(this,"Tube-Alpha2/Alpha1:",-1,
103  &(mpRadiation->mXRayTubeAlpha2Alpha1Ratio));
104  mpSizer->Add(xRayTubeAlpha2Alpha1,0,wxALIGN_LEFT);
105  mList.Add(xRayTubeAlpha2Alpha1);
106 
107  this->CrystUpdate(true);
108  this->SetSizer(mpSizer);
109  mpSizer->SetSizeHints(this);
110  this->Layout();
111  VFN_DEBUG_EXIT("WXRadiation::WXRadiation()",6)
112 }
113 WXRadiation::~WXRadiation()
114 {
115  mpRadiation->WXNotifyDelete();
116 }
117 
118 void WXRadiation::CrystUpdate(const bool uui,const bool lock)
119 {
120  if(lock) mMutex.Lock();
121  mList.CrystUpdate(false,false);
122  if(lock) mMutex.Unlock();
123  if(uui)
124  {
125  if(true==wxThread::IsMain()) this->UpdateUI(lock);
126  else
127  {
128  wxUpdateUIEvent event(ID_CRYST_UPDATEUI);
129  wxPostEvent(this,event);
130  }
131  }
132 }
133 void WXRadiation::UpdateUI(const bool lock)
134 {
135  mList.UpdateUI(lock);
136 }
137 void WXRadiation::OnUpdateUI(wxUpdateUIEvent& event)
138 {
139  this->UpdateUI(true);
140  event.Skip();
141 }
142 
144 
145 class WXProfileFitting:public wxWindow
146 {
147  public:
148  WXProfileFitting(wxWindow *parent,PowderPattern *pPattern,PowderPatternDiffraction *pDiff=0);
149  ~WXProfileFitting();
151  void OnFit(wxCommandEvent &event);
152  void OnExploreSpacegroups(wxCommandEvent &event);
153  private:
154  PowderPattern *mpPattern;
155  PowderPatternDiffraction *mpDiff;
156  wxCheckListBox *mpFitCheckList;
157  wxTextCtrl *mpLog;
158  wxListBox *mpList;
159  LSQNumObj mLSQ;
160  DECLARE_EVENT_TABLE()
161 };
162 
164 //
165 // WXPowderPattern
166 //
168 static const long ID_POWDER_MENU_COMP_ADDBACKGD_BAYESIAN=WXCRYST_ID();
169 static const long ID_POWDER_MENU_COMP_ADDBACKGD= WXCRYST_ID();
170 static const long ID_POWDER_MENU_COMP_ADDCRYST= WXCRYST_ID();
171 static const long ID_POWDER_MENU_GRAPH= WXCRYST_ID();
172 static const long ID_POWDER_MENU_SAVETEXT= WXCRYST_ID();
173 static const long ID_POWDER_MENU_SIMULATE= WXCRYST_ID();
174 static const long ID_POWDER_MENU_EXPORT= WXCRYST_ID();
175 static const long ID_POWDER_MENU_EXPORT_FULLPROF= WXCRYST_ID();
176 static const long ID_POWDER_MENU_IMPORT_FULLPROF= WXCRYST_ID();
177 static const long ID_POWDER_MENU_IMPORT_PSI_DMC= WXCRYST_ID();
178 static const long ID_POWDER_MENU_IMPORT_ILL_D1A5= WXCRYST_ID();
179 static const long ID_POWDER_MENU_IMPORT_XDD= WXCRYST_ID();
180 static const long ID_POWDER_MENU_IMPORT_CPI= WXCRYST_ID();
181 static const long ID_POWDER_MENU_IMPORT_FULLPROF4= WXCRYST_ID();
182 static const long ID_POWDER_MENU_IMPORT_MULTIDETECTORLLBG42=WXCRYST_ID();
183 static const long ID_POWDER_MENU_IMPORT_2THETAOBSSIGMA= WXCRYST_ID();
184 static const long ID_POWDER_MENU_IMPORT_2THETAOBS= WXCRYST_ID();
185 static const long ID_POWDER_MENU_IMPORT_TOFISISXYSIGMA= WXCRYST_ID();
186 static const long ID_POWDER_MENU_IMPORT_GSAS= WXCRYST_ID();
187 static const long ID_POWDER_MENU_IMPORT_CIF= WXCRYST_ID();
188 static const long ID_POWDER_MENU_FITSCALE_R= WXCRYST_ID();
189 static const long ID_POWDER_MENU_FITSCALE_RW= WXCRYST_ID();
190 static const long ID_POWDER_MENU_WAVELENGTH= WXCRYST_ID();
191 static const long ID_POWDER_MENU_WAVELENGTH_XRAY= WXCRYST_ID();
192 static const long ID_POWDER_MENU_WAVELENGTH_NEUTRON= WXCRYST_ID();
193 static const long ID_POWDER_MENU_WAVELENGTH_NEUTRON_TOF= WXCRYST_ID();
194 static const long ID_POWDER_MENU_WAVELENGTH_SET= WXCRYST_ID();
195 static const long ID_POWDER_MENU_WAVELENGTH_SET_AG= WXCRYST_ID();
196 static const long ID_POWDER_MENU_WAVELENGTH_SET_MO= WXCRYST_ID();
197 static const long ID_POWDER_MENU_WAVELENGTH_SET_CU= WXCRYST_ID();
198 static const long ID_POWDER_MENU_WAVELENGTH_SET_FE= WXCRYST_ID();
199 static const long ID_POWDER_MENU_WAVELENGTH_SET_CO= WXCRYST_ID();
200 static const long ID_POWDER_MENU_WAVELENGTH_SET_CR= WXCRYST_ID();
201 static const long ID_POWDER_MENU_WAVELENGTH_SET_AGA1= WXCRYST_ID();
202 static const long ID_POWDER_MENU_WAVELENGTH_SET_MOA1= WXCRYST_ID();
203 static const long ID_POWDER_MENU_WAVELENGTH_SET_CUA1= WXCRYST_ID();
204 static const long ID_POWDER_MENU_WAVELENGTH_SET_FEA1= WXCRYST_ID();
205 static const long ID_POWDER_MENU_WAVELENGTH_SET_COA1= WXCRYST_ID();
206 static const long ID_POWDER_MENU_WAVELENGTH_SET_CRA1= WXCRYST_ID();
207 static const long ID_POWDER_MENU_ADD_2THETA_EXCLUDE= WXCRYST_ID();
208 static const long ID_POWDER_MENU_LEBAIL= WXCRYST_ID();
209 static const long ID_POWDERBACKGROUND_IMPORT= WXCRYST_ID();
210 static const long ID_POWDERBACKGROUND_OPTIMIZEBAYESIAN= WXCRYST_ID();
211 static const long ID_POWDERDIFF_CRYSTAL= WXCRYST_ID();
212 static const long ID_POWDERDIFF_SAVEHKLFCALC= WXCRYST_ID();
213 static const long ID_POWDER_GRAPH_NEW_PATTERN= WXCRYST_ID();
214 static const long ID_POWDERTEXTURE_MENU_ADDPHASE= WXCRYST_ID();
215 static const long ID_POWDERTEXTURE_MENU_DELETEPHASE= WXCRYST_ID();
216 static const long ID_POWDERPATTERN_MENU_COMPONENTS= WXCRYST_ID();
217 static const long ID_POWDERPATTERN_MENU_PATTERN= WXCRYST_ID();
218 static const long ID_POWDERDIFF_PROFILE_DEPV= WXCRYST_ID();
219 static const long ID_POWDER_GRAPH_WIN= WXCRYST_ID();
220 
221 
222 BEGIN_EVENT_TABLE(WXPowderPattern, wxWindow)
223  EVT_BUTTON(ID_WXOBJ_COLLAPSE, WXCrystObj::OnToggleCollapse)
224  EVT_MENU(ID_POWDER_MENU_EXPORT_FULLPROF, WXPowderPattern::OnMenuExport)
225  EVT_MENU(ID_REFOBJ_MENU_OBJ_SAVE, WXRefinableObj::OnMenuSave)
226  EVT_MENU(ID_REFOBJ_MENU_OBJ_LOAD, WXRefinableObj::OnMenuLoad)
227  EVT_MENU(ID_REFOBJ_MENU_PAR_FIXALL, WXRefinableObj::OnMenuFixAllPar)
228  EVT_MENU(ID_REFOBJ_MENU_PAR_UNFIXALL, WXRefinableObj::OnMenuUnFixAllPar)
229  EVT_MENU(ID_POWDER_MENU_COMP_ADDBACKGD, WXPowderPattern::OnMenuAddCompBackgd)
230  EVT_MENU(ID_POWDER_MENU_COMP_ADDBACKGD_BAYESIAN, WXPowderPattern::OnMenuAddCompBackgdBayesian)
231  EVT_MENU(ID_POWDER_MENU_COMP_ADDCRYST, WXPowderPattern::OnMenuAddCompCryst)
232  EVT_MENU(ID_POWDER_MENU_SAVETEXT, WXPowderPattern::OnMenuSaveText)
233  EVT_MENU(ID_POWDER_MENU_SIMULATE, WXPowderPattern::OnMenuSimulate)
234  EVT_MENU(ID_POWDER_MENU_IMPORT_FULLPROF, WXPowderPattern::OnMenuImportPattern)
235  EVT_MENU(ID_POWDER_MENU_IMPORT_PSI_DMC, WXPowderPattern::OnMenuImportPattern)
236  EVT_MENU(ID_POWDER_MENU_IMPORT_ILL_D1A5, WXPowderPattern::OnMenuImportPattern)
237  EVT_MENU(ID_POWDER_MENU_IMPORT_XDD, WXPowderPattern::OnMenuImportPattern)
238  EVT_MENU(ID_POWDER_MENU_IMPORT_CPI, WXPowderPattern::OnMenuImportPattern)
239  EVT_MENU(ID_POWDER_MENU_IMPORT_FULLPROF4, WXPowderPattern::OnMenuImportPattern)
240  EVT_MENU(ID_POWDER_MENU_IMPORT_MULTIDETECTORLLBG42,WXPowderPattern::OnMenuImportPattern)
241  EVT_MENU(ID_POWDER_MENU_IMPORT_2THETAOBSSIGMA, WXPowderPattern::OnMenuImportPattern)
242  EVT_MENU(ID_POWDER_MENU_IMPORT_2THETAOBS, WXPowderPattern::OnMenuImportPattern)
243  EVT_MENU(ID_POWDER_MENU_IMPORT_TOFISISXYSIGMA, WXPowderPattern::OnMenuImportPattern)
244  EVT_MENU(ID_POWDER_MENU_IMPORT_GSAS, WXPowderPattern::OnMenuImportPattern)
245  EVT_MENU(ID_POWDER_MENU_IMPORT_CIF, WXPowderPattern::OnMenuImportPattern)
246  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET, WXPowderPattern::OnMenuSetWavelength)
247  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_XRAY, WXPowderPattern::OnMenuSetWavelength)
248  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_NEUTRON, WXPowderPattern::OnMenuSetWavelength)
249  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_NEUTRON_TOF, WXPowderPattern::OnMenuSetWavelength)
250  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_AG, WXPowderPattern::OnMenuSetWavelength)
251  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_MO, WXPowderPattern::OnMenuSetWavelength)
252  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_CU, WXPowderPattern::OnMenuSetWavelength)
253  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_FE, WXPowderPattern::OnMenuSetWavelength)
254  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_CO, WXPowderPattern::OnMenuSetWavelength)
255  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_CR, WXPowderPattern::OnMenuSetWavelength)
256  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_AGA1, WXPowderPattern::OnMenuSetWavelength)
257  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_MOA1, WXPowderPattern::OnMenuSetWavelength)
258  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_CUA1, WXPowderPattern::OnMenuSetWavelength)
259  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_FEA1, WXPowderPattern::OnMenuSetWavelength)
260  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_COA1, WXPowderPattern::OnMenuSetWavelength)
261  EVT_MENU(ID_POWDER_MENU_WAVELENGTH_SET_CRA1, WXPowderPattern::OnMenuSetWavelength)
262  EVT_MENU(ID_POWDER_MENU_GRAPH, WXPowderPattern::OnMenuShowGraph)
263  EVT_MENU(ID_POWDER_MENU_FITSCALE_R, WXPowderPattern::OnMenuFitScaleForR)
264  EVT_MENU(ID_POWDER_MENU_FITSCALE_RW, WXPowderPattern::OnMenuFitScaleForRw)
265  EVT_MENU(ID_POWDER_MENU_ADD_2THETA_EXCLUDE, WXPowderPattern::OnMenuAddExclude)
266  EVT_MENU(ID_POWDER_MENU_LEBAIL, WXPowderPattern::OnMenuLeBail)
267  EVT_UPDATE_UI(ID_CRYST_UPDATEUI, WXRefinableObj::OnUpdateUI)
268 END_EVENT_TABLE()
269 
270 WXPowderPattern::WXPowderPattern(wxWindow *parent, PowderPattern* pow):
271 WXRefinableObj(parent,pow),mpPowderPattern(pow),mpGraph(0),
272 mChi2(0.0),mGoF(0.0),mRwp(0.0),mRp(0.0)
273 {
274  VFN_DEBUG_MESSAGE("WXPowderPattern::WXPowderPattern()",6)
275  mpWXTitle->SetForegroundColour(wxColour(255,0,0));
276  mpWXTitle->SetSize(400,-1);
277  // Menu
278  mpMenuBar->AddMenu("Data",ID_REFOBJ_MENU_OBJ);
279  //:TODO: reactivate & test those menus
280  //mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_REFOBJ_MENU_OBJ_SAVE,"Save");
281  //mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_REFOBJ_MENU_OBJ_LOAD,"Load");
282  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_SAVETEXT,
283  "Save pattern (text)");
284  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_SIMULATE,
285  "Simulation mode (no obs. pattern)");
286  mpMenuBar->GetMenu(ID_REFOBJ_MENU_OBJ).AppendSeparator();
287  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_CIF,
288  "Import CIF Powder Data");
289  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_GSAS,
290  "Import GSAS Data(CONS-ESD,CONS6STD,RALF-ALT)");
291  mpMenuBar->GetMenu(ID_REFOBJ_MENU_OBJ).AppendSeparator();
292  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_2THETAOBSSIGMA,
293  "Import 2Theta-Obs-Sigma Pattern");
294  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_2THETAOBS,
295  "Import 2Theta-Obs Pattern");
296  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_FULLPROF,
297  "Import Fullprof Pattern");
298  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_FULLPROF4,
299  "Import FullProf format #4");
300  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_XDD,
301  "Import Xdd Pattern");
302  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_CPI,
303  "Import Sietronics CPI Pattern");
304  mpMenuBar->GetMenu(ID_REFOBJ_MENU_OBJ).AppendSeparator();
305  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_ILL_D1A5,
306  "Import Neutron ILL(D1A-D1B) Pattern (D1A5)");
307  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_PSI_DMC,
308  "Import PSI(DMC) Pattern");
309  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_MULTIDETECTORLLBG42,
310  "Import Neutron Multi-Detector Format (LLB G42)");
311  mpMenuBar->GetMenu(ID_REFOBJ_MENU_OBJ).AppendSeparator();
312  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDER_MENU_IMPORT_TOFISISXYSIGMA,
313  "Import Neutron TOF ISIS X Y Sigma");
314  mpMenuBar->AddMenu("Export",ID_POWDER_MENU_EXPORT);
315  mpMenuBar->AddMenuItem(ID_POWDER_MENU_EXPORT,ID_POWDER_MENU_EXPORT_FULLPROF,
316  "Export to Fullprof");
317  mpMenuBar->AddMenu("Parameters",ID_REFOBJ_MENU_PAR);
318  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_PAR,ID_REFOBJ_MENU_PAR_FIXALL,"Fix all");
319  //mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_PAR,ID_REFOBJ_MENU_PAR_UNFIXALL,"Unfix all");
320  mpMenuBar->AddMenu("Phases",ID_POWDERPATTERN_MENU_COMPONENTS);
321  mpMenuBar->AddMenuItem(ID_POWDERPATTERN_MENU_COMPONENTS,
322  ID_POWDER_MENU_COMP_ADDBACKGD_BAYESIAN,
323  "Add Background (Bayesian, automatic)");
324  mpMenuBar->AddMenuItem(ID_POWDERPATTERN_MENU_COMPONENTS,
325  ID_POWDER_MENU_COMP_ADDBACKGD,
326  "Add user-supplied Background ");
327  mpMenuBar->AddMenuItem(ID_POWDERPATTERN_MENU_COMPONENTS,ID_POWDER_MENU_COMP_ADDCRYST,
328  "Add Crystalline Phase");
329  mpMenuBar->AddMenu("Radiation",ID_POWDER_MENU_WAVELENGTH);
330  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
331  ID_POWDER_MENU_WAVELENGTH_NEUTRON,
332  "Neutron");
333  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
334  ID_POWDER_MENU_WAVELENGTH_NEUTRON_TOF,
335  "Neutron Time Of Flight");
336  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
337  ID_POWDER_MENU_WAVELENGTH_XRAY,
338  "X-Rays");
339  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
340  ID_POWDER_MENU_WAVELENGTH_SET,
341  "Monochromatic Wavelength");
342  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
343  ID_POWDER_MENU_WAVELENGTH_SET_AG,
344  "X-Ray Tube Ag Ka12");
345  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
346  ID_POWDER_MENU_WAVELENGTH_SET_AGA1,
347  "X-Ray Tube Ag Ka1");
348  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
349  ID_POWDER_MENU_WAVELENGTH_SET_MO,
350  "X-Ray Tube Mo Ka12");
351  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
352  ID_POWDER_MENU_WAVELENGTH_SET_MOA1,
353  "X-Ray Tube Mo Ka1");
354  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
355  ID_POWDER_MENU_WAVELENGTH_SET_CU,
356  "X-Ray Tube Cu Ka12");
357  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
358  ID_POWDER_MENU_WAVELENGTH_SET_CUA1,
359  "X-Ray Tube Cu Ka1");
360  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
361  ID_POWDER_MENU_WAVELENGTH_SET_FE,
362  "X-Ray Tube Fe Ka12");
363  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
364  ID_POWDER_MENU_WAVELENGTH_SET_FEA1,
365  "X-Ray Tube Fe Ka1");
366  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
367  ID_POWDER_MENU_WAVELENGTH_SET_CO,
368  "X-Ray Tube Co Ka12");
369  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
370  ID_POWDER_MENU_WAVELENGTH_SET_COA1,
371  "X-Ray Tube Co Ka1");
372  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
373  ID_POWDER_MENU_WAVELENGTH_SET_CR,
374  "X-Ray Tube Cr Ka12");
375  mpMenuBar->AddMenuItem(ID_POWDER_MENU_WAVELENGTH,
376  ID_POWDER_MENU_WAVELENGTH_SET_CRA1,
377  "X-Ray Tube Cr Ka1");
378  mpMenuBar->AddMenu("Pattern",ID_POWDERPATTERN_MENU_PATTERN);
379  mpMenuBar->AddMenuItem(ID_POWDERPATTERN_MENU_PATTERN,ID_POWDER_MENU_GRAPH,
380  "Show Graph");
381  mpMenuBar->AddMenuItem(ID_POWDERPATTERN_MENU_PATTERN,ID_POWDER_MENU_FITSCALE_R,
382  "Fit Scale for R");
383  mpMenuBar->AddMenuItem(ID_POWDERPATTERN_MENU_PATTERN,ID_POWDER_MENU_FITSCALE_RW,
384  "Fit Scale for Rw");
385  mpMenuBar->AddMenuItem(ID_POWDERPATTERN_MENU_PATTERN,
386  ID_POWDER_MENU_ADD_2THETA_EXCLUDE,
387  "Add excluded region");
388  mpMenuBar->GetMenu(ID_POWDERPATTERN_MENU_PATTERN).AppendSeparator();
389  mpMenuBar->AddMenuItem(ID_POWDERPATTERN_MENU_PATTERN,
390  ID_POWDER_MENU_LEBAIL,
391  "Fit profile + Le Bail extract");
392  //mpSizer->SetItemMinSize(mpMenuBar,
393  // mpMenuBar->GetSize().GetWidth(),
394  // mpMenuBar->GetSize().GetHeight());
395  //Radiation
396  mpSizer->Add(mpPowderPattern->mRadiation.WXCreate(this),0);
397  mList.Add(mpPowderPattern->mRadiation.WXGet());
398  // Correction to 2Theta
399  wxBoxSizer* thetaCorrSizer=new wxBoxSizer(wxHORIZONTAL);
400 
401  WXCrystObjBasic* fieldZero
402  =mpPowderPattern->GetPar(&(mpPowderPattern->mXZero)).WXCreate(this);
403  fieldZero->SetToolTip(_T("Zero shift of peaks\n")
404  _T("2Theta = 2Theta_Bragg + Zero\n"));
405  WXCrystObjBasic* fieldThetaDispl
406  =mpPowderPattern->GetPar(&(mpPowderPattern->m2ThetaDisplacement)).WXCreate(this);
407  fieldThetaDispl->SetToolTip(_T("Peak shift due to sample displacement:\n")
408  _T("2Theta = 2Theta_Bragg + Displacement/cos(Theta)"));
409  WXCrystObjBasic* fieldThetaTransp
410  =mpPowderPattern->GetPar(&(mpPowderPattern->m2ThetaTransparency)).WXCreate(this);
411  fieldThetaTransp->SetToolTip(_T("Zero shift of the peak 2theta positions\n")
412  _T("2Theta = 2Theta_Bragg + Transparency*sin(Theta)"));
413 
414  thetaCorrSizer->Add(fieldZero,0);
415  thetaCorrSizer->Add(fieldThetaDispl,0);
416  thetaCorrSizer->Add(fieldThetaTransp,0);
417  mList.Add(fieldZero);
418  mList.Add(fieldThetaDispl);
419  mList.Add(fieldThetaTransp);
420  mpSizer->Add(thetaCorrSizer);
421  // Time OF Flight parameters
422  wxBoxSizer* tofSizer=new wxBoxSizer(wxHORIZONTAL);
423  WXCrystObjBasic* fieldDIFC=mpPowderPattern->GetPar(&(mpPowderPattern->mDIFC)).WXCreate(this);
424  WXCrystObjBasic* fieldDIFA=mpPowderPattern->GetPar(&(mpPowderPattern->mDIFA)).WXCreate(this);
425  fieldDIFA->SetToolTip(_T("Peak position (time, in microseconds):\n")
426  _T("t = DIFA * d_hkl + DIFC * d_hkl^2 + ZERO"));
427  fieldDIFC->SetToolTip(_T("Peak position (time, in microseconds):\n")
428  _T("t = DIFA * d_hkl + DIFC * d_hkl^2 + ZERO"));
429  tofSizer->Add(fieldDIFC,0);
430  tofSizer->Add(fieldDIFA,0);
431  mList.Add(fieldDIFC);
432  mList.Add(fieldDIFA);
433  mpSizer->Add(tofSizer);
434  // Max Sin(theta/Lambda)
435  WXFieldPar<REAL> *maxSiThOvLa=
436  new WXFieldPar<REAL>(this,"Max Sin(theta)/lambda:",-1,
437  &(mpPowderPattern->mMaxSinThetaOvLambda));
438  mpSizer->Add(maxSiThOvLa,0,wxALIGN_LEFT);
439  mList.Add(maxSiThOvLa);
440  maxSiThOvLa->SetToolTip(_T("Maximum sin(theta)/lambda=1/2d\n")
441  _T("For global optimization, the default value of ")
442  _T("0.25 (2A resolution) should be sufficient.\n")
443  _T("Use larger values if necessary (0.4(1.25A), 0.5(1A))")
444  _T("but keep in mind that the number of reflections (and")
445  _T("therefore the computing time) varies as [sin(theta/lambda)]^3..."));
446  // Statistics
447  wxBoxSizer* pStats=new wxBoxSizer(wxHORIZONTAL);
448 
449  WXFieldPar<REAL> *pWXFieldChi2=new WXFieldPar<REAL>(this,"Chi^2",-1,&mChi2,140);
450  pStats->Add(pWXFieldChi2 ,0,wxALIGN_CENTER);
451  mList.Add(pWXFieldChi2);
452  pWXFieldChi2->SetToolTip(_T("Chi^2=SUM[(Obs_i-Calc_i)^2/Sigma_i^2]"));
453  dynamic_cast<WXFieldParBase *>(pWXFieldChi2)->SetFormat(_T("%10.2f"));
454 
455  WXFieldPar<REAL> *pWXFieldGof=new WXFieldPar<REAL>(this,"GoF",-1,&mGoF,90);
456  pStats->Add(pWXFieldGof ,0,wxALIGN_CENTER);
457  mList.Add(pWXFieldGof);
458  pWXFieldGof->SetToolTip(_T("GoF=Chi^2/NbPoints"));
459  dynamic_cast<WXFieldParBase *>(pWXFieldGof)->SetFormat(_T("%8.3f"));
460 
461  WXFieldPar<REAL> *pWXFieldRwp=new WXFieldPar<REAL>(this,"Rwp",-1,&mRwp,70);
462  pStats->Add(pWXFieldRwp ,0,wxALIGN_CENTER);
463  mList.Add(pWXFieldRwp);
464  pWXFieldRwp->SetToolTip(_T("Full profile R-factor (weighted)\n")
465  _T("Will use integrated profiles if option is set."));
466  dynamic_cast<WXFieldParBase *>(pWXFieldRwp)->SetFormat(_T("%8.4f"));
467 
468  WXFieldPar<REAL> *pWXFieldRp=new WXFieldPar<REAL>(this,"Rp",-1,&mRp,70);
469  pStats->Add(pWXFieldRp ,0,wxALIGN_CENTER);
470  mList.Add(pWXFieldRp);
471  pWXFieldRp->SetToolTip(_T("Full profile R-factor (unweighted)\n")
472  _T("Will use integrated profiles if option is set."));
473  dynamic_cast<WXFieldParBase *>(pWXFieldRp)->SetFormat(_T("%8.4f"));
474  //pStats->SetSizeHints(this);
475  //pStats->Layout();
476 
477  mpSizer->Add(pStats);
478  // Components
479  mpWXComponent=mpPowderPattern
480  ->mPowderPatternComponentRegistry.WXCreate(this);
481  mpSizer->Add(mpWXComponent,0,wxALIGN_LEFT);
482  mList.Add(mpWXComponent);
483 
484  VFN_DEBUG_MESSAGE("WXPowderPattern::WXPowderPattern():1",6)
485  this->CrystUpdate(true);
486  {
487  if(!wxConfigBase::Get()->HasEntry(_T("PowderPattern/BOOL/Automatically open powder pattern graph")))
488  wxConfigBase::Get()->Write(_T("PowderPattern/BOOL/Automatically open powder pattern graph"), false);
489  else
490  {
491  bool val;
492  wxConfigBase::Get()->Read(_T("PowderPattern/BOOL/Automatically open powder pattern graph"), &val);
493  if(val)
494  {
495  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED,ID_POWDER_MENU_GRAPH);
496  wxPostEvent(this,event);
497  }
498  }
499  }
500  VFN_DEBUG_MESSAGE("WXPowderPattern::WXPowderPattern():End",6)
501 }
502 
503 void WXPowderPattern::CrystUpdate(const bool uui,const bool lock)
504 {
505  VFN_DEBUG_ENTRY("WXPowderPattern::CrystUpdate()",7)
506  wxWakeUpIdle();
507  if(lock) mMutex.Lock();
509 
510  if(mpPowderPattern->GetNbPoint()<=0)
511  {
512  if(lock) mMutex.Unlock();
513  this->WXRefinableObj::CrystUpdate(uui,lock);
514  return;// nothing to display yet
515  }
516 
517  // Will force re-generating reflection list if the wavelength,
518  // or lattice par, or the spacegroup has changed.
519  VFN_DEBUG_MESSAGE("WXPowderPattern::CrystUpdate()",7)
520  mpPowderPattern->Prepare();
521  VFN_DEBUG_MESSAGE("WXPowderPattern::CrystUpdate()",7)
522 
523  mChi2=mpPowderPattern->GetChi2_Option();
524  if(mpPowderPattern->mNbPointUsed>0)
525  mGoF=mpPowderPattern->GetChi2()/mpPowderPattern->mNbPointUsed;
526  else mGoF=0;
527  //cout<<"WXPowderPattern::CrystUpdate():"<<mpPowderPattern->GetChi2()<<"/"<<mpPowderPattern->mNbPointUsed<<"="<<mGoF<<endl;
528  mRwp=mpPowderPattern->GetRw();
529  mRp=mpPowderPattern->GetR();
530 
531  if(mpGraph!=0)
532  {
533  CrystVector_REAL tmp;
534  mpPowderPattern->CalcPowderPattern();
535  tmp=mpPowderPattern->GetPowderPatternVariance();
536  for(long i=0;i<tmp.numElements();i++)
537  {
538  if(tmp(i)<0) tmp(i)=0;
539  else tmp(i)=sqrt(tmp(i));
540  }
541  mpGraph->SetPattern( mpPowderPattern->GetPowderPatternX(),
542  mpPowderPattern->GetPowderPatternObs(),
543  mpPowderPattern->GetPowderPatternCalc(),
544  tmp,
545  mpPowderPattern->GetChi2Cumul());
546  }
547  if(lock) mMutex.Unlock();
548  this->WXRefinableObj::CrystUpdate(uui,lock);
549  VFN_DEBUG_EXIT("WXPowderPattern::CrystUpdate()",7)
550 }
551 
552 void WXPowderPattern::OnMenuAddCompBackgd(wxCommandEvent & WXUNUSED(event))
553 {
554  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuAddCompBackgd()",6)
556  const unsigned int nb=mpPowderPattern->GetNbPowderPatternComponent();
557  bool hasBack=false;
558  for(unsigned int i=0;i<nb;i++)
559  if(mpPowderPattern->GetPowderPatternComponent(i).GetClassName()=="PowderPatternBackground")
560  {
561  hasBack=true;
562  break;
563  }
564  if(hasBack)
565  {
566  wxMessageDialog dialog(this,_T("You already have one background !\n")
567  _T(" Are you sure you want to add one ?"),
568  _T("Warning : Duplicate Background !"),
569  wxYES_NO|wxICON_HAND|wxNO_DEFAULT);
570  if(wxID_YES!=dialog.ShowModal())
571  return;
572  }
573  PowderPatternBackground *backgdData= new PowderPatternBackground;
574  mpPowderPattern->AddPowderPatternComponent(*backgdData);
575  if(mpGraph!=0) mpPowderPattern->Prepare();//else this will be done when opening the graph
576  wxTheApp->GetTopWindow()->Layout();
577  wxTheApp->GetTopWindow()->SendSizeEvent();
578 }
579 
580 void WXPowderPattern::OnMenuAddCompBackgdBayesian(wxCommandEvent & WXUNUSED(event))
581 {
582  VFN_DEBUG_ENTRY("WXPowderPattern::OnMenuAddCompBackgdBayesian()",6)
584  const unsigned int nb=mpPowderPattern->GetNbPowderPatternComponent();
585  bool hasBack=false;
586  for(unsigned int i=0;i<nb;i++)
587  if(mpPowderPattern->GetPowderPatternComponent(i).GetClassName()=="PowderPatternBackground")
588  {
589  hasBack=true;
590  break;
591  }
592  if(hasBack)
593  {
594  wxMessageDialog dialog(this,_T("You already have one background !\n")
595  _T(" Are you sure you want to add one ?"),
596  _T("Warning : Duplicate Background !"),
597  wxYES_NO|wxICON_HAND|wxNO_DEFAULT);
598  if(wxID_YES!=dialog.ShowModal())
599  return;
600  }
601 
602  long nbPointSpline=20;
603  wxString mes=_T("Number of Interpolation Points");
604  wxString s;
605  s.Printf(_T("%ld"),nbPointSpline);
606  wxTextEntryDialog dialog(this,mes,_T("Automatic Bayesian (David-Sivia) Background"),
607  s,wxOK | wxCANCEL);
608  if(wxID_OK!=dialog.ShowModal())
609  {
610  VFN_DEBUG_EXIT("WXPowderPattern::OnMenuAddCompBackgdBayesian():Canceled",6)
611  return;
612  }
613  dialog.GetValue().ToLong(&nbPointSpline);
614  if(nbPointSpline<=1)nbPointSpline=2;
615 
616  wxProgressDialog dlgProgress(_T("Automatic Bayesian Background"),_T("Automatic Background: Initializing..."),
617  4,this,wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME|wxPD_CAN_ABORT);
618 
619  PowderPatternBackground *pBckgd= new PowderPatternBackground;
620  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuAddCompBackgdBayesian()",6)
621  mpPowderPattern->AddPowderPatternComponent(*pBckgd);
622  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuAddCompBackgdBayesian()",6)
623  {
624  CrystVector_REAL x(nbPointSpline),backgd(nbPointSpline);
625  const CrystVector_REAL *pObs=&(pBckgd->GetParentPowderPattern().GetPowderPatternObs());
626  const unsigned long nbPoint=pBckgd->GetParentPowderPattern().GetNbPoint();
627  const float xmin=pBckgd->GetParentPowderPattern().GetPowderPatternX()(0),
628  xmax=pBckgd->GetParentPowderPattern().GetPowderPatternX()(nbPoint-1);
629  for(int i=0;i<nbPointSpline;i++)
630  {// xmax is not necessarily > xmin, but in the right order (TOF)
631  x(i)=xmin+(xmax-xmin)/(REAL)(nbPointSpline-1)*REAL(i);
632  REAL x1=xmin+(xmax-xmin)/(REAL)(nbPointSpline-1)*REAL(i-.2);
633  REAL x2=xmin+(xmax-xmin)/(REAL)(nbPointSpline-1)*REAL(i+.2);
634  long n1=(long)(pBckgd->GetParentPowderPattern().X2Pixel(x1));
635  long n2=(long)(pBckgd->GetParentPowderPattern().X2Pixel(x2));
636  if(n1<0) n1=0;
637  if(n2>(long)nbPoint)n2=nbPoint;
638  backgd(i)=(*pObs)(n1);
639  for(long j=n1;j<n2;j++)
640  if((*pObs)(j)<backgd(i))backgd(i)=(*pObs)(j);
641  }
642  pBckgd->SetInterpPoints(x,backgd);
643  }
644  if(mpGraph!=0) mpPowderPattern->Prepare();//else this will be done when opening the graph
645 
646  pBckgd->UnFixAllPar();
647  pBckgd->GetOption(0).SetChoice(0);//linear
648  if(dlgProgress.Update(1,_T("Automatic Background: Optimizing Linear Model..."))==false) return;
649  pBckgd->OptimizeBayesianBackground();
650  pBckgd->GetOption(0).SetChoice(1);//spline
651  if(dlgProgress.Update(2,_T("Automatic Background: Optimizing Spline Model..."))==false) return;
652  pBckgd->OptimizeBayesianBackground();
653  pBckgd->FixAllPar();
654 
655  wxTheApp->GetTopWindow()->Layout();
656  wxTheApp->GetTopWindow()->SendSizeEvent();
657  VFN_DEBUG_EXIT("WXPowderPattern::OnMenuAddCompBackgdBayesian()",6)
658 }
659 
660 void WXPowderPattern::OnMenuAddCompCryst(wxCommandEvent & WXUNUSED(event))
661 {
662  VFN_DEBUG_ENTRY("WXPowderPattern::OnMenuAddCompCryst()",10)
664  PowderPatternDiffraction * diffData=new PowderPatternDiffraction;
665  int choice;
666  Crystal *cryst=dynamic_cast<Crystal*>
668  "Choose a Crystal Structure:",choice));
669  if(0==cryst) {delete diffData;return;}
670  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuAddCompCryst()",10)
671  diffData->SetCrystal(*cryst);
672  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuAddCompCryst()",10)
673  mpPowderPattern->AddPowderPatternComponent(*diffData);
674  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuAddCompCryst()",10)
675  if(diffData->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF)
676  {
677  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuAddCompCryst()",10)
678  //wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED,ID_POWDERDIFF_PROFILE_DEPV);
679  //wxPostEvent(diffData->WXGet(),event);
680  ReflectionProfileDoubleExponentialPseudoVoigt *p=
681  new ReflectionProfileDoubleExponentialPseudoVoigt
682  (diffData->GetCrystal());
683  diffData->SetProfile(p);
684  }
685  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuAddCompCryst()",10)
686  if(mpGraph!=0) mpPowderPattern->Prepare();//else this will be done when opening the graph
687  wxTheApp->GetTopWindow()->Layout();
688  wxTheApp->GetTopWindow()->SendSizeEvent();
689  this->CrystUpdate();
690  VFN_DEBUG_EXIT("WXPowderPattern::OnMenuAddCompCryst()",10)
691 }
692 
693 class WXPowderPatternGraphFrame :public wxFrame
694 {
695 public:
696  WXPowderPatternGraphFrame(wxWindow *parent, wxWindowID id, const wxString& title, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE, const wxString& name = wxFrameNameStr) :
697  wxFrame(parent, id, title, pos, size, style, name)
698  {}
699  ~WXPowderPatternGraphFrame()
700  {
701  gvWindowPosition[ID_POWDER_GRAPH_WIN] = make_pair(this->GetScreenPosition(), this->GetSize());
702  }
703 };
704 
705 void WXPowderPattern::OnMenuShowGraph(wxCommandEvent & WXUNUSED(event))
706 {
707  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuShowGraph()"<<mpGraph,6)
708  if(mpGraph!=0) return;
709  if(mpPowderPattern->GetNbPoint()<=0) return;
711  mpPowderPattern->Prepare();
712  wxFrame* frame;
713  if(gvWindowPosition.count(ID_POWDER_GRAPH_WIN))
714  frame = new WXPowderPatternGraphFrame(this, ID_POWDER_GRAPH_WIN, wxString::FromAscii(mpPowderPattern->GetName().c_str()),
715  gvWindowPosition[ID_POWDER_GRAPH_WIN].first,
716  gvWindowPosition[ID_POWDER_GRAPH_WIN].second,wxCLOSE_BOX|wxRESIZE_BORDER|wxCAPTION);//wxFRAME_FLOAT_ON_PARENT
717  else
718  frame = new WXPowderPatternGraphFrame(this, ID_POWDER_GRAPH_WIN, wxString::FromAscii(mpPowderPattern->GetName().c_str()),
719  wxDefaultPosition,wxSize(500,300),wxCLOSE_BOX|wxRESIZE_BORDER|wxCAPTION);//wxFRAME_FLOAT_ON_PARENT
720  mpGraph = new WXPowderPatternGraph(frame,this);
721 
722  wxSizer *ps=new wxBoxSizer(wxHORIZONTAL);
723  ps->Add(mpGraph,1,wxEXPAND);
724  frame->SetSizer(ps);
725  frame->SetAutoLayout(true);
726 
727  frame->CreateStatusBar(2);
728  frame->Show(true);
729  frame->Raise();
730  this->CrystUpdate(true);
731  //frame->SetStatusText("");
732 }
733 
734 void WXPowderPattern::OnMenuSaveText(wxCommandEvent & WXUNUSED(event))
735 {
736  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuSaveText()",6)
738  wxFileDialog save(this,_T("Choose a file"),_T(""),_T(""),_T("*.txt"),wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
739  if(save.ShowModal() != wxID_OK) return;
740 
741  ofstream out(save.GetPath().ToAscii());
742  if(!out) return;//:TODO:
743  mpPowderPattern->PrintObsCalcData(out);
744  out.close();
745 }
746 
747 void WXPowderPattern::OnMenuSimulate(wxCommandEvent & WXUNUSED(event))
748 {
749  VFN_DEBUG_ENTRY("WXPowderPattern::OnMenuSimulate()",6)
751  double min=0.,max=120.;
752  long nbPoints=6000;
753  {
754  wxTextEntryDialog dialog(this,_T("2Theta Min"),
755  _T("Enter minimum 2Theta (degrees)"),_T("5"),wxOK | wxCANCEL);
756  if(wxID_OK!=dialog.ShowModal())
757  {
758  VFN_DEBUG_EXIT("WXPowderPattern::OnMenuSimulate():Cancelled",6)
759  return;
760  }
761  dialog.GetValue().ToDouble(&min);
762  if(min<1) min=1.0;
763  }
764  {
765  wxTextEntryDialog dialog(this,_T("2Theta Max"),
766  _T("Enter maximum 2Theta (degrees)"),_T("100"),wxOK | wxCANCEL);
767  if(wxID_OK!=dialog.ShowModal())
768  {
769  VFN_DEBUG_EXIT("WXPowderPattern::OnMenuSimulate():Cancelled",6)
770  return;
771  }
772  dialog.GetValue().ToDouble(&max);
773  }
774  {
775  wxTextEntryDialog dialog(this,_T("Number of points"),
776  _T("Enter the number of points"),_T("1000"),wxOK | wxCANCEL);
777  if(wxID_OK!=dialog.ShowModal())
778  {
779  VFN_DEBUG_EXIT("WXPowderPattern::OnMenuSimulate():Cancelled",6)
780  return;
781  }
782  dialog.GetValue().ToLong(&nbPoints);
783  }
784  CrystVector_REAL newObs(nbPoints);
785  mpPowderPattern->SetPowderPatternPar(min*DEG2RAD,(max-min)/(nbPoints-1)*DEG2RAD,nbPoints);
786  newObs=1;//we must not have 0 in case a scale factor is fitted...
787  newObs(0)=0.01;//Avoid having the same value for ALL points for scaling the graph.
788  if(mpPowderPattern->GetNbPowderPatternComponent()>0)
789  {
790  // Use the calculated pattern, for indexing simulation
791  newObs=mpPowderPattern->GetPowderPatternCalc();
792  // Add some noise !
793  for(long i=0;i<newObs.numElements();++i)
794  newObs(i) += sqrt(newObs(i))*(2*rand()/(REAL)RAND_MAX-1);
795  }
796  mpPowderPattern->SetPowderPatternObs(newObs);
797  VFN_DEBUG_EXIT("WXPowderPattern::OnMenuSimulate()",6)
798 }
799 
800 void WXPowderPattern::OnMenuImportPattern(wxCommandEvent &event)
801 {
802  VFN_DEBUG_MESSAGE("WXPowderPattern::OnMenuImportPattern()",6)
803  wxFileDialog open(this,_T("Choose a file"),_T(""),_T(""),_T("*.*"),wxFD_OPEN | wxFD_FILE_MUST_EXIST);
804  if(open.ShowModal() != wxID_OK) return;
805  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_FULLPROF)
806  mpPowderPattern->ImportPowderPatternFullprof(string(open.GetPath().ToAscii()));
807  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_PSI_DMC)
808  mpPowderPattern->ImportPowderPatternPSI_DMC(string(open.GetPath().ToAscii()));
809  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_ILL_D1A5)
810  mpPowderPattern->ImportPowderPatternILL_D1A5(string(open.GetPath().ToAscii()));
811  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_XDD)
812  mpPowderPattern->ImportPowderPatternXdd(string(open.GetPath().ToAscii()));
813  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_CPI)
814  mpPowderPattern->ImportPowderPatternSietronicsCPI(string(open.GetPath().ToAscii()));
815  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_FULLPROF4)
816  mpPowderPattern->ImportPowderPatternFullprof4(string(open.GetPath().ToAscii()));
817  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_MULTIDETECTORLLBG42)
818  mpPowderPattern->ImportPowderPatternMultiDetectorLLBG42(string(open.GetPath().ToAscii()));
819  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_2THETAOBSSIGMA)
820  mpPowderPattern->ImportPowderPattern2ThetaObsSigma(string(open.GetPath().ToAscii()));
821  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_2THETAOBS)
822  mpPowderPattern->ImportPowderPattern2ThetaObs(string(open.GetPath().ToAscii()));
823  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_TOFISISXYSIGMA)
824  mpPowderPattern->ImportPowderPatternTOF_ISIS_XYSigma(string(open.GetPath().ToAscii()));
825  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_GSAS)
826  mpPowderPattern->ImportPowderPatternGSAS(string(open.GetPath().ToAscii()));
827  if(event.GetId()==(long)ID_POWDER_MENU_IMPORT_CIF)
828  {
829  ifstream fin (open.GetPath().ToAscii());
830  if(!fin)
831  {
832  throw ObjCrystException("WXPowderPattern::OnMenuImportPattern(): Error opening file for input:"+string(open.GetPath().ToAscii()));
833  }
834  ObjCryst::CIF cif(fin,true,true);
835  mpPowderPattern->ImportPowderPatternCIF(cif);
836  }
837  bool val;
838  wxConfigBase::Get()->Read(_T("PowderPattern/BOOL/Automatically open powder pattern graph"), &val);
839  if(val)
840  {
841  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED,ID_POWDER_MENU_GRAPH);
842  wxPostEvent(this,event);
843  }
844 }
845 
846 void WXPowderPattern::OnMenuFitScaleForR(wxCommandEvent & WXUNUSED(event))
847 {
848  if(0==mpGraph) return;
850  mpPowderPattern->FitScaleFactorForR();//FitScaleFactorForIntegratedR
851  this->CrystUpdate(true);
852 }
853 
854 void WXPowderPattern::OnMenuFitScaleForRw(wxCommandEvent & WXUNUSED(event))
855 {
856  if(0==mpGraph) return;
858  mpPowderPattern->FitScaleFactorForRw();//FitScaleFactorForIntegratedRw
859  this->CrystUpdate(true);
860 }
861 
862 
863 void WXPowderPattern::OnMenuSetWavelength(wxCommandEvent & event)
864 {
866  // this looks stupid. In fact, if a user changed the wavelength in the
867  // corresponding field, this is (unfortunately) not applied to the
868  // components automagically. So we need this function to do the job...
869  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_XRAY)
870  mpPowderPattern->SetRadiationType(RAD_XRAY);
871  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_NEUTRON)
872  mpPowderPattern->SetRadiationType(RAD_NEUTRON);
873  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_NEUTRON_TOF)
874  {
875  mpPowderPattern->SetRadiationType(RAD_NEUTRON);
876  mpPowderPattern->GetRadiation().SetWavelengthType(WAVELENGTH_TOF);
877  }
878  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET)
879  {
880  double lambda;
881  wxTextEntryDialog dialog(this,_T("new Wavelength)"),
882  _T("Enter new Wavelength (Angstroems)"),_T("1"),wxOK | wxCANCEL);
883  if(wxID_OK!=dialog.ShowModal())
884  {
885  VFN_DEBUG_EXIT("WXPowderPattern))OnMenuSetWavelength())Monochromatic)Cancelled",6)
886  return;
887  }
888  dialog.GetValue().ToDouble(&lambda);
889  mpPowderPattern->SetWavelength(lambda);
890  }
891  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_AG)
892  mpPowderPattern->SetWavelength("Ag");
893  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_MO)
894  mpPowderPattern->SetWavelength("Mo");
895  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_CU)
896  mpPowderPattern->SetWavelength("Cu");
897  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_FE)
898  mpPowderPattern->SetWavelength("Fe");
899  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_CO)
900  mpPowderPattern->SetWavelength("Co");
901  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_CR)
902  mpPowderPattern->SetWavelength("Cr");
903  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_AGA1)
904  mpPowderPattern->SetWavelength("AgA1");
905  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_MOA1)
906  mpPowderPattern->SetWavelength("MoA1");
907  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_CUA1)
908  mpPowderPattern->SetWavelength("CuA1");
909  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_FEA1)
910  mpPowderPattern->SetWavelength("FeA1");
911  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_COA1)
912  mpPowderPattern->SetWavelength("CoA1");
913  if(event.GetId()== ID_POWDER_MENU_WAVELENGTH_SET_CRA1)
914  mpPowderPattern->SetWavelength("CrA1");
915  this->CrystUpdate(true);
916 }
917 
918 void WXPowderPattern::OnMenuAddExclude(wxCommandEvent & WXUNUSED(event))
919 {
921  double min,max;
922  //min
923  {
924  wxString txt=_T("Enter Min 2theta to exclude (degrees):");
925  if(mpPowderPattern->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF)
926  txt=_T("Enter Min 2theta to exclude (microseconds):");
927  wxTextEntryDialog dialog(this,_T("Min"),txt,_T("0"),wxOK | wxCANCEL);
928  if(wxID_OK!=dialog.ShowModal())
929  {
930  VFN_DEBUG_EXIT("WXPowderPattern::OnMenuAddExclude():Cancelled",6)
931  return;
932  }
933  dialog.GetValue().ToDouble(&min);
934  }
935  //max
936  {
937  wxString txt=_T("Enter Max 2theta to exclude (degrees):");
938  if(mpPowderPattern->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF)
939  txt=_T("Enter Max 2theta to exclude (microseconds):");
940  wxTextEntryDialog dialog(this,_T("Max"),txt,_T("5"),wxOK | wxCANCEL);
941  if(wxID_OK!=dialog.ShowModal())
942  {
943  VFN_DEBUG_EXIT("WXPowderPattern::OnMenuAddExclude():Cancelled",6)
944  return;
945  }
946  dialog.GetValue().ToDouble(&max);
947  }
948  if(max<min)
949  {
950  VFN_DEBUG_EXIT("WXPowderPattern::OnMenuAddExclude():Stupid user.",6)
951  return;
952  }
953  if(mpPowderPattern->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF)
954  mpPowderPattern->AddExcludedRegion(min,max);
955  else mpPowderPattern->AddExcludedRegion(min*DEG2RAD,max*DEG2RAD);
956 }
957 
958 void WXPowderPattern::OnMenuLeBail(wxCommandEvent& event)
959 {
960  #if 0
961  wxFrame *pFrame=new wxFrame(this,-1,_T("Profile Fitting"));
962  WXProfileFitting *pFit;
963  pFit=new WXProfileFitting(pFrame,&(this->GetPowderPattern()));
964  pFrame->Show(true);
965  #else
966  cout<<"Beginning refinement"<<endl;
967  LSQNumObj lsq;
968  lsq.SetRefinedObj(this->GetPowderPattern(),0,true,true);
969  lsq.PrepareRefParList(true);
971  lsq.SetParIsFixed(gpRefParTypeScatt,false);
973  //lsq.SetParIsUsed(gpRefParTypeScattDataProfile,true);
974  //lsq.SetParIsUsed(gpRefParTypeScattDataCorrPos,true);
975  //lsq.SetParIsUsed(gpRefParTypeScattDataBackground,true);
976  //lsq.SetParIsUsed(gpRefParTypeUnitCell,true);
977  try {lsq.Refine(10,true,false);}
978  catch(const ObjCrystException &except){};
979  cout<<"Finishing refinement"<<endl;
980  this->GetPowderPattern().UpdateDisplay();
981  #endif
982 }
983 
984 void WXPowderPattern::OnMenuExport(wxCommandEvent &event)
985 {
987  wxFileDialog save(this,_T("Choose a .pcr file"),_T(""),_T(""),_T("*.pcr"),wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
988  if(save.ShowModal() != wxID_OK) return;
989 
990  wxString path,name,ext;
991  wxFileName::SplitPath(save.GetPath(), &path, &name, &ext, wxPATH_NATIVE);
992  wxString mes;
993  wxString pcr=path+wxFileName::GetPathSeparator()+name+_T(".pcr");
994  wxString dat=path+wxFileName::GetPathSeparator()+name+_T(".dat");
995  mes.Printf(_T("This will create the files:\n %s\n %s"),pcr.c_str(),dat.c_str());
996  wxMessageDialog mesd(this,mes,_T("Files"),wxOK|wxCANCEL|wxICON_INFORMATION);
997  if(mesd.ShowModal()==wxID_OK)
998  mpPowderPattern->ExportFullprof(string((path+wxFileName::GetPathSeparator()+name).ToAscii()));
999 }
1000 
1001 void WXPowderPattern::NotifyDeleteGraph() {mpGraph=0;}
1002 const PowderPattern& WXPowderPattern::GetPowderPattern()const
1003 { return *mpPowderPattern;}
1004 
1005 PowderPattern& WXPowderPattern::GetPowderPattern()
1006 { return *mpPowderPattern;}
1007 
1008 void WXPowderPattern::UpdateUI(const bool lock)
1009 {
1010  if(lock)mMutex.Lock();
1011  if(mpGraph!=0)
1012  {
1013  mpGraph->GetParent()->SetLabel(wxString::FromAscii(mpPowderPattern->GetName().c_str()));
1014  }
1015  this->WXRefinableObj::UpdateUI(false);
1016  if(lock)mMutex.Unlock();
1017 }
1019 //
1020 // WXPowderPatternGraph
1021 //
1023 static const long ID_POWDERGRAPH_MENU_UPDATE= WXCRYST_ID();
1024 static const long ID_POWDERGRAPH_MENU_TOGGLELABEL= WXCRYST_ID();
1025 static const long ID_POWDERGRAPH_MENU_TOGGPEAK= WXCRYST_ID();
1026 static const long ID_POWDERGRAPH_MENU_FINDPEAKS= WXCRYST_ID();
1027 static const long ID_POWDERGRAPH_MENU_LOADPEAKS= WXCRYST_ID();
1028 static const long ID_POWDERGRAPH_MENU_SAVEPEAKS= WXCRYST_ID();
1029 static const long ID_POWDERGRAPH_MENU_ADDPEAK= WXCRYST_ID();
1030 static const long ID_POWDERGRAPH_MENU_REMOVEPEAK= WXCRYST_ID();
1031 static const long ID_POWDERGRAPH_MENU_INDEX= WXCRYST_ID();
1032 static const long ID_POWDERGRAPH_MENU_XSCALE_DATA= WXCRYST_ID();
1033 static const long ID_POWDERGRAPH_MENU_XSCALE_D= WXCRYST_ID();
1034 static const long ID_POWDERGRAPH_MENU_XSCALE_2PID= WXCRYST_ID();
1035 static const long ID_POWDERGRAPH_MENU_YSCALE_LINEAR= WXCRYST_ID();
1036 static const long ID_POWDERGRAPH_MENU_YSCALE_SQRT= WXCRYST_ID();
1037 static const long ID_POWDERGRAPH_MENU_YSCALE_LOG10= WXCRYST_ID();
1038 static const long ID_POWDERGRAPH_MENU_LEBAIL= WXCRYST_ID();
1039 
1040 BEGIN_EVENT_TABLE(WXPowderPatternGraph, wxWindow)
1041  EVT_PAINT( WXPowderPatternGraph::OnPaint)
1042  EVT_MOUSE_EVENTS( WXPowderPatternGraph::OnMouse)
1043  EVT_MENU(ID_POWDERGRAPH_MENU_UPDATE, WXPowderPatternGraph::OnUpdate)
1044  EVT_MENU(ID_POWDERGRAPH_MENU_TOGGLELABEL, WXPowderPatternGraph::OnToggleLabel)
1045  EVT_MENU(ID_POWDERGRAPH_MENU_TOGGPEAK, WXPowderPatternGraph::OnToggleLabel)
1046  EVT_MENU(ID_POWDERGRAPH_MENU_FINDPEAKS, WXPowderPatternGraph::OnFindPeaks)
1047  EVT_MENU(ID_POWDERGRAPH_MENU_LOADPEAKS, WXPowderPatternGraph::OnLoadPeaks)
1048  EVT_MENU(ID_POWDERGRAPH_MENU_SAVEPEAKS, WXPowderPatternGraph::OnSavePeaks)
1049  EVT_MENU(ID_POWDERGRAPH_MENU_ADDPEAK, WXPowderPatternGraph::OnChangePeak)
1050  EVT_MENU(ID_POWDERGRAPH_MENU_REMOVEPEAK, WXPowderPatternGraph::OnChangePeak)
1051  EVT_MENU(ID_POWDERGRAPH_MENU_INDEX, WXPowderPatternGraph::OnIndex)
1052  EVT_MENU(ID_POWDERGRAPH_MENU_XSCALE_DATA, WXPowderPatternGraph::OnChangeScale)
1053  EVT_MENU(ID_POWDERGRAPH_MENU_XSCALE_D, WXPowderPatternGraph::OnChangeScale)
1054  EVT_MENU(ID_POWDERGRAPH_MENU_XSCALE_2PID, WXPowderPatternGraph::OnChangeScale)
1055  EVT_MENU(ID_POWDERGRAPH_MENU_YSCALE_LINEAR, WXPowderPatternGraph::OnChangeScale)
1056  EVT_MENU(ID_POWDERGRAPH_MENU_YSCALE_SQRT, WXPowderPatternGraph::OnChangeScale)
1057  EVT_MENU(ID_POWDERGRAPH_MENU_YSCALE_LOG10, WXPowderPatternGraph::OnChangeScale)
1058  EVT_MENU(ID_POWDERGRAPH_MENU_LEBAIL, WXPowderPatternGraph::OnLeBail)
1059  EVT_UPDATE_UI(ID_POWDER_GRAPH_NEW_PATTERN, WXPowderPatternGraph::OnRedrawNewPattern)
1060  EVT_CHAR( WXPowderPatternGraph::OnKeyDown)
1061  EVT_MOUSEWHEEL( WXPowderPatternGraph::OnMouseWheel)
1062  EVT_SIZE( WXPowderPatternGraph::OnSize)
1063 END_EVENT_TABLE()
1064 
1066 wxWindow(frame,-1,wxPoint(-1,-1),wxSize(-1,-1)),
1067 mpPattern(parent),mMargin(20),mDiffPercentShift(.20),
1068 mMaxIntensity(-1),mMinIntensity(-1),mMinX(-1),mMaxX(-1),
1069 mDefaultIntensityScale(true),
1070 mpParentFrame(frame),
1071 mIsDragging(false),mDisplayLabel(true),mDisplayPeak(true)
1072 {
1073  mpPopUpMenu=new wxMenu(_T("Powder Pattern"));
1074  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_UPDATE, _T("&Update"));
1075  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_TOGGLELABEL, _T("&Hide labels"));
1076  #if 1
1077  mpPopUpMenu->AppendSeparator();
1078  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_FINDPEAKS, _T("&Find peaks"));
1079  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_LOADPEAKS, _T("&Load peaks"));
1080  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_SAVEPEAKS, _T("&Save peaks"));
1081  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_INDEX, _T("&Index !"));
1082  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_TOGGPEAK, _T("&Hide peaks"));
1083  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_ADDPEAK, _T("&Add peak"));
1084  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_REMOVEPEAK, _T("&Remove peak"));
1085  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_SAVEPEAKS, FALSE);
1086  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_TOGGPEAK, FALSE);
1087  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_ADDPEAK, TRUE);
1088  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_REMOVEPEAK, FALSE);
1089  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_INDEX, FALSE);
1090  #endif
1091  mpPopUpMenu->AppendSeparator();
1092  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_LEBAIL, _T("Fit &Profile + Le Bail extraction"));
1093  mpPopUpMenu->AppendSeparator();
1094  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_XSCALE_DATA, _T("&X scale: 2theta/TOF"));
1095  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_XSCALE_D, _T("&X scale: Q=1/d"));
1096  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_XSCALE_2PID, _T("&X scale: Q=2pi/d"));
1097  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_YSCALE_LINEAR, _T("&Y scale: I"));
1098  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_YSCALE_SQRT, _T("&Y scale: sqrt(I)"));
1099  mpPopUpMenu->Append(ID_POWDERGRAPH_MENU_YSCALE_LOG10, _T("&Y scale: log10(I)"));
1100  if(!wxConfigBase::Get()->HasEntry(_T("PowderPattern/BOOL/Default-display reflection indices")))
1101  wxConfigBase::Get()->Write(_T("PowderPattern/BOOL/Default-display reflection indices"), mDisplayLabel);
1102  else
1103  {
1104  wxConfigBase::Get()->Read(_T("PowderPattern/BOOL/Default-display reflection indices"), &mDisplayLabel);
1105  if(mDisplayLabel) mpPopUpMenu->SetLabel(ID_POWDERGRAPH_MENU_TOGGLELABEL, _T("Hide labels"));
1106  else mpPopUpMenu->SetLabel(ID_POWDERGRAPH_MENU_TOGGLELABEL, _T("Show labels"));
1107  }
1108 
1109  // Scale used to display graph x coordinates : 0 - experimental ; 1 - 1/d ; 2 - 2pi/d
1110  if(!wxConfigBase::Get()->HasEntry(_T("PowderPattern/LONG/graph x scale")))
1111  wxConfigBase::Get()->Write(_T("PowderPattern/LONG/graph x scale"), 0);
1112 
1113  // Scale used to display graph y coordinates : 0 - linear ; 1 - square root ; 2 - log10
1114  if(!wxConfigBase::Get()->HasEntry(_T("PowderPattern/LONG/graph y scale")))
1115  wxConfigBase::Get()->Write(_T("PowderPattern/LONG/graph y scale"), 0);
1116 
1117  wxConfigBase::Get()->Read(_T("PowderPattern/LONG/graph x scale"), &mXScale);
1118  wxConfigBase::Get()->Read(_T("PowderPattern/LONG/graph y scale"), &mYScale);
1119 
1120  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_DATA, TRUE);
1121  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_D, TRUE);
1122  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_2PID, TRUE);
1123  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_LINEAR, TRUE);
1124  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_SQRT, TRUE);
1125  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_LOG10, TRUE);
1126 
1127  if(mXScale==0) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_DATA, FALSE);
1128  if(mXScale==1) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_D, FALSE);
1129  if(mXScale==2) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_2PID, FALSE);
1130  if(mYScale==0)mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_LINEAR, FALSE);
1131  if(mYScale==1) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_SQRT, FALSE);
1132  if(mYScale==2) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_LOG10, FALSE);
1133 
1134  mpPattern->CrystUpdate(true);
1135 }
1136 
1137 WXPowderPatternGraph::~WXPowderPatternGraph()
1138 {
1139  mpPattern->NotifyDeleteGraph();
1140 }
1141 
1142 void WXPowderPatternGraph::OnPaint(wxPaintEvent& WXUNUSED(event))
1143 {
1144  if((mObs.numElements()<=0)||(mCalc.numElements()<=0)) return;
1145  VFN_DEBUG_MESSAGE("WXPowderPatternGraph:OnPaint()",5)
1146  unsigned int ct=0;
1147  while(wxMUTEX_NO_ERROR!=mMutex.TryLock())
1148  {
1149  if(++ct>10) return;
1150  wxMilliSleep(50);
1151  }
1152 
1153  wxBufferedPaintDC dc(this);
1154  PrepareDC(dc);
1155  mpParentFrame->PrepareDC(dc);
1156 
1157  dc.DestroyClippingRegion();
1158  dc.SetBackground(wxBrush(_T("white"), wxSOLID));
1159  dc.Clear();
1160 
1161  wxColour blue=wxColour(0,0,255);
1162  wxPen bluePen=wxPen(blue);
1163  wxString fontInfo;
1164  #ifdef __WIN32__
1165  dc.SetFont(*wxNORMAL_FONT);
1166  #else
1167  dc.SetFont(*wxSMALL_FONT);
1168  #endif
1169 
1170  long nbPoint=mX.numElements();
1171 
1172  // Get Window Size
1173  wxCoord width,height;
1174  this->GetSize(&width, &height);
1175  //const int margin=mMargin;
1176  //width -= margin;
1177  //height -= margin;
1178  VFN_DEBUG_MESSAGE("WXPowderPatternGraph:OnPaint():1",5)
1179 
1180  //Check pattern is not being updated
1181  VFN_DEBUG_MESSAGE("WXPowderPatternGraph:OnPaint():2:"<<mObs.numElements(),5)
1182 
1183  VFN_DEBUG_MESSAGE("WXPowderPatternGraph:OnPaint():3:min="
1184  <<mMinX<<", max="<<mMaxX<<", width="
1185  <<width<<",margin="<<mMargin,5)
1186  // Draw sigma bars
1187  {
1188  dc.SetPen(* wxLIGHT_GREY_PEN);
1189  wxCoord x,y1,y2;
1190  for(long i=0;i<nbPoint;i++)
1191  {
1192  if((mX(i)>mMinX)&&(mX(i)<mMaxX))
1193  {
1194  x=this->Point2ScreenX(i);
1195  y1=this->Data2ScreenY(mObs(i)-mSigma(i)/2.);
1196  y2=this->Data2ScreenY(mObs(i)+mSigma(i)/2.);
1197 
1198  dc.DrawLine(x,y1,x,y2);
1199  }
1200  }
1201  }
1202  // Draw Axis (sort of)
1203  {
1204  wxCoord tmpW,tmpH;
1205  dc.SetPen(* wxBLACK_PEN);
1206  dc.DrawLine(mMargin*3,height-mMargin,mMargin*3,mMargin);
1207  dc.DrawLine(mMargin*3,height-mMargin,width,height-mMargin);
1208  const int nbTick=10;//approximate
1209  wxCoord xc,yc;
1210  //Y axis
1211  {
1212  xc=(wxCoord)mMargin*3;
1213  REAL miny=mMinIntensity,maxy=mMaxIntensity;
1214  if(mYScale==1) {miny=sqrt(miny) ;maxy=sqrt(maxy);}
1215  if(mYScale==2) {miny=log10(miny);maxy=log10(maxy);}
1216  REAL yStep=pow((float)10,(float)floor(log10((maxy-miny)/nbTick)));
1217  yStep *= floor((maxy-miny)/yStep/nbTick);
1218  for(REAL ys=yStep*ceil(miny/yStep);ys<maxy;ys+=yStep)
1219  {
1220  REAL y=ys;
1221  if(mYScale==1) {y=ys*ys;}
1222  if(mYScale==2) {y=pow((float)10,(float)ys);}
1223  yc=this->Data2ScreenY(y);
1224  dc.DrawLine(xc-3,yc,xc+3,yc);
1225  fontInfo.Printf(_T("%g"),y);
1226  dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
1227  dc.DrawText(fontInfo,xc-tmpW-3,yc-tmpH/2);
1228  }
1229  }
1230  //X axis
1231  {
1232  yc=(wxCoord)(height-mMargin);
1233 
1234  REAL minx=mMinX,maxx=mMaxX;
1235  float mind,maxd;// 1/d
1236  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
1237  {
1238  mind=2*mpPattern->GetPowderPattern().X2STOL(minx*DEG2RAD);
1239  maxd=2*mpPattern->GetPowderPattern().X2STOL(maxx*DEG2RAD);
1240  }
1241  else
1242  {
1243  mind=2*mpPattern->GetPowderPattern().X2STOL(minx);
1244  maxd=2*mpPattern->GetPowderPattern().X2STOL(maxx);
1245  }
1246  if(mXScale==1) {minx=mind; maxx=maxd;}
1247  if(mXScale==2) {minx=2*M_PI*mind;maxx=2*M_PI*maxd;}
1248 
1249  REAL xStep=pow((float)10,(float)floor(log10((maxx-minx)/nbTick)));
1250  xStep *= floor((maxx-minx)/xStep/nbTick);
1251  for(REAL xs=xStep*ceil(minx/xStep);xs<maxx;xs+=xStep)
1252  {
1253  REAL x=xs;
1254  if(mXScale==1) {x=mpPattern->GetPowderPattern().STOL2X(xs/2);}
1255  if(mXScale==2) {x=mpPattern->GetPowderPattern().STOL2X(xs/(4*M_PI));}
1256  if(mXScale==0) xc=this->Data2ScreenX(x);
1257  else
1258  {
1259  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
1260  xc=this->Data2ScreenX(RAD2DEG*x);
1261  else xc=this->Data2ScreenX(x);
1262  }
1263  dc.DrawLine(xc,yc-3,xc,yc+3);
1264  fontInfo.Printf(_T("%g"),xs);
1265  dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
1266  dc.DrawText(fontInfo,xc-tmpW/2,yc+6);
1267  }
1268  }
1269  }
1270  // Draw cumulated Chi^2, scaled
1271  {
1272  dc.SetPen(* wxGREY_PEN);
1273  wxCoord x1,y1,x2,y2;
1274  x2=this->Point2ScreenX(0);
1275  const REAL s=(mMaxIntensity-mMinIntensity)/mChi2Cumul(mpPattern->GetPowderPattern().GetNbPointUsed()-1);
1276  y2=this->Data2ScreenY(mMinIntensity+mChi2Cumul(0)*s);
1277  for(unsigned long i=0;i<mpPattern->GetPowderPattern().GetNbPointUsed();i++)
1278  {
1279  if((mX(i)>mMinX)&&(mX(i)<mMaxX))
1280  {
1281  x1=x2;
1282  y1=y2;
1283  x2=this->Point2ScreenX(i);
1284  y2=this->Data2ScreenY(mMinIntensity+mChi2Cumul(i)*s);
1285  dc.DrawLine(x1,y1,x2,y2);
1286  }
1287  }
1288  }
1289  // Draw observed pattern
1290  VFN_DEBUG_MESSAGE("WXPowderPatternGraph:OnPaint():4:",5)
1291  {
1292  dc.SetPen(bluePen);
1293  wxCoord x1,y1,x2,y2;
1294  x2=this->Point2ScreenX(0);
1295  y2=this->Data2ScreenY(mObs(0));
1296  for(long i=0;i<nbPoint;i++)
1297  {
1298  if((mX(i)>mMinX)&&(mX(i)<mMaxX))
1299  {
1300  x1=x2;
1301  y1=y2;
1302  x2=this->Point2ScreenX(i);
1303  y2=this->Data2ScreenY(mObs(i));
1304  dc.DrawLine(x1,y1,x2,y2);
1305  }
1306  }
1307  }
1308 
1309  // Draw calculated pattern
1310  VFN_DEBUG_MESSAGE("WXPowderPatternGraph:OnPaint():5:",5)
1311  {
1312  dc.SetPen(* wxRED_PEN);
1313  wxCoord x1,y1,x2,y2;
1314  x2=this->Point2ScreenX(0);
1315  y2=this->Data2ScreenY(mCalc(0));
1316  for(long i=0;i<nbPoint;i++)
1317  {
1318  if((mX(i)>mMinX)&&(mX(i)<mMaxX))
1319  {
1320  x1=x2;
1321  y1=y2;
1322  x2=this->Point2ScreenX(i);
1323  y2=this->Data2ScreenY(mCalc(i));
1324  dc.DrawLine(x1,y1,x2,y2);
1325  }
1326  }
1327  }
1328 
1329  // Display labels ?
1330  list<list<pair<const REAL ,const string > > > vLabel;
1331  if(true==mDisplayLabel) // "vLabel=mvLabelList;" does not work (gcc 4.1.1)
1332  for(list<list<pair<const REAL ,const string > > >::const_iterator
1333  comp=mvLabelList.begin();comp!=mvLabelList.end();++comp) vLabel.push_back(*comp);
1334  // Show peaks ?
1335  if((true==mDisplayPeak)&&(mPeakList.GetPeakList().size()>0))
1336  {
1337  list<pair<const REAL ,const string > > peakLabels;
1338  char buf[50];
1339  unsigned int ix=0;
1340  for(vector<PeakList::hkl>::const_iterator pos=mPeakList.GetPeakList().begin();pos!=mPeakList.GetPeakList().end();++pos)
1341  {
1342  const float x=mpPattern->GetPowderPattern().STOL2X(pos->dobs/2);
1343  if(pos->isSpurious)
1344  {
1345  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
1346  sprintf(buf,"#%2u,x=%6.3f d=%6.3fA SPURIOUS?",ix,x*RAD2DEG,1/pos->dobs);
1347  else
1348  sprintf(buf,"#%2u,x=%6.3f d=%6.3fA SPURIOUS?",ix,x ,1/pos->dobs);
1349  }
1350  else
1351  {
1352  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
1353  sprintf(buf,"#%2u,x=%6.2f d=%6.3fA",ix,x*RAD2DEG,1/pos->dobs);
1354  else
1355  sprintf(buf,"#%2u,x=%6.2f d=%6.3fA",ix,x ,1/pos->dobs);
1356  }
1357  ++ix;
1358  peakLabels.push_back(make_pair(x,buf));
1359  }
1360  vLabel.push_back(peakLabels);
1361  // Do we have a list of predicted HKL positions as well ?
1362  if(mPeakList.mvPredictedHKL.size()>0)
1363  {
1364  peakLabels.clear();
1365  for(list<PeakList::hkl>::const_iterator pos=mPeakList.mvPredictedHKL.begin();pos!=mPeakList.mvPredictedHKL.end();++pos)
1366  {
1367  const float dobs=sqrt(pos->d2calc);
1368  const float x=mpPattern->GetPowderPattern().STOL2X(dobs/2);
1369  sprintf(buf,"?(%2d %2d %2d)?",pos->h,pos->k,pos->l);
1370  peakLabels.push_back(make_pair(x,buf));
1371  }
1372  vLabel.push_back(peakLabels);
1373  }
1374  }
1375  // Draw labels
1376  VFN_DEBUG_MESSAGE("WXPowderPatternGraph:OnPaint():5:",5)
1377  if(vLabel.size()>0)
1378  {
1379  wxCoord x,y;
1380  wxCoord tmpW,tmpH;
1381  int loop=1;
1382  REAL yr;
1383  unsigned int pen=0;
1384  unsigned int icomp=0;
1385  // First, Crystalline phases, background (empty), then list of peaks and predicted hkl list
1386  for(list<list<pair<const REAL ,const string > > >::const_iterator comp=vLabel.begin();comp!=vLabel.end();comp++)
1387  {
1388  if(comp->size()==0)
1389  {// Only background components should be empty
1390  icomp++;
1391  continue;
1392  }
1393  switch(pen)
1394  {
1395  case 0 : dc.SetPen(wxPen(wxColour( 0, 0, 0),2));dc.SetTextForeground(wxColour( 0, 0, 0));break;
1396  case 1 : dc.SetPen(wxPen(wxColour( 0, 0,255),2));dc.SetTextForeground(wxColour( 0, 0,255));break;
1397  case 2 : dc.SetPen(wxPen(wxColour( 0,255, 0),2));dc.SetTextForeground(wxColour( 0,255, 0));break;
1398  case 3 : dc.SetPen(wxPen(wxColour(255, 0, 0),2));dc.SetTextForeground(wxColour(255, 0, 0));break;
1399  case 4 : dc.SetPen(wxPen(wxColour( 0,255,255),2));dc.SetTextForeground(wxColour( 0,255,255));break;
1400  case 5 : dc.SetPen(wxPen(wxColour(255, 0,255),2));dc.SetTextForeground(wxColour(255, 0,255));break;
1401  case 6 : dc.SetPen(wxPen(wxColour(255,160, 0),2));dc.SetTextForeground(wxColour(255,160, 0));break;
1402  case 7 : dc.SetPen(wxPen(wxColour(128,128,255),2));dc.SetTextForeground(wxColour(128,128,255));break;
1403  case 8 : dc.SetPen(wxPen(wxColour(128,255,128),2));dc.SetTextForeground(wxColour(128,255,128));break;
1404  case 9 : dc.SetPen(wxPen(wxColour(255,128,128),2));dc.SetTextForeground(wxColour(255,128,128));break;
1405  case 10: dc.SetPen(wxPen(wxColour( 0, 0,128),2));dc.SetTextForeground(wxColour( 0, 0,128));break;
1406  case 11: dc.SetPen(wxPen(wxColour( 0, 80, 0),2));dc.SetTextForeground(wxColour( 0, 80, 0));break;
1407  case 12: dc.SetPen(wxPen(wxColour(128, 0, 0),2));dc.SetTextForeground(wxColour(128, 0, 0));break;
1408  default: dc.SetPen(wxPen(wxColour(128,128,128),2));dc.SetTextForeground(wxColour(128,128,128));break;
1409  }
1410  unsigned long ct=0;
1411  for(list<pair<const REAL ,const string > >::const_iterator pos=comp->begin();pos!=comp->end();++pos)
1412  {
1413  REAL point=pos->first;
1414  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
1415  point *= RAD2DEG;
1416  if((point>=mMinX)&&(point<=mMaxX))
1417  {
1418  if(++ct>200)
1419  {
1420  cout <<"Too many labels (>100): displaying only first 100 and ticking 100 more..."<<endl;
1421  break;
1422  }
1423  x=this->Data2ScreenX(point);
1424  const REAL pixel=mpPattern->GetPowderPattern().X2Pixel(pos->first);
1425  if(mCalc((long)pixel)>mObs((long)pixel)) yr=mCalc((long)pixel);
1426  else yr=mObs((long)pixel);
1427  y=this->Data2ScreenY(yr);
1428 
1429  dc.DrawLine(x,y-5,x,y-10);
1430  if(ct<100)
1431  {
1432  fontInfo.Printf(wxString::FromAscii(pos->second.c_str()));
1433  dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
1434  dc.DrawText(fontInfo,x-tmpW/2,y-tmpH*(loop++)-10);
1435  }
1436  if(loop==5) loop=1;
1437  }
1438  }
1439  // Draw legend (crystal names, Le Bail mode,...)
1440  wxString legend;
1441  if(icomp<mpPattern->GetPowderPattern().GetNbPowderPatternComponent())
1442  {
1443  PowderPatternDiffraction *pDiff=0;
1444  if(mpPattern->GetPowderPattern().GetPowderPatternComponent(icomp).GetClassName()=="PowderPatternDiffraction")
1445  {
1446  pDiff=dynamic_cast<PowderPatternDiffraction*> (&(mpPattern->GetPowderPattern().GetPowderPatternComponent(icomp)));
1447  if(pDiff->GetExtractionMode()) legend=wxString::FromAscii((pDiff->GetCrystal().GetName()+" (LE BAIL MODE)").c_str());
1448  else legend=wxString::FromAscii(pDiff->GetCrystal().GetName().c_str());
1449  }
1450  }
1451  else
1452  {
1453  if((icomp-mpPattern->GetPowderPattern().GetNbPowderPatternComponent())==0)
1454  legend="Found Peaks";
1455  else legend="Indexed HKL";
1456  }
1457  fontInfo.Printf(legend);
1458  wxCoord tmpW,tmpH;
1459  dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
1460  dc.DrawText(fontInfo,(wxCoord)mMargin*3+5,(wxCoord)(mMargin+tmpH*(pen)));
1461 
1462  ++pen;++icomp;
1463  }
1464  }
1465  mMutex.Unlock();
1466  VFN_DEBUG_MESSAGE("WXPowderPatternGraph:OnPaint():End",5)
1467 }
1468 
1469 void WXPowderPatternGraph::OnMouse(wxMouseEvent &event)
1470 {
1471  if(event.Leaving()) return;// wxMSW2.4 bug ?
1472  if(wxMUTEX_NO_ERROR!=mMutex.TryLock())
1473  {
1474  mIsDragging=false;
1475  return;
1476  }
1477  VFN_DEBUG_MESSAGE("WXPowderPatternGraph:OnMouse()"
1478  <<endl<<"IsButton():"<<event.IsButton()
1479  <<endl<<"ButtonDown():"<<event.ButtonDown()
1480  <<endl<<"Dragging():"<<event.Dragging()
1481  <<endl<<"Entering():"<<event.Entering()
1482  <<endl<<"Leaving():"<<event.Leaving()
1483  <<endl<<"GetButton()"<<event.GetButton()
1484  <<endl<<"GetWheelAxis():"<<event.GetWheelAxis()
1485  <<endl<<"GetWheelDelta():"<<event.GetWheelDelta()
1486  <<endl<<"GetWheelRotation():"<<event.GetWheelRotation()
1487  <<endl<<"Moving():"<<event.Moving()
1488  <<endl,7)
1489  // Write mouse pointer coordinates
1490  wxClientDC dc(this);
1491  PrepareDC(dc);
1492  mpParentFrame->PrepareDC(dc);
1493 
1494  wxPoint pos=event.GetPosition();
1495  const long x= dc.DeviceToLogicalX(pos.x);
1496  const long y= dc.DeviceToLogicalY(pos.y);
1497 
1498  wxCoord width,height;
1499  this->GetSize(&width, &height);
1500 
1501  if((x>width)||(y>height))
1502  {
1503  mMutex.Unlock();
1504  return;
1505  }
1506  //cout <<pos.x<<" "<<pos.y<<" "<<x<<" "<<y<<" "<<width<<" "<<height<<endl;
1507  const REAL x0=this->Screen2DataX(x);
1508  const REAL intensity=this->Screen2DataY(y);
1509  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()==WAVELENGTH_TOF)
1510  {
1511  wxString str;
1512  const long pixel=
1513  (long)(mpPattern->GetPowderPattern().X2PixelCorr(x0));
1514  str.Printf(_T("tof=%6.2f ,I=%12.2f. pixel=#%ld"),x0,intensity,pixel);
1515  mMutex.Unlock();
1516  mpParentFrame->SetStatusText(str);
1517  mMutex.Lock();
1518  str.Printf(_T("d=%6.3fA"),0.5/mpPattern->GetPowderPattern().X2STOL(x0));
1519  mMutex.Unlock();
1520  mpParentFrame->SetStatusText(str,1);
1521  mMutex.Lock();
1522  }
1523  else
1524  {
1525  const REAL intensity=this->Screen2DataY(y);
1526 
1527  wxString str;
1528  const long pixel=
1529  (long)(mpPattern->GetPowderPattern().X2PixelCorr(x0*DEG2RAD));
1530  str.Printf(_T("2theta=%6.2f ,I=%12.2f. pixel=#%ld"),x0,intensity,pixel);
1531  // SetStatusText() triggers an OnPaint event ? Avoid deadlock by releasing the data mutex..
1532  mMutex.Unlock();
1533  mpParentFrame->SetStatusText(str);
1534  mMutex.Lock();
1535  str.Printf(_T("d=%6.3fA"),0.5/mpPattern->GetPowderPattern().X2STOL(x0*DEG2RAD));
1536  mMutex.Unlock();
1537  mpParentFrame->SetStatusText(str,1);
1538  mMutex.Lock();
1539  }
1540  if (event.Dragging() && event.LeftIsDown() && (!mIsDragging))
1541  {//Begin zooming
1542  mIsDragging=true;
1543  mDraggingX0=x0;
1544  mDraggingIntensity0=intensity;
1545  mMutex.Unlock();
1546  return;
1547  }
1548  if(event.LeftUp() && mIsDragging)
1549  {//Finished zooming !
1550  VFN_DEBUG_MESSAGE("WXPowderPatternGraph::OnMouse():Finished zooming...",5)
1551  mIsDragging=false;
1552 
1553  if( (fabs(x0-mDraggingX0)<.1) || (fabs(mDraggingIntensity0-intensity)< fabs(mMaxIntensity*.02)) )
1554  {
1555  mMutex.Unlock();
1556  return;
1557  }
1558  if(mDraggingIntensity0>intensity)
1559  {
1560  if(mDraggingIntensity0<0.)
1561  {
1562  mMutex.Unlock();
1563  return;
1564  }
1565  mMinIntensity=intensity;
1566  mMaxIntensity=mDraggingIntensity0;
1567  }
1568  else
1569  {
1570  if(intensity<0.)
1571  {
1572  mMutex.Unlock();
1573  return;
1574  }
1575  mMinIntensity=mDraggingIntensity0;
1576  mMaxIntensity=intensity;
1577  }
1578  if(mDraggingX0>x0)
1579  {
1580  mMinX=x0;
1581  mMaxX=mDraggingX0;
1582  }
1583  else
1584  {
1585  mMinX=mDraggingX0;
1586  mMaxX=x0;
1587  }
1588  mDefaultIntensityScale=false;
1589  mClockAxisLimits.Click();
1590  mMutex.Unlock();
1591  wxUpdateUIEvent event(ID_POWDER_GRAPH_NEW_PATTERN);
1592  wxPostEvent(this,event);
1593  return;
1594  }
1595 
1596  if(false==event.Dragging()) mIsDragging=false;
1597 
1598  if(event.LeftDClick())
1599  {//Reset axis range
1600  mMutex.Unlock();
1601  this->ResetAxisLimits();
1602  wxUpdateUIEvent event(ID_POWDER_GRAPH_NEW_PATTERN);
1603  wxPostEvent(this,event);
1604  event.Skip();
1605  return;
1606  }
1607 
1608  if(event.RightIsDown())
1609  {//popup menu
1610  mMutex.Unlock();
1611  if(mpPattern->GetPowderPattern().IsBeingRefined())
1612  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_UPDATE, false);
1613  else
1614  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_UPDATE, true);
1615  // Store x coordinate to allow adding/removing peaks manually
1616  mDraggingX0=x;
1617  this->PopupMenu(mpPopUpMenu, event.GetX(), event.GetY() );
1618  return;
1619  }
1620  if (event.GetWheelDelta()>0)
1621  {// Wheel or double-touch event on OSX + trackpad
1622  if(event.ControlDown())
1623  {
1624  VFN_DEBUG_MESSAGE("WXPowderPatternGraph::OnMouse(): Mouse Wheel / double touch + control (OSX: command)",2)
1625  }
1626  else
1627  {
1628  VFN_DEBUG_MESSAGE("WXPowderPatternGraph::OnMouse(): Mouse Wheel / double touch",2)
1629  const int delta=event.GetWheelDelta();
1630  int dx=0,dy=0;
1631  if(event.GetWheelAxis()==1) dx=event.GetWheelRotation();
1632  else dy=event.GetWheelRotation();
1633  if(dx>16) dx=16;
1634  if(dx<-16)dx=-16;
1635  if(dy>16) dy=16;
1636  if(dy<-16)dy=-16;
1637 
1638  const long nbPoint=mX.numElements();
1639  if(dx>0)
1640  {
1641  const REAL range=mMaxX-mMinX;
1642  mMaxX += range/128.*abs(dx);
1643  if(mX(nbPoint-1)>mX(0))
1644  {
1645  if(mMaxX>=mX(nbPoint-1)) mMaxX=mX(nbPoint-1);
1646  }
1647  else
1648  {
1649  if(mMaxX>=mX(0)) mMaxX=mX(0);
1650  }
1651  mMinX=mMaxX-range;
1652  }
1653  else if(dx<0)
1654  {
1655  const REAL range=mMaxX-mMinX;
1656  mMinX -= range/128.*abs(dx);
1657  if(mX(nbPoint-1)>mX(0))
1658  {
1659  if(mMinX<mX(0)) mMinX=mX(0);
1660  }
1661  else
1662  {
1663  if(mMinX<mX(nbPoint-1)) mMinX=mX(nbPoint-1);
1664  }
1665  mMaxX=mMinX+range;
1666  }
1667 
1668  if(dy<0)
1669  {
1670  if(abs(mMaxX-mMinX)>1)
1671  {
1672  const REAL halfrange=(mMaxX-mMinX)/2;
1673  const REAL middle=(mMaxX+mMinX)/2;
1674  //d1,d2 are used to zoom from the mouse position rather than the middle
1675  const REAL d1=(x0-mMinX)/halfrange;
1676  const REAL d2=(mMaxX-x0)/halfrange;
1677  mMinX= middle-halfrange*(64-abs(dy)*d1)/64.;
1678  mMaxX= middle+halfrange*(64-abs(dy)*d2)/64.;
1679  }
1680  }
1681  else if(dy>0)
1682  {
1683  const REAL halfrange=(mMaxX-mMinX)/2;
1684  const REAL middle=(mMaxX+mMinX)/2;
1685  const REAL d1=(x0-mMinX)/halfrange;
1686  const REAL d2=(mMaxX-x0)/halfrange;
1687  mMinX= middle-halfrange*(64+abs(dy)*d1)/64.;
1688  mMaxX= middle+halfrange*(64+abs(dy)*d2)/64.;
1689  }
1690  if(mX(nbPoint-1)>mX(0))
1691  {
1692  if(mMinX<mX(0)) mMinX=mX(0);
1693  if(mMaxX>mX(nbPoint-1)) mMaxX=mX(nbPoint-1);
1694  }
1695  else
1696  {
1697  if(mMinX<mX(nbPoint-1)) mMinX=mX(nbPoint-1);
1698  if(mMaxX>mX(0)) mMaxX=mX(0);
1699  }
1700  if(mDefaultIntensityScale)
1701  {// Adapt max intensity as well
1702  float x0=mMinX,x1=mMaxX;
1703  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
1704  {
1705  x0 *= DEG2RAD;
1706  x1 *= DEG2RAD;
1707  }
1708  long ix0=long(this->mpPattern->GetPowderPattern().X2Pixel(x0));
1709  long ix1=long(this->mpPattern->GetPowderPattern().X2Pixel(x1));
1710  //cout<<"Switch default intensity 1: "<<"["<<ix0<<"] - "<<"["<<ix1<<"]"<<endl;
1711  if(ix0<0) ix0=0;
1712  if(ix0>=mX.numElements()) ix0=mX.numElements()-1;
1713  if(ix1<0) ix1=0;
1714  if(ix1>=mX.numElements()) ix1=mX.numElements()-1;
1715  if(ix0>ix1)
1716  {
1717  const long ixtmp=ix0;
1718  ix0=ix1;
1719  ix1=ixtmp;
1720  }
1721  const long imin=mObs.imin(ix0,ix1);
1722  const long imax=mObs.imax(ix0,ix1);
1723  const long iminc=mCalc.imin(ix0,ix1);
1724  const long imaxc=mCalc.imax(ix0,ix1);
1725  //cout<<"Switch default intensity 3: "<<mObs(imin)<<"["<<ix0<<"] - "<<mObs(imax)<<"["<<ix1<<"]"<<endl;
1726  if(mObs(imin)<mCalc(iminc)) mMinIntensity=mObs(imin); else mMinIntensity=mCalc(iminc);
1727  if(mObs(imax)>mCalc(imaxc)) mMaxIntensity=mObs(imax); else mMaxIntensity=mCalc(imaxc);
1728  mMaxIntensity=mMaxIntensity+(mMaxIntensity-mMinIntensity)*0.1;
1729  }
1730 
1731  mMutex.Unlock();
1732  mClockAxisLimits.Click();
1733  wxUpdateUIEvent event(ID_POWDER_GRAPH_NEW_PATTERN);
1734  wxPostEvent(this,event);
1735  event.Skip();
1736  return;
1737  }
1738  }
1739  mMutex.Unlock();
1740  event.Skip();
1741 }
1742 void WXPowderPatternGraph::OnMouseWheel(wxMouseEvent &event)
1743 {
1744  VFN_DEBUG_ENTRY("WXPowderPatternGraph::OnMouseWheel()",6)
1745  wxMutexLocker mlock(mMutex);
1746  const long nbPoint=mX.numElements();
1747  if(event.GetWheelRotation()>=event.GetWheelDelta())
1748  {
1749  const REAL range=mMaxX-mMinX;
1750  mMaxX += range/8;
1751  if(mX(nbPoint-1)>mX(0))
1752  {
1753  if(mMaxX>=mX(nbPoint-1)) mMaxX=mX(nbPoint-1);
1754  }
1755  else
1756  {
1757  if(mMaxX>=mX(0)) mMaxX=mX(0);
1758  }
1759  mMinX=mMaxX-range;
1760  }
1761  if(event.GetWheelRotation()<=(-event.GetWheelDelta()))
1762  {
1763  const REAL range=mMaxX-mMinX;
1764  mMinX -= range/8;
1765  if(mX(nbPoint-1)>mX(0))
1766  {
1767  if(mMinX<mX(0)) mMinX=mX(0);
1768  }
1769  else
1770  {
1771  if(mMinX<mX(nbPoint-1)) mMinX=mX(nbPoint-1);
1772  }
1773  mMaxX=mMinX+range;
1774  }
1775  mClockAxisLimits.Click();
1776  wxUpdateUIEvent ev(ID_POWDER_GRAPH_NEW_PATTERN);
1777  wxPostEvent(this,ev);
1778  VFN_DEBUG_EXIT("WXPowderPatternGraph::OnMouseWheel()",6)
1779 }
1780 
1781 void WXPowderPatternGraph::OnUpdate(wxCommandEvent & WXUNUSED(event))
1782 {
1783  VFN_DEBUG_MESSAGE("WXPowderPatternGraph::OnUpdate()",6)
1784  mpPattern->CrystUpdate(true,true);
1785 }
1786 
1787 void WXPowderPatternGraph::OnToggleLabel(wxCommandEvent &event)
1788 {
1789  VFN_DEBUG_MESSAGE("WXPowderPatternGraph::OnToggleLabel()",6)
1790  if(event.GetId()==ID_POWDERGRAPH_MENU_TOGGPEAK)
1791  {
1792  mDisplayPeak = !mDisplayPeak;
1793  if(mDisplayPeak) mpPopUpMenu->SetLabel(ID_POWDERGRAPH_MENU_TOGGPEAK, _T("Hide peaks"));
1794  else mpPopUpMenu->SetLabel(ID_POWDERGRAPH_MENU_TOGGPEAK, _T("Show peaks"));
1795  }
1796  if(event.GetId()==ID_POWDERGRAPH_MENU_TOGGLELABEL)
1797  {
1798  mDisplayLabel = !mDisplayLabel;
1799  if(mDisplayLabel) mpPopUpMenu->SetLabel(ID_POWDERGRAPH_MENU_TOGGLELABEL, _T("Hide labels"));
1800  else mpPopUpMenu->SetLabel(ID_POWDERGRAPH_MENU_TOGGLELABEL, _T("Show labels"));
1801  }
1802  this->Refresh(false);
1803 }
1804 
1805 void WXPowderPatternGraph::OnFindPeaks(wxCommandEvent& WXUNUSED(event))
1806 {
1807  float dmin=1.5;
1808  while(true)
1809  {
1810  mPeakList=mpPattern->GetPowderPattern().FindPeaks(dmin,-1,1000);
1811  dmin*=0.75;
1812  if((mPeakList.GetPeakList().size()>30)||(dmin<0.3)) break;
1813  }
1814 
1815  const unsigned int nb=mPeakList.GetPeakList().size();
1816  //if(nb<5) return;
1817 
1818  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_SAVEPEAKS, TRUE);
1819  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_TOGGPEAK, TRUE);
1820  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_INDEX, TRUE);
1821  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_ADDPEAK, TRUE);
1822  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_REMOVEPEAK, TRUE);
1823 
1824  // Keep lowest peaks
1825  if(mPeakList.GetPeakList().size()>40) mPeakList.GetPeakList().resize(40);
1826  //mpPattern->CrystUpdate(true,true);
1827  if(true)
1828  {// display 2nd derivative as 'calc' (will remain until an update to the pattern is made)
1829  CrystVector_REAL obsd2;
1830  obsd2=SavitzkyGolay(mObs,4,2);
1831  const float norm=-obsd2.min();
1832  obsd2 /= -norm;
1833 
1834  mCalc=obsd2;
1835  mCalc*=mObs.max();
1836  }
1837 
1838  this->Refresh(false);
1839 }
1840 
1841 void WXPowderPatternGraph::OnLoadPeaks(wxCommandEvent& WXUNUSED(event))
1842 {
1843  wxFileDialog fn(this,_T("Choose a file"),_T(""),_T(""),_T("*"),wxFD_OPEN);
1844  if(fn.ShowModal() != wxID_OK) return;
1845  ifstream f(fn.GetPath().ToAscii());
1846  if(!f) return;//:TODO:
1847  mPeakList.GetPeakList().clear();
1848  mPeakList.ImportDhklDSigmaIntensity(f);
1849  f.close();
1850 
1851  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_SAVEPEAKS, TRUE);
1852  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_TOGGPEAK, TRUE);
1853  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_INDEX, TRUE);
1854  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_ADDPEAK, TRUE);
1855  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_REMOVEPEAK, TRUE);
1856  this->Refresh(false);
1857 }
1858 
1859 void WXPowderPatternGraph::OnSavePeaks(wxCommandEvent& WXUNUSED(event))
1860 {
1861  wxFileDialog save(this,_T("Choose a file"),_T(""),_T(""),_T("*.txt"),wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
1862  if(save.ShowModal() != wxID_OK) return;
1863 
1864  ofstream out(save.GetPath().ToAscii());
1865  if(!out) return;//:TODO:
1866  mPeakList.ExportDhklDSigmaIntensity(out);
1867  out.close();
1868 }
1869 
1870 
1871 void WXPowderPatternGraph::OnChangePeak(wxCommandEvent& event)
1872 {
1873  if(event.GetId()==ID_POWDERGRAPH_MENU_REMOVEPEAK)
1874  {
1875  unsigned int idx=0;
1876  const float d=2*mpPattern->GetPowderPattern().X2STOL(this->Screen2DataX((long)mDraggingX0)*DEG2RAD);
1877  float dist=100.0;
1878  for(unsigned int i=0;i<mPeakList.GetPeakList().size();++i)
1879  {
1880  float x=mpPattern->GetPowderPattern().STOL2X(mPeakList.GetPeakList()[i].dobs/2);
1881  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
1882  x *= RAD2DEG;
1883  x=this->Data2ScreenX(x);
1884  if(abs(x-mDraggingX0)<dist)
1885  {
1886  dist=abs(x-mDraggingX0);
1887  idx=i;
1888  }
1889  cout<<__FILE__<<":"<<__LINE__<<": 1/d0="<<d<<" peak #"<<i<<",d="<<1/mPeakList.GetPeakList()[i].dobs
1890  <<"("<<mDraggingX0<<","<<x<<"), mindist="<<dist<<endl;
1891  }
1892  if(dist>5) mpParentFrame->SetStatusText(_T("Could not find peak close enough"),1);
1893  else
1894  {
1895  if(mPeakList.GetPeakList().size()<5) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_INDEX, FALSE);
1896  if(mPeakList.GetPeakList().size()==0)
1897  {
1898  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_TOGGPEAK, FALSE);
1899  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_SAVEPEAKS, FALSE);
1900  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_REMOVEPEAK, FALSE);
1901  }
1902  wxString buf;
1903  buf.Printf(_T("Removing peak at d=%6.3f"),1/mPeakList.GetPeakList()[idx].dobs);
1904  mpParentFrame->SetStatusText(buf,1);
1905  mPeakList.RemovePeak(idx);
1906  this->Refresh(false);
1907  }
1908  }
1909  if(event.GetId()==ID_POWDERGRAPH_MENU_ADDPEAK)
1910  {
1911  float d,sig;
1912  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
1913  {
1914  d = 2*mpPattern->GetPowderPattern().X2STOL(this->Screen2DataX((long)mDraggingX0 )*DEG2RAD);
1915  // Use 2*local step as sigma
1916  long x1=(long)(mpPattern->GetPowderPattern().STOL2Pixel(d/2));
1917  if(x1<1) x1+=1;
1918  sig=2*abs( mpPattern->GetPowderPattern().X2STOL(mpPattern->GetPowderPattern().GetPowderPatternX()(x1 ))
1919  -mpPattern->GetPowderPattern().X2STOL(mpPattern->GetPowderPattern().GetPowderPatternX()(x1-1)));
1920  }
1921  else
1922  {
1923  d = 2*mpPattern->GetPowderPattern().X2STOL(this->Screen2DataX((long)mDraggingX0 ));
1924  long x1=(long)(mpPattern->GetPowderPattern().STOL2Pixel(d/2));
1925  cout<<__FILE__<<":"<<__LINE__<<":"<<x1<<endl;
1926  if(x1<1) x1+=1;
1927  sig=2*abs( mpPattern->GetPowderPattern().X2STOL(mpPattern->GetPowderPattern().GetPowderPatternX()(x1 ))
1928  -mpPattern->GetPowderPattern().X2STOL(mpPattern->GetPowderPattern().GetPowderPatternX()(x1-1)));
1929  cout<<__FILE__<<":"<<__LINE__<<":"<<sig<<endl;
1930  }
1931 
1932  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_SAVEPEAKS, TRUE);
1933  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_TOGGPEAK, TRUE);
1934  if(mPeakList.GetPeakList().size()>=5) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_INDEX, TRUE);
1935  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_REMOVEPEAK, TRUE);
1936 
1937  wxString buf;
1938  buf.Printf(_T("Added peak at d=%6.3f"),1/d);
1939  mPeakList.AddPeak(d,1.0,sig);
1940  mpParentFrame->SetStatusText(buf,1);
1941  this->Refresh(false);
1942  mPeakList.Print(cout);
1943  }
1944 }
1946 
1947 class WXCellExplorer:public wxWindow
1948 {
1949  public:
1950  WXCellExplorer(wxWindow *parent,PeakList &peaklist,WXPowderPatternGraph *graph=NULL);
1951  ~WXCellExplorer();
1953  void OnIndex(wxCommandEvent &event);
1955  void OnSelectCell(wxCommandEvent &event);
1957  void OnApplyCell(wxCommandEvent &event);
1959  void OnChooseCrystal(wxCommandEvent &event);
1962  void OnAutoLeBail(wxCommandEvent &event);
1963  private:
1964  WXPowderPatternGraph *mpGraph;
1965  PeakList *mpPeakList;
1966  CellExplorer *mpCellExplorer;
1967  wxRadioBox *mpAlgorithm;
1968  wxRadioBox *mpBravais;
1969  wxListBox *mpCell;
1970  wxTextCtrl *mpLog;
1971  wxTextCtrl *mpLengthMin,*mpLengthMax;
1972  wxTextCtrl *mpAngleMin,*mpAngleMax;
1973  wxTextCtrl *mpVolumeMin,*mpVolumeMax;
1974  wxTextCtrl *mpNbSpurious;
1975  wxTextCtrl *mpNbPeak;
1976  wxTextCtrl *mpErrorD;
1977  WXFieldChoice *mpFieldCrystal;
1978  wxTextCtrl *mpStopOnScore,*mpStopOnDepth;
1979  wxTextCtrl *mpReportOnScore,*mpReportOnDepth;
1980  Crystal *mpCrystal;
1981  PowderPatternDiffraction *mpDiff;
1982  wxCheckBox *mpWeakDiffraction;
1983  wxCheckBox *mpContinueOnSolution;
1984  wxCheckBox *mpTryCenteredLattice;
1985  wxCheckBox *mpAutomaticLeBail;
1986  DECLARE_EVENT_TABLE()
1987 };
1988 static const long ID_CELLEXPLORER_INDEX= WXCRYST_ID();
1989 static const long ID_CELLEXPLORER_INDEX_QUICK= WXCRYST_ID();
1990 static const long ID_CELLEXPLORER_WEAK= WXCRYST_ID();
1991 static const long ID_CELLEXPLORER_SELECTCELL= WXCRYST_ID();
1992 static const long ID_CELLEXPLORER_APPLYCELL= WXCRYST_ID();
1993 static const long ID_CELLEXPLORER_CHOOSECRYSTAL= WXCRYST_ID();
1994 static const long ID_CELLEXPLORER_LEBAIL= WXCRYST_ID();
1995 static const long ID_CELLEXPLORER_CENTERED= WXCRYST_ID();
1996 
1997 BEGIN_EVENT_TABLE(WXCellExplorer, wxWindow)
1998  EVT_BUTTON(ID_CELLEXPLORER_INDEX, WXCellExplorer::OnIndex)
1999  EVT_BUTTON(ID_CELLEXPLORER_INDEX_QUICK, WXCellExplorer::OnIndex)
2000  EVT_LISTBOX(ID_CELLEXPLORER_SELECTCELL, WXCellExplorer::OnSelectCell)
2001  EVT_LISTBOX_DCLICK(ID_CELLEXPLORER_SELECTCELL,WXCellExplorer::OnApplyCell)
2002  EVT_BUTTON(ID_CELLEXPLORER_APPLYCELL, WXCellExplorer::OnApplyCell)
2003  EVT_BUTTON(ID_CELLEXPLORER_CHOOSECRYSTAL, WXCellExplorer::OnChooseCrystal)
2004  EVT_CHECKBOX(ID_CELLEXPLORER_LEBAIL, WXCellExplorer::OnAutoLeBail)
2005 END_EVENT_TABLE()
2006 
2007 WXCellExplorer::WXCellExplorer(wxWindow *parent, PeakList &peaklist, WXPowderPatternGraph *graph):
2008 wxWindow(parent,-1),mpGraph(graph),mpPeakList(&peaklist),mpCellExplorer(0),mpCrystal(0),mpDiff(0)
2009 {
2010  wxBoxSizer *pSizer1=new wxBoxSizer(wxHORIZONTAL);
2011  this->SetSizer(pSizer1);
2012 
2013  wxNotebook *pNotebook = new wxNotebook(this, -1);
2014 
2015  pSizer1->Add(pNotebook,0,wxALIGN_TOP);
2016 
2017  // Quick interface
2018  wxWindow *pQuick=new wxWindow(pNotebook,-1);
2019  pNotebook->AddPage(pQuick,_T("Quick"));
2020 
2021  wxStaticBoxSizer *pSizerQuick=new wxStaticBoxSizer(wxVERTICAL,pQuick);
2022 
2023  wxButton *pQuickButtonIndex=new wxButton(pQuick,ID_CELLEXPLORER_INDEX_QUICK,_T("Find cell!"));
2024  pSizerQuick->Add(pQuickButtonIndex,0,wxALIGN_CENTER);
2025 
2026  mpWeakDiffraction=new wxCheckBox(pQuick,ID_CELLEXPLORER_WEAK,_T("Weak Diffraction (scan larger volume)"));
2027  pSizerQuick->Add(mpWeakDiffraction,0,wxALIGN_CENTER);
2028 
2029  mpContinueOnSolution=new wxCheckBox(pQuick,ID_CELLEXPLORER_WEAK,_T("Continue exploring after solution"));
2030  pSizerQuick->Add(mpContinueOnSolution,0,wxALIGN_CENTER);
2031 
2032  mpTryCenteredLattice=new wxCheckBox(pQuick,ID_CELLEXPLORER_CENTERED,_T("Try Centered Lattices"));
2033  pSizerQuick->Add(mpTryCenteredLattice,0,wxALIGN_CENTER);
2034 
2035  pQuick->SetSizer(pSizerQuick);
2036  pSizerQuick->Fit(pQuick);
2037  pSizerQuick->RecalcSizes();
2038  pQuick->Layout();
2039  // Advanced interface
2040  wxWindow *pAdvanced=new wxWindow(pNotebook,-1);
2041 
2042  wxStaticBoxSizer *pSizerAdvanced=new wxStaticBoxSizer(wxVERTICAL,pAdvanced);
2043 
2044  wxButton *pButton1=new wxButton(pAdvanced,ID_CELLEXPLORER_INDEX,_T("Find cell!"));
2045  pSizerAdvanced->Add(pButton1,0,wxALIGN_CENTER);
2046 
2047  wxBoxSizer *pLengthSizer=new wxBoxSizer(wxHORIZONTAL);
2048  wxStaticText *pLengthText=new wxStaticText(pAdvanced,-1,_T("Length min, max (A):"));
2049  pLengthSizer->Add(pLengthText,0,wxALIGN_CENTER);
2050  mpLengthMin=new wxTextCtrl(pAdvanced,-1,_T("3"),wxDefaultPosition,wxSize(30,-1),0,
2051  wxTextValidator(wxFILTER_NUMERIC));
2052  pLengthSizer->Add(mpLengthMin,0,wxALIGN_CENTER);
2053  mpLengthMax=new wxTextCtrl(pAdvanced,-1,_T("25"),wxDefaultPosition,wxSize(30,-1),0,
2054  wxTextValidator(wxFILTER_NUMERIC));
2055  pLengthSizer->Add(mpLengthMax,0,wxALIGN_CENTER);
2056  pSizerAdvanced->Add(pLengthSizer,0,wxALIGN_CENTER);
2057 
2058  wxBoxSizer *pAngleSizer=new wxBoxSizer(wxHORIZONTAL);
2059  wxStaticText *pAngleText=new wxStaticText(pAdvanced,-1,_T("Angle max(90< <179):"));
2060  pAngleSizer->Add(pAngleText,0,wxALIGN_CENTER);
2061  //mpAngleMin=new wxTextCtrl(this,-1,"90",wxDefaultPosition,wxSize(40,-1),0,
2062  // wxTextValidator(wxFILTER_NUMERIC));
2063  //pAngleSizer->Add(mpAngleMin,0,wxALIGN_CENTER);
2064  mpAngleMax=new wxTextCtrl(pAdvanced,-1,_T("130"),wxDefaultPosition,wxSize(40,-1),0,
2065  wxTextValidator(wxFILTER_NUMERIC));
2066  pAngleSizer->Add(mpAngleMax,0,wxALIGN_CENTER);
2067  pSizerAdvanced->Add(pAngleSizer,0,wxALIGN_CENTER);
2068 
2069  wxBoxSizer *pVolumeSizer=new wxBoxSizer(wxHORIZONTAL);
2070  wxStaticText *pVolumeText=new wxStaticText(pAdvanced,-1,_T("Volume min, max (A3):"));
2071  pVolumeSizer->Add(pVolumeText,0,wxALIGN_CENTER);
2072  mpVolumeMin=new wxTextCtrl(pAdvanced,-1,_T("10"),wxDefaultPosition,wxSize(50,-1),0,
2073  wxTextValidator(wxFILTER_NUMERIC));
2074  pVolumeSizer->Add(mpVolumeMin,0,wxALIGN_CENTER);
2075  mpVolumeMax=new wxTextCtrl(pAdvanced,-1,_T("2500"),wxDefaultPosition,wxSize(50,-1),0,
2076  wxTextValidator(wxFILTER_NUMERIC));
2077  pVolumeSizer->Add(mpVolumeMax,0,wxALIGN_CENTER);
2078  pSizerAdvanced->Add(pVolumeSizer,0,wxALIGN_CENTER);
2079 
2080  wxBoxSizer *pSpuriousSizer=new wxBoxSizer(wxHORIZONTAL);
2081  wxStaticText *pSpuriousText=new wxStaticText(pAdvanced,-1,_T("Nb spurious lines:"));
2082  pSpuriousSizer->Add(pSpuriousText,0,wxALIGN_CENTER);
2083  mpNbSpurious=new wxTextCtrl(pAdvanced,-1,_T("0"),wxDefaultPosition,wxSize(40,-1),0,
2084  wxTextValidator(wxFILTER_NUMERIC));
2085  pSpuriousSizer->Add(mpNbSpurious,0,wxALIGN_CENTER);
2086  pSizerAdvanced->Add(pSpuriousSizer,0,wxALIGN_CENTER);
2087 
2088  wxBoxSizer *pNbPeakSizer=new wxBoxSizer(wxHORIZONTAL);
2089  wxStaticText *pNbPeakText=new wxStaticText(pAdvanced,-1,_T("Use Nb Peaks:"));
2090  pNbPeakSizer->Add(pNbPeakText,0,wxALIGN_CENTER);
2091  mpNbPeak=new wxTextCtrl(pAdvanced,-1,_T("20"),wxDefaultPosition,wxSize(40,-1),0,
2092  wxTextValidator(wxFILTER_NUMERIC));
2093  pNbPeakSizer->Add(mpNbPeak,0,wxALIGN_CENTER);
2094  pSizerAdvanced->Add(pNbPeakSizer,0,wxALIGN_CENTER);
2095 
2096  wxBoxSizer *pStopSizer=new wxBoxSizer(wxHORIZONTAL);
2097  wxStaticText* pStopOnScoreText=new wxStaticText(pAdvanced,-1,_T("Stop on Score>"));
2098  pStopSizer->Add(pStopOnScoreText,0,wxALIGN_CENTER);
2099  mpStopOnScore=new wxTextCtrl(pAdvanced,-1,_T("50"),wxDefaultPosition,wxSize(50,-1),0,
2100  wxTextValidator(wxFILTER_NUMERIC));
2101  pStopSizer->Add(mpStopOnScore,0,wxALIGN_CENTER);
2102 
2103  wxStaticText* pStopOnDepthText=new wxStaticText(pAdvanced,-1,_T("and depth>="));
2104  pStopSizer->Add(pStopOnDepthText,0,wxALIGN_CENTER);
2105  mpStopOnDepth=new wxTextCtrl(pAdvanced,-1,_T("6"),wxDefaultPosition,wxSize(30,-1),0,
2106  wxTextValidator(wxFILTER_NUMERIC));
2107  pStopSizer->Add(mpStopOnDepth,0,wxALIGN_CENTER);
2108  pSizerAdvanced->Add(pStopSizer,0,wxALIGN_CENTER);
2109 
2110 
2111  wxBoxSizer *pReportSizer=new wxBoxSizer(wxHORIZONTAL);
2112  wxStaticText* pReportOnScoreText=new wxStaticText(pAdvanced,-1,_T("Report score>"));
2113  pReportSizer->Add(pReportOnScoreText,0,wxALIGN_CENTER);
2114  mpReportOnScore=new wxTextCtrl(pAdvanced,-1,_T("10"),wxDefaultPosition,wxSize(50,-1),0,
2115  wxTextValidator(wxFILTER_NUMERIC));
2116  pReportSizer->Add(mpReportOnScore,0,wxALIGN_CENTER);
2117 
2118  wxStaticText* pReportOnDepthText=new wxStaticText(pAdvanced,-1,_T("or depth>="));
2119  pReportSizer->Add(pReportOnDepthText,0,wxALIGN_CENTER);
2120  mpReportOnDepth=new wxTextCtrl(pAdvanced,-1,_T("4"),wxDefaultPosition,wxSize(50,-1),0,
2121  wxTextValidator(wxFILTER_NUMERIC));
2122  pReportSizer->Add(mpReportOnDepth,0,wxALIGN_CENTER);
2123  pSizerAdvanced->Add(pReportSizer,0,wxALIGN_CENTER);
2124 
2125  wxBoxSizer *pErrorSizer=new wxBoxSizer(wxHORIZONTAL);
2126  wxStaticText* pErrorText=new wxStaticText(pAdvanced,-1,_T("delta(d)/d^2 error:"));
2127  pErrorSizer->Add(pErrorText,0,wxALIGN_CENTER);
2128  mpErrorD=new wxTextCtrl(pAdvanced,-1,_T("0"),wxDefaultPosition,wxSize(50,-1),0,
2129  wxTextValidator(wxFILTER_NUMERIC));
2130  pErrorSizer->Add(mpErrorD,0,wxALIGN_CENTER);
2131  pSizerAdvanced->Add(pErrorSizer,0,wxALIGN_CENTER);
2132 
2133  wxArrayString bravaisChoices;
2134  bravaisChoices.Add(_T("Triclinic"));
2135  bravaisChoices.Add(_T("Monoclinic"));
2136  bravaisChoices.Add(_T("Orthorombic"));
2137  bravaisChoices.Add(_T("Hexagonal"));
2138  bravaisChoices.Add(_T("Rhomboedral"));
2139  bravaisChoices.Add(_T("Tetragonal"));
2140  bravaisChoices.Add(_T("Cubic"));
2141  mpBravais=new wxRadioBox((wxWindow*)pAdvanced,-1,_T("Crystal System"),wxDefaultPosition,wxDefaultSize,bravaisChoices,0,wxRA_SPECIFY_ROWS);
2142  mpBravais->SetSelection(2);
2143  //mpBravais->Enable(0,false);
2144  pSizerAdvanced->Add(mpBravais,0,wxALIGN_CENTER);
2145 
2146  wxArrayString algoChoices;
2147  algoChoices.Add(_T("DICVOL"));
2148  //algoChoices.Add(_T("Differential Evolution")); // :TODO: re-enable after testing
2149  #if 0
2150  mpAlgorithm=new wxRadioBox(pAdvanced,-1,_T("Algorithm"),wxDefaultPosition,wxDefaultSize,algoChoices,0,wxRA_SPECIFY_ROWS);
2151  mpAlgorithm->Enable(1,false);
2152  pSizerAdvanced->Add(mpAlgorithm,0,wxALIGN_CENTER);
2153  #endif
2154  pAdvanced->SetSizer(pSizerAdvanced);
2155  pSizerAdvanced->Fit(pAdvanced);
2156  pSizerAdvanced->RecalcSizes();
2157  pAdvanced->Layout();
2158 
2159  pNotebook->AddPage(pAdvanced,_T("Advanced"));
2160 
2161  pNotebook->Layout();
2162  // Solutions & log
2163  wxBoxSizer *pSizer2=new wxBoxSizer(wxVERTICAL);
2164 
2165  //wxButton *pButton2=new wxButton(this,ID_CELLEXPLORER_APPLYCELL,"Apply selected cell");
2166  //pSizer2->Add(pButton2,0,wxALIGN_CENTER);
2167 
2168  mpFieldCrystal=new WXFieldChoice(this,ID_CELLEXPLORER_CHOOSECRYSTAL,"Choose crystal to apply selected cell to:",200);
2169  pSizer2->Add(mpFieldCrystal,0,wxALIGN_CENTER);
2170 
2171  mpAutomaticLeBail=new wxCheckBox(this,ID_CELLEXPLORER_LEBAIL,_T("Automatic Profile Fitting (Le Bail)"));
2172  pSizer2->Add(mpAutomaticLeBail,0,wxALIGN_CENTER);
2173 
2174  wxArrayString cells;
2175  mpCell=new wxListBox(this,ID_CELLEXPLORER_SELECTCELL,wxDefaultPosition,wxSize(750,400),cells,wxLB_SINGLE);
2176  mpCell->SetFont(wxFont(9,wxTELETYPE,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL));
2177  pSizer2->Add(mpCell,0,wxALIGN_CENTER);
2178 
2179  mpLog =new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(750,250),wxTE_MULTILINE|wxTE_READONLY|wxTE_DONTWRAP);
2180  mpLog->SetFont(wxFont(9,wxTELETYPE,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL));
2181  pSizer2->Add(mpLog,0,wxALIGN_CENTER);
2182 
2183  pSizer1->Add(pSizer2,0,wxALIGN_TOP);
2184 
2185  this->Layout();
2186  pSizer1->Fit(this->GetParent());
2187  pSizer1->SetSizeHints(this);
2188 
2189  // Estimate volume from number of peaks at a given dmin
2190  // See J. Appl. Cryst. 20 (1987), 161
2191  unsigned int nb=mpPeakList->GetPeakList().size();
2192  if(nb>20) nb=20;// Just use 20 - beyond that we probably have a lot of weak peaks missed
2193  const float dmin=mpPeakList->GetPeakList()[nb-1].dobs;
2194  const float dmax=mpPeakList->GetPeakList()[0].dobs/10;// /10: assume no peaks at lower resolution
2195  mpLog->AppendText(wxString::Format(_T("Predicted unit vell volume from %2u observed peaks between: dmax=%6.3f A-> dmin=%6.3fA\n"),nb,1/dmax,1/dmin));
2196  mpLog->AppendText(wxString::Format(_T("(Assuming observed lines represent 120%% down to 30%% of existing reflections)\n")));
2197  mpLog->AppendText(wxString::Format(_T(" Cubic P v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,CUBIC ,LATTICE_P,1.2),EstimateCellVolume(dmin,dmax,nb,CUBIC ,LATTICE_P,0.3)));
2198  mpLog->AppendText(wxString::Format(_T(" Cubic I v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,CUBIC ,LATTICE_I,1.2),EstimateCellVolume(dmin,dmax,nb,CUBIC ,LATTICE_I,0.3)));
2199  mpLog->AppendText(wxString::Format(_T(" Cubic F v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,CUBIC ,LATTICE_F,1.2),EstimateCellVolume(dmin,dmax,nb,CUBIC ,LATTICE_F,0.3)));
2200  mpLog->AppendText(wxString::Format(_T(" Tetragonal P v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,TETRAGONAL ,LATTICE_P,1.2),EstimateCellVolume(dmin,dmax,nb,TETRAGONAL ,LATTICE_P,0.3)));
2201  mpLog->AppendText(wxString::Format(_T(" Tetragonal I v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,TETRAGONAL ,LATTICE_I,1.2),EstimateCellVolume(dmin,dmax,nb,TETRAGONAL ,LATTICE_I,0.3)));
2202  mpLog->AppendText(wxString::Format(_T(" Orthorombic P v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,ORTHOROMBIC,LATTICE_P,1.2),EstimateCellVolume(dmin,dmax,nb,ORTHOROMBIC,LATTICE_P,0.3)));
2203  mpLog->AppendText(wxString::Format(_T(" Orthorombic I,C v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,ORTHOROMBIC,LATTICE_I,1.2),EstimateCellVolume(dmin,dmax,nb,ORTHOROMBIC,LATTICE_I,0.3)));
2204  mpLog->AppendText(wxString::Format(_T(" Orthorombic F v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,ORTHOROMBIC,LATTICE_F,1.2),EstimateCellVolume(dmin,dmax,nb,ORTHOROMBIC,LATTICE_I,0.3)));
2205  mpLog->AppendText(wxString::Format(_T(" Hexagonal v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,HEXAGONAL ,LATTICE_P,1.2),EstimateCellVolume(dmin,dmax,nb,HEXAGONAL ,LATTICE_P,0.3)));
2206  mpLog->AppendText(wxString::Format(_T(" Monoclinic P v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,MONOCLINIC ,LATTICE_P,1.2),EstimateCellVolume(dmin,dmax,nb,MONOCLINIC ,LATTICE_P,0.3)));
2207  mpLog->AppendText(wxString::Format(_T(" Monoclinic C v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,MONOCLINIC ,LATTICE_C,1.2),EstimateCellVolume(dmin,dmax,nb,MONOCLINIC ,LATTICE_C,0.3)));
2208  mpLog->AppendText(wxString::Format(_T(" Triclinic v=%6.0f -> %6.0f A\n"),EstimateCellVolume(dmin,dmax,nb,TRICLINIC ,LATTICE_P,1.2),EstimateCellVolume(dmin,dmax,nb,TRICLINIC ,LATTICE_P,0.3)));
2209 }
2210 
2211 WXCellExplorer::~WXCellExplorer()
2212 {
2213  if(mpDiff!=0)
2214  {
2215  mpDiff->SetExtractionMode(false,false);
2216  mpDiff->UpdateDisplay();
2217  }
2218 }
2219 
2220 void WXCellExplorer::OnIndex(wxCommandEvent &event)
2221 {
2222 
2223  Chronometer chrono;
2224  if(event.GetId()==ID_CELLEXPLORER_INDEX_QUICK)
2225  {
2226  // Erase spurious record
2227  for(vector<PeakList::hkl>::iterator pos=mpPeakList->mvHKL.begin();pos!=mpPeakList->mvHKL.end();++pos)
2228  pos->isSpurious=false;
2229 
2230  // Use at most 30 reflections for indexing
2231  PeakList peaklist=*mpPeakList;
2232  if(peaklist.GetPeakList().size()>20) peaklist.GetPeakList().resize(20);
2233 
2234  // Estimate volume from number of peaks at a given dmin
2235  // See J. Appl. Cryst. 20 (1987), 161
2236  unsigned int nb=mpPeakList->GetPeakList().size();
2237  if(nb>20) nb=20;// Just use 20 - beyond that we probably have a lot of weak peaks
2238  float dmin=mpPeakList->GetPeakList()[nb-1].dobs;
2239  const float dmax=mpPeakList->GetPeakList()[0].dobs/10;//assume there are no peaks at lower resolution
2240  mpLog->AppendText(wxString::Format(_T("Predicting volumes from %2u peaks between d=%6.3f and d=%6.3f\n"),nb,1/dmax,1/dmin));
2241  mpLog->AppendText(wxString::Format(_T("Starting indexing using %2u peaks\n"),nb));
2242 
2243  mpCellExplorer = new CellExplorer(peaklist,CUBIC,0);
2244  mpCellExplorer->SetLengthMinMax(3,25);
2245  mpCellExplorer->SetAngleMinMax(90*DEG2RAD,140*DEG2RAD);
2246  mpCellExplorer->SetD2Error(0);
2247 
2248  float weak_f=1.0;
2249  if(mpWeakDiffraction->GetValue()) weak_f=0.5;
2250  const bool continueOnSolution=mpContinueOnSolution->GetValue();
2251 
2252  const bool noCentered=!(mpTryCenteredLattice->GetValue());
2253 
2254  const float stopOnScore=50, reportOnScore=10;
2255  const unsigned int stopOnDepth=6+int(continueOnSolution), reportOnDepth=4;
2256 
2257  unsigned int nbSpurious=0;
2258  wxProgressDialog dlgProgress(_T("Indexing..."),_T("Starting Indexing in Quick Mode"),
2259  7,this,wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME|wxPD_CAN_ABORT);
2260  while(nbSpurious<=3)
2261  {
2262  float t0,minv,maxv,lengthmax;
2263  mpCellExplorer->SetNbSpurious(nbSpurious);
2264  CrystalCentering cent;
2265  char centc;
2266  for(int lat=0;lat<=2;++lat)
2267  {
2268  switch(lat)
2269  {//LATTICE_P,LATTICE_I,LATTICE_A,LATTICE_B,LATTICE_C,LATTICE_F
2270  case 0:cent=LATTICE_P;centc='P';break;
2271  case 1:cent=LATTICE_I;centc='I';break;
2272  case 2:cent=LATTICE_F;centc='F';break;
2273  }
2274  minv=EstimateCellVolume(dmin,dmax,nb,CUBIC ,cent,1.5);
2275  maxv=EstimateCellVolume(dmin,dmax,nb,CUBIC ,cent,0.4*weak_f);
2276  mpCellExplorer->SetVolumeMinMax(minv,maxv);
2277  lengthmax=pow(maxv,(float)(1/3.0))*3;
2278  if(lengthmax<25)lengthmax=25;
2279  mpCellExplorer->SetLengthMinMax(3,lengthmax);
2280  mpCellExplorer->SetCrystalSystem(CUBIC);
2281  mpCellExplorer->SetCrystalCentering(cent);
2282  mpLog->AppendText(wxString::Format(_T("CUBIC %c : V= %6.0f -> %6.0f A^3, max length=%6.2fA"),centc,minv,maxv,lengthmax));
2283  t0=chrono.seconds();
2284  if(dlgProgress.Update(0,wxString::Format(_T("CUBIC %c (%u spurious), V=%6.0f-%6.0f, l<%6.2fA\n")
2285  _T("Best Score=%6.1f"),centc,
2286  nbSpurious,minv,maxv,lengthmax,mpCellExplorer->GetBestScore()))==false) break;
2287  mpCellExplorer->DicVol(reportOnScore,reportOnDepth,stopOnScore,stopOnDepth);
2288  mpLog->AppendText(wxString::Format(_T(" -> %3u sols in %6.2fs, best score=%6.1f\n"),
2289  (unsigned int)(mpCellExplorer->GetSolutions().size()),chrono.seconds()-t0,mpCellExplorer->GetBestScore()));
2290  mpLog->Update();
2291  if(noCentered) break;
2292  }
2293  for(int lat=0;lat<=1;++lat)
2294  if((mpCellExplorer->GetBestScore()<=stopOnScore)||continueOnSolution)
2295  {
2296  switch(lat)
2297  {//LATTICE_P,LATTICE_I,LATTICE_A,LATTICE_B,LATTICE_C,LATTICE_F
2298  case 0:cent=LATTICE_P;centc='P';break;
2299  case 1:cent=LATTICE_I;centc='I';break;
2300  }
2301  minv=EstimateCellVolume(dmin,dmax,nb,TETRAGONAL,cent,1.5);
2302  maxv=EstimateCellVolume(dmin,dmax,nb,TETRAGONAL,cent,0.4*weak_f);
2303  mpCellExplorer->SetVolumeMinMax(minv,maxv);
2304  float lengthmax=pow(maxv,(float)(1/3.0))*3;
2305  if(lengthmax<25)lengthmax=25;
2306  mpCellExplorer->SetLengthMinMax(3,lengthmax);
2307  mpCellExplorer->SetCrystalSystem(TETRAGONAL);
2308  mpCellExplorer->SetCrystalCentering(cent);
2309  mpLog->AppendText(wxString::Format(_T("TETRAGONAL %c : V= %6.0f -> %6.0f A^3, max length=%6.2fA"),centc,minv,maxv,lengthmax));
2310  t0=chrono.seconds();
2311  if(dlgProgress.Update(1,wxString::Format(_T("TETRAGONAL %c (%u spurious), V=%6.0f-%6.0f, l<%6.2fA\n")
2312  _T("Best Score=%6.1f"),centc,
2313  nbSpurious,minv,maxv,lengthmax,mpCellExplorer->GetBestScore()))==false) break;
2314  mpCellExplorer->DicVol(reportOnScore,reportOnDepth,stopOnScore,stopOnDepth);
2315  mpLog->AppendText(wxString::Format(_T(" -> %3u sols in %6.2fs, best score=%6.1f\n"),
2316  (unsigned int)(mpCellExplorer->GetSolutions().size()),chrono.seconds()-t0,mpCellExplorer->GetBestScore()));
2317  mpLog->Update();
2318  if(noCentered) break;
2319  }
2320  if((mpCellExplorer->GetBestScore()<=stopOnScore)||continueOnSolution)
2321  {
2322  minv=EstimateCellVolume(dmin,dmax,nb,RHOMBOEDRAL,LATTICE_P,1.5);
2323  maxv=EstimateCellVolume(dmin,dmax,nb,RHOMBOEDRAL,LATTICE_P,0.4*weak_f);
2324  mpCellExplorer->SetVolumeMinMax(minv,maxv);
2325  lengthmax=pow(maxv,(float)(1/3.0))*3;
2326  if(lengthmax<25)lengthmax=25;
2327  mpCellExplorer->SetLengthMinMax(3,lengthmax);
2328  mpCellExplorer->SetCrystalSystem(RHOMBOEDRAL);
2329  mpCellExplorer->SetCrystalCentering(LATTICE_P);
2330  mpLog->AppendText(wxString::Format(_T("RHOMBOEDRAL : V= %6.0f -> %6.0f A^3, max length=%6.2fA"),minv,maxv,lengthmax));
2331  t0=chrono.seconds();
2332  if(dlgProgress.Update(2,wxString::Format(_T("RHOMBOEDRAL (%u spurious), V=%6.0f-%6.0f, l<%6.2fA\n")
2333  _T("Best Score=%6.1f"),
2334  nbSpurious,minv,maxv,lengthmax,mpCellExplorer->GetBestScore()))==false) break;
2335  mpCellExplorer->DicVol(reportOnScore,reportOnDepth,stopOnScore,stopOnDepth);
2336  mpLog->AppendText(wxString::Format(_T(" -> %3u sols in %6.2fs, best score=%6.1f\n"),
2337  (unsigned int)(mpCellExplorer->GetSolutions().size()),chrono.seconds()-t0,mpCellExplorer->GetBestScore()));
2338  mpLog->Update();
2339  }
2340  if((mpCellExplorer->GetBestScore()<=stopOnScore)||continueOnSolution)
2341  {
2342  minv=EstimateCellVolume(dmin,dmax,nb,HEXAGONAL,LATTICE_P,1.5);
2343  maxv=EstimateCellVolume(dmin,dmax,nb,HEXAGONAL,LATTICE_P,0.4*weak_f);
2344  mpCellExplorer->SetVolumeMinMax(minv,maxv);
2345  lengthmax=pow(maxv,(float)(1/3.0))*3;
2346  if(lengthmax<25)lengthmax=25;
2347  mpCellExplorer->SetLengthMinMax(3,lengthmax);
2348  mpCellExplorer->SetCrystalSystem(HEXAGONAL);
2349  mpCellExplorer->SetCrystalCentering(LATTICE_P);
2350  mpLog->AppendText(wxString::Format(_T("HEXAGONAL : V= %6.0f -> %6.0f A^3, max length=%6.2fA"),minv,maxv,lengthmax));
2351  t0=chrono.seconds();
2352  if(dlgProgress.Update(3,wxString::Format(_T("HEXAGONAL (%u spurious), V=%6.0f-%6.0f, l<%6.2fA\n")
2353  _T("Best Score=%6.1f"),
2354  nbSpurious,minv,maxv,lengthmax,mpCellExplorer->GetBestScore()))==false) break;
2355  mpCellExplorer->DicVol(reportOnScore,reportOnDepth,stopOnScore,stopOnDepth);
2356  mpLog->AppendText(wxString::Format(_T(" -> %3u sols in %6.2fs, best score=%6.1f\n"),
2357  (unsigned int)(mpCellExplorer->GetSolutions().size()),chrono.seconds()-t0,mpCellExplorer->GetBestScore()));
2358  mpLog->Update();
2359  }
2360  for(int lat=0;lat<=5;++lat)
2361  if((mpCellExplorer->GetBestScore()<=stopOnScore)||continueOnSolution)
2362  {
2363  switch(lat)
2364  {//LATTICE_P,LATTICE_I,LATTICE_A,LATTICE_B,LATTICE_C,LATTICE_F
2365  case 0:cent=LATTICE_P;centc='P';break;
2366  case 1:cent=LATTICE_I;centc='I';break;
2367  case 2:cent=LATTICE_A;centc='A';break;
2368  case 3:cent=LATTICE_B;centc='B';break;
2369  case 4:cent=LATTICE_C;centc='C';break;
2370  case 5:cent=LATTICE_F;centc='F';break;
2371  }
2372  minv=EstimateCellVolume(dmin,dmax,nb,ORTHOROMBIC,cent,1.5);
2373  maxv=EstimateCellVolume(dmin,dmax,nb,ORTHOROMBIC,cent,0.4*weak_f);
2374  mpCellExplorer->SetVolumeMinMax(minv,maxv);
2375  lengthmax=pow(maxv,(float)(1/3.0))*3;
2376  if(lengthmax<25)lengthmax=25;
2377  mpCellExplorer->SetLengthMinMax(3,lengthmax);
2378  mpCellExplorer->SetCrystalSystem(ORTHOROMBIC);
2379  mpCellExplorer->SetCrystalCentering(cent);
2380  mpLog->AppendText(wxString::Format(_T("ORTHOROMBIC %c: V= %6.0f -> %6.0f A^3, max length=%6.2fA"),centc,minv,maxv,lengthmax));
2381  t0=chrono.seconds();
2382  if(dlgProgress.Update(4,wxString::Format(_T("ORTHOROMBIC %c (%u spurious), V=%6.0f-%6.0f, l<%6.2fA\n")
2383  _T("Best Score=%6.1f"),centc,
2384  nbSpurious,minv,maxv,lengthmax,mpCellExplorer->GetBestScore()))==false) break;
2385  mpCellExplorer->DicVol(reportOnScore,reportOnDepth,stopOnScore,stopOnDepth);
2386  mpLog->AppendText(wxString::Format(_T(" -> %3u sols in %6.2fs, best score=%6.1f\n"),
2387  (unsigned int)(mpCellExplorer->GetSolutions().size()),chrono.seconds()-t0,mpCellExplorer->GetBestScore()));
2388  mpLog->Update();
2389  if(noCentered) break;
2390  }
2391  for(int lat=0;lat<=3;++lat)
2392  if((mpCellExplorer->GetBestScore()<=stopOnScore)||continueOnSolution)
2393  {
2394  switch(lat)
2395  {//LATTICE_P,LATTICE_I,LATTICE_A,LATTICE_B,LATTICE_C,LATTICE_F
2396  case 0:cent=LATTICE_P;centc='P';break;
2397  case 1:cent=LATTICE_C;centc='C';break;
2398  case 2:cent=LATTICE_I;centc='I';break;
2399  case 3:cent=LATTICE_A;centc='A';break;
2400  }
2401  minv=EstimateCellVolume(dmin,dmax,nb,MONOCLINIC,cent,1.5);
2402  maxv=EstimateCellVolume(dmin,dmax,nb,MONOCLINIC,cent,0.4*weak_f);
2403  mpCellExplorer->SetVolumeMinMax(minv,maxv);
2404  lengthmax=pow(maxv,(float)(1/3.0))*3;
2405  if(lengthmax<25)lengthmax=25;
2406  mpCellExplorer->SetLengthMinMax(3,lengthmax);
2407  mpCellExplorer->SetCrystalSystem(MONOCLINIC);
2408  mpCellExplorer->SetCrystalCentering(cent);
2409  mpLog->AppendText(wxString::Format(_T("MONOCLINIC %c : V= %6.0f -> %6.0f A^3, max length=%6.2fA"),centc,minv,maxv,lengthmax));
2410  t0=chrono.seconds();
2411  if(dlgProgress.Update(5,wxString::Format(_T("MONOCLINIC %c (%u spurious), V=%6.0f-%6.0f, l<%6.2fA\n")
2412  _T("Best Score=%6.1f"),centc,
2413  nbSpurious,minv,maxv,lengthmax,mpCellExplorer->GetBestScore()))==false) break;
2414  mpCellExplorer->DicVol(reportOnScore,reportOnDepth,stopOnScore,stopOnDepth);
2415  mpLog->AppendText(wxString::Format(_T(" -> %3u sols in %6.2fs, best score=%6.1f\n"),
2416  (unsigned int)(mpCellExplorer->GetSolutions().size()),chrono.seconds()-t0,mpCellExplorer->GetBestScore()));
2417  mpLog->Update();
2418  if(noCentered) break;
2419  }
2420 
2421  nbSpurious+=1;
2422  if((mpCellExplorer->GetBestScore()>=stopOnScore)||(nbSpurious>3)) break;
2423  mpLog->AppendText(wxString::Format(_T("\n Trying now with %2u spurious peaks\n"),nbSpurious));
2424  mpLog->Update();
2425  }
2426  }
2427  else
2428  {
2429  // Erase spurious record
2430  for(vector<PeakList::hkl>::iterator pos=mpPeakList->mvHKL.begin();pos!=mpPeakList->mvHKL.end();++pos)
2431  pos->isSpurious=false;
2432 
2433  wxString s;
2434  double lmin,lmax,amin=90,amax,vmin,vmax,error,stopOnScore,reportOnScore;
2435  long nbspurious,nbPeak,stopOnDepth,reportOnDepth;
2436  s=mpLengthMin->GetValue();s.ToDouble(&lmin);
2437  s=mpLengthMax->GetValue();s.ToDouble(&lmax);
2438  //s=mpAngleMin->GetValue();s.ToDouble(&amin);
2439  s=mpAngleMax->GetValue();s.ToDouble(&amax);
2440  s=mpVolumeMin->GetValue();s.ToDouble(&vmin);
2441  s=mpVolumeMax->GetValue();s.ToDouble(&vmax);
2442  s=mpNbSpurious->GetValue();s.ToLong(&nbspurious);
2443  s=mpNbPeak->GetValue();s.ToLong(&nbPeak);
2444  s=mpErrorD->GetValue();s.ToDouble(&error);
2445  s=mpStopOnScore->GetValue();s.ToDouble(&stopOnScore);
2446  s=mpStopOnDepth->GetValue();s.ToLong(&stopOnDepth);
2447  s=mpReportOnScore->GetValue();s.ToDouble(&reportOnScore);
2448  s=mpReportOnDepth->GetValue();s.ToLong(&reportOnDepth);
2449 
2450  // Use at most 30 reflections for indexing
2451  if(mpPeakList->GetPeakList().size()>nbPeak) mpPeakList->GetPeakList().resize(nbPeak);
2452 
2453  mpCellExplorer = new CellExplorer(*mpPeakList,(CrystalSystem)(mpBravais->GetSelection()),0);
2454 
2455  mpCellExplorer->SetLengthMinMax((float)lmin,(float)lmax);
2456  mpCellExplorer->SetAngleMinMax((float)amin*DEG2RAD,(float)amax*DEG2RAD);
2457  mpCellExplorer->SetVolumeMinMax((float)vmin,(float)vmax);
2458  mpCellExplorer->SetNbSpurious((unsigned int)nbspurious);
2459  mpCellExplorer->SetD2Error((float)(error*error));
2460 
2461  mpCellExplorer->SetCrystalCentering(LATTICE_P);
2462 
2463  cout<<lmin<<" "<<lmax<<" "<<amin<<" "<<amax<<" "<<vmin<<" "<<vmax<<" "<<(unsigned int)nbspurious<<" "<<error*error<<endl;
2464  #if 1
2465  mpCellExplorer->DicVol(reportOnScore,reportOnDepth,stopOnScore,stopOnDepth);
2466  #else
2467  if(mpAlgorithm->GetSelection()==0) mpCellExplorer->DicVol(reportOnScore,reportOnDepth,stopOnScore,stopOnDepth);
2468  else
2469  {
2470  for(unsigned int i=0;i<20;++i)
2471  {
2472  mpCellExplorer->Evolution(5000,true,0.7,0.5,50);
2473  if(mpCellExplorer->GetBestScore()>stopOnScore) break;
2474  }
2475  }
2476  #endif
2477  }
2478  mpLog->AppendText(wxString::Format(_T("Finished indexing, bestscore=%6.1f, elapsed time=%6.2fs\n"),
2479  mpCellExplorer->GetBestScore(),chrono.seconds()));
2480  // Merge similar solutions - useful here for solutions from different runs/different systems
2481  mpCellExplorer->ReduceSolutions();
2482  if(mpCellExplorer->GetSolutions().size()>0)
2483  {
2484  char buf[200];
2485  wxArrayString sols;
2486  float bestvol=0;
2487  for(list<pair<RecUnitCell,float> >::const_iterator pos=mpCellExplorer->GetSolutions().begin();
2488  pos!=mpCellExplorer->GetSolutions().end();++pos)
2489  {
2490  vector<float> uc=pos->first.DirectUnitCell();
2491  if(pos==mpCellExplorer->GetSolutions().begin()) bestvol=uc[6]*.99999;
2492  const float relvol=uc[6]/bestvol;
2493  string sys;
2494  switch(pos->first.mlattice)
2495  {
2496  case TRICLINIC:sys="TRICLINIC"; break;
2497  case MONOCLINIC:sys="MONOCLINIC"; break;
2498  case ORTHOROMBIC:sys="ORTHOROMBIC"; break;
2499  case HEXAGONAL:sys="HEXAGONAL"; break;
2500  case RHOMBOEDRAL:sys="RHOMBOEDRAL"; break;
2501  case TETRAGONAL:sys="TETRAGONAL"; break;
2502  case CUBIC:sys="CUBIC"; break;
2503  }
2504  char centc;
2505  switch(pos->first.mCentering)
2506  {
2507  case LATTICE_P:centc='P'; break;
2508  case LATTICE_I:centc='I'; break;
2509  case LATTICE_A:centc='A'; break;
2510  case LATTICE_B:centc='B'; break;
2511  case LATTICE_C:centc='C'; break;
2512  case LATTICE_F:centc='F'; break;
2513  }
2514 
2515  sprintf(buf,"Score=%6.1f V=%6.1f(%3.1fV) %6.3f %6.3f %6.3f %6.2f %6.2f %6.2f %s %c",pos->second,
2516  uc[6],relvol,uc[0],uc[1],uc[2],uc[3]*RAD2DEG,uc[4]*RAD2DEG,uc[5]*RAD2DEG,sys.c_str(),centc);
2517  //cout<<buf<<endl;
2518  sols.Add(wxString::FromAscii(buf));
2519  }
2520  mpCell->Set(sols);
2521  }
2522 
2523  if(mpGraph!=0) mpGraph->Refresh(FALSE);
2524 }
2525 void WXCellExplorer::OnSelectCell(wxCommandEvent &event)
2526 {
2527  VFN_DEBUG_ENTRY("WXCellExplorer::OnSelectCell()",7)
2528  const int choice=mpCell->GetSelection();
2529  if(choice!=wxNOT_FOUND)
2530  {
2531  wxString s;
2532  long nbspurious;
2533  s=mpNbSpurious->GetValue();s.ToLong(&nbspurious);
2534 
2535  list<pair<RecUnitCell,float> >::const_iterator pos=mpCellExplorer->GetSolutions().begin();
2536  for(int i=0;i<choice;++i)++pos;// We need a random access ?
2537  // This will update the hkl in the list and therefore on the graph
2538  Score(*mpPeakList,pos->first,nbspurious,true,true,true);
2539  if(mpCrystal!=NULL)
2540  {
2541  // Apply crystal structure
2542  list<pair<RecUnitCell,float> >::const_iterator pos=mpCellExplorer->GetSolutions().begin();
2543  for(int i=0;i<choice;++i)++pos;// We need a random access ?
2544  vector<float> uc=pos->first.DirectUnitCell();
2545  mpCrystal->GetPar("a").SetValue(uc[0]);
2546  mpCrystal->GetPar("b").SetValue(uc[1]);
2547  mpCrystal->GetPar("c").SetValue(uc[2]);
2548  mpCrystal->GetPar("alpha").SetValue(uc[3]);
2549  mpCrystal->GetPar("beta").SetValue(uc[4]);
2550  mpCrystal->GetPar("gamma").SetValue(uc[5]);
2551  switch(pos->first.mlattice)
2552  {
2553  case TRICLINIC:mpCrystal->GetSpaceGroup().ChangeSpaceGroup("P-1");break;
2554  case MONOCLINIC:mpCrystal->GetSpaceGroup().ChangeSpaceGroup("P2/m");break;
2555  case ORTHOROMBIC:mpCrystal->GetSpaceGroup().ChangeSpaceGroup("Pmmm");break;
2556  case HEXAGONAL:mpCrystal->GetSpaceGroup().ChangeSpaceGroup("P6/mmm");break;
2557  case RHOMBOEDRAL:mpCrystal->GetSpaceGroup().ChangeSpaceGroup("R-3m");break;
2558  case TETRAGONAL:mpCrystal->GetSpaceGroup().ChangeSpaceGroup("P4/mmm");break;
2559  case CUBIC:mpCrystal->GetSpaceGroup().ChangeSpaceGroup("Pm-3m");break;
2560  }
2561  mpCrystal->UpdateDisplay();
2562  }
2563  try{
2564  if(mpAutomaticLeBail->GetValue())
2565  {
2566  VFN_DEBUG_MESSAGE("WXCellExplorer::OnSelectCell():auto-Le Bail",7);
2567  // run Le Bail
2568  const bool fitzero=true,
2569  fitwidth0=true,
2570  fitwidth=true,
2571  fiteta=true,
2572  fitasym=true,
2573  fitdispltransp=true,
2574  fitbackgd=true,
2575  fitcell=true;
2576 
2577  wxProgressDialog dlgProgress(_T("Le Bail and Profile Fitting"),_T("Le Bail Fitting, cycle #0/20"),
2578  25,this,wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME|wxPD_CAN_ABORT);
2579  mpDiff->SetExtractionMode(true,true);
2580  VFN_DEBUG_MESSAGE("WXCellExplorer::OnSelectCell():auto-Le Bail",7);
2581 
2582  mpLog->AppendText(wxString::Format(_T("Starting 20 Le Bail cycles\n")));
2583  for(int i=0;i<10;++i)
2584  {
2585  VFN_DEBUG_MESSAGE("WXCellExplorer::OnSelectCell():auto-Le Bail #"<<i,7);
2586  mpDiff->ExtractLeBail(2);
2587  mpDiff->GetParentPowderPattern().FitScaleFactorForRw();
2588  VFN_DEBUG_MESSAGE("WXCellExplorer::OnSelectCell():auto-Le Bail #"<<i,7);
2589  mpDiff->GetParentPowderPattern().UpdateDisplay();
2590  if(dlgProgress.Update(i,wxString::Format(_T("Le Bail Fitting, cycle #%d/20"),i*2))==false) return;
2591  }
2592  mpLog->AppendText(wxString::Format(_T(" => Rwp=%5.3f%%, GoF=%7.3f\n"),
2593  mpDiff->GetParentPowderPattern().GetRw()*100,
2594  mpDiff->GetParentPowderPattern().GetChi2()
2595  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
2596 
2597  LSQNumObj lsqobj("Profile Fitting object");
2598  lsqobj.SetRefinedObj(mpDiff->GetParentPowderPattern(),0,true,true);
2599  lsqobj.PrepareRefParList(true);
2600  lsqobj.SetParIsUsed(gpRefParTypeObjCryst,false);
2601  lsqobj.SetParIsUsed(gpRefParTypeScattDataScale,true);
2602  lsqobj.SetParIsUsed(gpRefParTypeScattDataProfile,true);
2603  lsqobj.SetParIsUsed(gpRefParTypeScattDataCorrPos,true);
2604  lsqobj.SetParIsUsed(gpRefParTypeScattDataBackground,true);
2605  lsqobj.SetParIsUsed(gpRefParTypeUnitCell,true);
2606  lsqobj.SetParIsFixed(gpRefParTypeObjCryst,true);
2607  lsqobj.SetParIsFixed(gpRefParTypeScattDataScale,false);
2608 
2609  // :TODO: take car of other profiles than pseudo-voigt (DE-PV)
2610  if(fitzero) lsqobj.SetParIsFixed("Zero",false);
2611  if(fitwidth0) lsqobj.SetParIsFixed("W",false);
2612  if(fitzero||fitwidth0)
2613  {
2614  mpLog->AppendText(wxString::Format(_T("Fitting zero shift && constant width\n")));
2615  if(dlgProgress.Update(11,_T("Fitting zero shift && constant width"))==false) return;
2616  lsqobj.Refine(5,true,false);
2617  mpDiff->GetParentPowderPattern().FitScaleFactorForRw();
2618  mpDiff->GetParentPowderPattern().UpdateDisplay();
2619  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
2620  mpDiff->GetParentPowderPattern().GetRw()*100,
2621  mpDiff->GetParentPowderPattern().GetChi2()
2622  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
2623  }
2624  if(fitwidth) lsqobj.SetParIsFixed("U",false);
2625  if(fitwidth) lsqobj.SetParIsFixed("V",false);
2626  if(fiteta) lsqobj.SetParIsFixed("Eta0",false);
2627  if(fitwidth||fiteta)
2628  {
2629  mpLog->AppendText(wxString::Format(_T("Fitting width and gaussian/lorentzian fixed mix\n")));
2630  if(dlgProgress.Update(12,_T("Fitting variable width and gaussian/lorentzian fixed mix"))==false) return;
2631  lsqobj.Refine(5,true,false);
2632  mpDiff->GetParentPowderPattern().FitScaleFactorForRw();
2633  mpDiff->GetParentPowderPattern().UpdateDisplay();
2634  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
2635  mpDiff->GetParentPowderPattern().GetRw()*100,
2636  mpDiff->GetParentPowderPattern().GetChi2()
2637  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
2638  }
2639 
2640  if(fiteta) lsqobj.SetParIsFixed("Eta1",false);
2641  if(fiteta)
2642  {
2643  mpLog->AppendText(wxString::Format(_T("Fitting variable width and gaussian/lorentzian mix\n")));
2644  if(dlgProgress.Update(13,_T("Fitting variable width and gaussian/lorentzian mix"))==false) return;
2645  lsqobj.Refine(5,true,false);
2646  mpDiff->GetParentPowderPattern().FitScaleFactorForRw();
2647  mpDiff->GetParentPowderPattern().UpdateDisplay();
2648  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
2649  mpDiff->GetParentPowderPattern().GetRw()*100,
2650  mpDiff->GetParentPowderPattern().GetChi2()
2651  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
2652  }
2653 
2654  if(fitasym) lsqobj.SetParIsFixed("Asym0",false);
2655  if(fitasym) lsqobj.SetParIsFixed("Asym1",false);
2656  if(fitasym) lsqobj.SetParIsFixed("Asym2",false);
2657  if(fitdispltransp) lsqobj.SetParIsFixed("2ThetaDispl",false);
2658  if(fitdispltransp) lsqobj.SetParIsFixed("2ThetaTransp",false);
2659  if(fitdispltransp||fitasym)
2660  {
2661  mpLog->AppendText(wxString::Format(_T("Fitting assymetry and sample displacement/transparency\n")));
2662  if(dlgProgress.Update(14,_T("Fitting assymetry and sample displacement/transparency"))==false) return;
2663  lsqobj.Refine(5,true,false);
2664  mpDiff->GetParentPowderPattern().FitScaleFactorForRw();
2665  mpDiff->GetParentPowderPattern().UpdateDisplay();
2666  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
2667  mpDiff->GetParentPowderPattern().GetRw()*100,
2668  mpDiff->GetParentPowderPattern().GetChi2()
2669  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
2670  }
2671 
2672  if(fitbackgd)
2673  {
2674  lsqobj.SetParIsFixed(gpRefParTypeScattDataBackground,false);
2675  // Make sure points beyond max resolution are not optimized
2676  const unsigned int nbcomp= mpGraph->GetWXPowderPattern().GetPowderPattern().GetNbPowderPatternComponent();
2677  for(unsigned int i=0;i<nbcomp;++i)
2678  if(mpGraph->GetWXPowderPattern().GetPowderPattern().GetPowderPatternComponent(i).GetClassName()=="PowderPatternBackground")
2679  {
2680  PowderPatternBackground *pback=dynamic_cast<PowderPatternBackground *>
2681  (&(mpGraph->GetWXPowderPattern().GetPowderPattern().GetPowderPatternComponent(i)));
2682  pback->FixParametersBeyondMaxresolution(lsqobj.GetCompiledRefinedObj());
2683  }
2684 
2685  mpLog->AppendText(wxString::Format(_T("Fitting background\n")));
2686  if(dlgProgress.Update(15,_T("Fitting background"))==false) return;
2687  lsqobj.Refine(5,true,false);
2688  mpDiff->GetParentPowderPattern().FitScaleFactorForRw();
2689  mpDiff->GetParentPowderPattern().UpdateDisplay();
2690  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
2691  mpDiff->GetParentPowderPattern().GetRw()*100,
2692  mpDiff->GetParentPowderPattern().GetChi2()
2693  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
2694  }
2695 
2696  if(fitcell) lsqobj.SetParIsFixed(gpRefParTypeUnitCell,false);
2697  if(fitcell)
2698  {
2699  mpLog->AppendText(wxString::Format(_T("Fitting unit cell\n")));
2700  if(dlgProgress.Update(16,_T("Fitting unit cell"))==false) return;
2701  lsqobj.Refine(5,true,false);
2702  mpDiff->GetParentPowderPattern().FitScaleFactorForRw();
2703  mpDiff->GetParentPowderPattern().UpdateDisplay();
2704  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
2705  mpDiff->GetParentPowderPattern().GetRw()*100,
2706  mpDiff->GetParentPowderPattern().GetChi2()
2707  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
2708  }
2709  // Run Le Bail again from scratch
2710  mpDiff->SetExtractionMode(true,true);
2711  mpLog->AppendText(wxString::Format(_T("Starting 10 Le Bail cycles\n")));
2712  for(int i=17;i<22;++i)
2713  {
2714  if(dlgProgress.Update(i,wxString::Format(_T("Le Bail Fitting, cycle #%d/10"),(i-17)*2))==false) return;
2715  mpDiff->ExtractLeBail(2);
2716  mpDiff->GetParentPowderPattern().FitScaleFactorForRw();
2717  mpDiff->GetParentPowderPattern().UpdateDisplay();
2718  }
2719  mpLog->AppendText(wxString::Format(_T(" => Rwp=%5.3f%%, GoF=%7.3f\n"),
2720  mpDiff->GetParentPowderPattern().GetRw()*100,
2721  mpDiff->GetParentPowderPattern().GetChi2()
2722  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
2723  // Last fit
2724  mpLog->AppendText(wxString::Format(_T("Last fit...\n")));
2725  if(dlgProgress.Update(23,_T("Last fit..."))==false) return;
2726  lsqobj.Refine(5,true,false);
2727  mpDiff->GetParentPowderPattern().FitScaleFactorForRw();
2728  mpLog->AppendText(wxString::Format(_T(" => Rwp=%5.3f%%, GoF=%7.3f\n"),
2729  mpDiff->GetParentPowderPattern().GetRw()*100,
2730  mpDiff->GetParentPowderPattern().GetChi2()
2731  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
2732  mpDiff->GetParentPowderPattern().UpdateDisplay();
2733  mpCrystal->UpdateDisplay();
2734  }
2735  }
2736  catch(const ObjCrystException &except)
2737  {
2738  mpLog->AppendText(wxString::Format(_T(" OOPS : refinement diverged ! Aborting.")));
2739  }
2740  if(mpGraph!=0) mpGraph->Refresh(FALSE);
2741  //:TODO: store refined cell parameters, display GoF in cell list
2742  }
2743  VFN_DEBUG_EXIT("WXCellExplorer::OnSelectCell",7)
2744 }
2745 void WXCellExplorer::OnApplyCell(wxCommandEvent &event)
2746 {
2747  const int choice=mpCell->GetSelection();
2748  if((mpCrystal!=0)&&(choice!=wxNOT_FOUND))
2749  {
2750  list<pair<RecUnitCell,float> >::const_iterator pos=mpCellExplorer->GetSolutions().begin();
2751  for(int i=0;i<choice;++i)++pos;// We need a random access ?
2752  vector<float> uc=pos->first.DirectUnitCell();
2753  mpCrystal->GetPar("a").SetValue(uc[0]);
2754  mpCrystal->GetPar("b").SetValue(uc[1]);
2755  mpCrystal->GetPar("c").SetValue(uc[2]);
2756  mpCrystal->GetPar("alpha").SetValue(uc[3]);
2757  mpCrystal->GetPar("beta").SetValue(uc[4]);
2758  mpCrystal->GetPar("gamma").SetValue(uc[5]);
2759  mpCrystal->UpdateDisplay();
2760  if(mpGraph!=0)
2761  {
2762  wxCommandEvent ev(ID_POWDERGRAPH_MENU_UPDATE);
2763  mpGraph->OnUpdate(ev);
2764  }
2765  }
2766 }
2767 
2768 void WXCellExplorer::OnChooseCrystal(wxCommandEvent &event)
2769 {
2770  VFN_DEBUG_MESSAGE("WXCellExplorer::OnChooseCrystal()",6)
2772  int choice;
2773  mpCrystal=dynamic_cast<Crystal*>
2774  ( WXDialogChooseFromRegistry(gCrystalRegistry,(wxWindow*)this,
2775  "Choose a Crystal Structure:",choice));
2776  if(0==mpCrystal) return;
2777  mpFieldCrystal->SetValue(mpCrystal->GetName());
2778 }
2779 
2780 void WXCellExplorer::OnAutoLeBail(wxCommandEvent &event)
2781 {
2782  if(mpGraph==NULL)
2783  {
2784  mpAutomaticLeBail->SetValue(false);
2785  return;
2786  }
2787  VFN_DEBUG_ENTRY("WXCellExplorer::OnAutoLeBail()",7)
2788  // Check if powder pattern has a background phase
2789  const unsigned int nbcomp= mpGraph->GetWXPowderPattern().GetPowderPattern().GetNbPowderPatternComponent();
2790  bool needBackground=true;
2791  for(unsigned int i=0;i<nbcomp;++i)
2792  if(mpGraph->GetWXPowderPattern().GetPowderPattern().GetPowderPatternComponent(i).GetClassName()=="PowderPatternBackground")
2793  {
2794  needBackground=false;
2795  break;
2796  };
2797  if(needBackground)
2798  {
2799  int answer =wxMessageBox(_T("To automatically run profile-fitting\n")
2800  _T("and Le Bail extraction, you must have\n")
2801  _T("defined a background phase for the pattern\n")
2802  _T("and you will need to choose a crystal phase\n\n")
2803  _T("Do you want to do that now ?"),
2804  _T("Add Background ?"),wxYES_NO|wxICON_QUESTION);
2805  if(answer==wxNO)
2806  {
2807  mpAutomaticLeBail->SetValue(false);
2808  return;
2809  }
2810  wxCommandEvent ev;
2811  mpGraph->GetWXPowderPattern().OnMenuAddCompBackgdBayesian(ev);
2812  }
2813  // Check if a crystal structure has been selected to apply the calculated cell
2814  if(mpCrystal==NULL)
2815  {
2816  if(gCrystalRegistry.GetNb()==0)
2817  {
2818  mpCrystal=new Crystal(4,5,6,"P1");
2819  mpCrystal->SetName("Indexing Result");
2820  wxTheApp->GetTopWindow()->Layout();
2821  wxTheApp->GetTopWindow()->SendSizeEvent();
2822  }
2823  else
2824  {
2825  int answer =wxMessageBox(_T("To automatically run profile-fitting\n")
2826  _T("and Le Bail extraction, you must have\n")
2827  _T("defined a Crystal phase to apply the cell to\n\n")
2828  _T("Do you want to use an EXISTING crystal structure ?\n")
2829  _T("(otherwise a new one will be created for you)"),
2830  _T("Select Crystal ?"),wxYES_NO|wxICON_QUESTION);
2831  if(answer==wxNO)
2832  {
2833  mpCrystal=new Crystal(4,5,6,"P1");
2834  mpCrystal->SetName("Indexing Result");
2835  wxTheApp->GetTopWindow()->Layout();
2836  wxTheApp->GetTopWindow()->SendSizeEvent();
2837  }
2838  else
2839  {
2840  wxCommandEvent ev;
2841  this->OnChooseCrystal(ev);
2842  }
2843  }
2844  }
2845  // Now make sure this Crystal structure is used by the powder pattern object
2846  bool needPowderPatternDiffraction=true;
2847  unsigned int nbPowderPatternDiffraction=0;
2848  for(unsigned int i=0;i<nbcomp;++i)
2849  if(mpGraph->GetWXPowderPattern().GetPowderPattern().GetPowderPatternComponent(i).GetClassName()=="PowderPatternDiffraction")
2850  {
2851  nbPowderPatternDiffraction++;
2852  mpDiff=dynamic_cast<PowderPatternDiffraction*>
2853  (&(mpGraph->GetWXPowderPattern().GetPowderPattern().GetPowderPatternComponent(i)));
2854  if(&(mpDiff->GetCrystal())==mpCrystal)
2855  {
2856  needPowderPatternDiffraction=false;
2857  break;
2858  }
2859  };
2860  VFN_DEBUG_MESSAGE("WXCellExplorer::OnAutoLeBail():needPowderPatternDiffraction=="<<needPowderPatternDiffraction,7)
2861  if(needPowderPatternDiffraction)
2862  {
2863  if(nbPowderPatternDiffraction>0)
2864  {
2865  int answer =wxMessageBox(_T("To automatically run profile-fitting\n")
2866  _T("and Le Bail extraction, you must assign\n")
2867  _T("the Crystal to a Diffraction Component\n\n")
2868  _T("Do you want to use an already existing one ?"),
2869  _T("Use Crystal Phase ?"),wxYES_NO|wxICON_QUESTION);
2870  if(answer==wxYES)
2871  {
2872  //if(nbPowderPatternDiffraction==1) :TODO: handle multiple phases
2873  {
2874  for(unsigned int i=0;i<nbcomp;++i)
2875  if(mpGraph->GetWXPowderPattern().GetPowderPattern().GetPowderPatternComponent(i).GetClassName()=="PowderPatternDiffraction")
2876  {
2877  mpDiff=dynamic_cast<PowderPatternDiffraction*>
2878  (&(mpGraph->GetWXPowderPattern().GetPowderPattern().GetPowderPatternComponent(i)));
2879  mpDiff->SetCrystal(*mpCrystal);
2880  return;
2881  }
2882  }
2883  }
2884  }
2885  else
2886  {// Create one crystalline phase
2887  VFN_DEBUG_MESSAGE("WXCellExplorer::OnAutoLeBail():Create PowderPatternDiffraction",7)
2888  mpDiff=new PowderPatternDiffraction;
2889  mpDiff->SetCrystal(*mpCrystal);
2890  mpGraph->GetWXPowderPattern().GetPowderPattern().AddPowderPatternComponent(*mpDiff);
2891  if(mpGraph->GetWXPowderPattern().GetPowderPattern().GetRadiation().GetWavelengthType()==WAVELENGTH_TOF)
2892  {
2893  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED,ID_POWDERDIFF_PROFILE_DEPV);
2894  wxPostEvent(mpDiff->WXGet(),event);
2895  }
2896  mpGraph->GetWXPowderPattern().GetPowderPattern().Prepare();
2897  mpGraph->GetWXPowderPattern().CrystUpdate();
2898  wxTheApp->GetTopWindow()->Layout();
2899  wxTheApp->GetTopWindow()->SendSizeEvent();
2900  }
2901  }
2902  // Limit resolution (:TODO: Take into account density of peask to limit to ~100 reflections)
2903  mpDiff->GetParentPowderPattern().SetMaxSinThetaOvLambda(0.25);
2904  // If one cell is already selected, do optimization immediately
2905  if(mpCell->GetSelection()>=0)
2906  {
2907  VFN_DEBUG_MESSAGE("WXCellExplorer::OnAutoLeBail()->OnSelectCell()",7)
2908  cout<<mpCell->GetSelection()<<endl;
2909  wxCommandEvent ev;
2910  this->OnSelectCell(ev);
2911  }
2912  VFN_DEBUG_EXIT("WXCellExplorer::OnAutoLeBail()",7)
2913 }
2914 
2916 
2917 void WXPowderPatternGraph::OnIndex(wxCommandEvent& WXUNUSED(event))
2918 {
2919  wxFrame *mpFrame=new wxFrame(this,-1,_T("Fox cell Explorer (EXPERIMENTAL)"));
2920  WXCellExplorer *mpWXCellExplorer;
2921  mpWXCellExplorer=new WXCellExplorer(mpFrame,mPeakList,this);
2922  mpFrame->Show(TRUE);
2923 }
2924 
2925 void WXPowderPatternGraph::OnChangeScale(wxCommandEvent& event)
2926 {
2927  VFN_DEBUG_MESSAGE("WXPowderPatternGraph::OnChangeScale()",10)
2928  if(event.GetId()==ID_POWDERGRAPH_MENU_XSCALE_DATA) mXScale=0;
2929  if(event.GetId()==ID_POWDERGRAPH_MENU_XSCALE_D) mXScale=1;
2930  if(event.GetId()==ID_POWDERGRAPH_MENU_XSCALE_2PID) mXScale=2;
2931  if(event.GetId()==ID_POWDERGRAPH_MENU_YSCALE_LINEAR)mYScale=0;
2932  if(event.GetId()==ID_POWDERGRAPH_MENU_YSCALE_SQRT) mYScale=1;
2933  if(event.GetId()==ID_POWDERGRAPH_MENU_YSCALE_LOG10) mYScale=2;
2934 
2935  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_DATA, TRUE);
2936  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_D, TRUE);
2937  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_2PID, TRUE);
2938  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_LINEAR, TRUE);
2939  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_SQRT, TRUE);
2940  mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_LOG10, TRUE);
2941 
2942  if(mXScale==0) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_DATA, FALSE);
2943  if(mXScale==1) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_D, FALSE);
2944  if(mXScale==2) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_XSCALE_2PID, FALSE);
2945  if(mYScale==0)mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_LINEAR, FALSE);
2946  if(mYScale==1) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_SQRT, FALSE);
2947  if(mYScale==2) mpPopUpMenu->Enable(ID_POWDERGRAPH_MENU_YSCALE_LOG10, FALSE);
2948 
2949  this->Refresh(false);
2950 }
2951 
2952 void WXPowderPatternGraph::OnLeBail(wxCommandEvent& event)
2953 {
2954  wxFrame *pFrame=new wxFrame(this,-1,_T("Profile Fitting"));
2955  WXProfileFitting *pFit;
2956  pFit=new WXProfileFitting(pFrame,&(this->GetWXPowderPattern().GetPowderPattern()));
2957  pFrame->Show(true);
2958 }
2959 
2960 void WXPowderPatternGraph::OnKeyDown(wxKeyEvent& event)
2961 {
2962  wxMutexLocker mlock(mMutex);
2963  const long nbPoint=mX.numElements();
2964 
2965  switch(event.GetKeyCode())
2966  {
2967  case(WXK_LEFT):
2968  {
2969  const REAL range=mMaxX-mMinX;
2970  mMinX -= range/8;
2971  if(mX(nbPoint-1)>mX(0))
2972  {
2973  if(mMinX<mX(0)) mMinX=mX(0);
2974  }
2975  else
2976  {
2977  if(mMinX<mX(nbPoint-1)) mMinX=mX(nbPoint-1);
2978  }
2979  mMaxX=mMinX+range;
2980  break;
2981  }
2982  case(WXK_RIGHT):
2983  {
2984  const REAL range=mMaxX-mMinX;
2985  mMaxX += range/8;
2986  if(mX(nbPoint-1)>mX(0))
2987  {
2988  if(mMaxX>=mX(nbPoint-1)) mMaxX=mX(nbPoint-1);
2989  }
2990  else
2991  {
2992  if(mMaxX>=mX(0)) mMaxX=mX(0);
2993  }
2994  mMinX=mMaxX-range;
2995  break;
2996  }
2997  case(WXK_UP):
2998  {
2999  REAL max=mObs.max(),min=mObs.min();
3000  if(min<1e-6*max)min=1e-6*max;
3001  if(mYScale==2)
3002  {
3003  const REAL range=log10(max)-log10(min);
3004  mMinIntensity*=pow(10,range/8);
3005  mMaxIntensity*=pow(10,range/8);
3006  break;
3007  }
3008  const REAL range=mMaxIntensity-mMinIntensity;
3009  mMinIntensity+=range/8;
3010  mMaxIntensity+=range/8;
3011  break;
3012  }
3013  case(WXK_DOWN):
3014  {
3015  REAL max=mObs.max(),min=mObs.min();
3016  if(min<1e-6*max)min=1e-6*max;
3017  if(mYScale==2)
3018  {
3019  const REAL range=log10(max)-log10(min);
3020  mMinIntensity*=pow(10,-range/8);
3021  mMaxIntensity*=pow(10,-range/8);
3022  break;
3023  }
3024  const REAL range=mMaxIntensity-mMinIntensity;
3025  mMinIntensity-=range/8;
3026  if(mMinIntensity<1e-6*max) mMinIntensity=1e-6*max;
3027  mMaxIntensity=mMinIntensity+range;
3028  break;
3029  }
3030  case(43):// WXK_ADD ?
3031  {
3032  if(abs(mMaxX-mMinX)>1)
3033  {
3034  const REAL halfrange=(mMaxX-mMinX)/2;
3035  const REAL middle=(mMaxX+mMinX)/2;
3036  mMinX= (long)(middle-halfrange*4./5.);
3037  mMaxX = (long)(middle+halfrange*4./5.);
3038  }
3039  break;
3040  }
3041  case(45):// WXK_SUBTRACT ?
3042  {
3043  const REAL halfrange=(mMaxX-mMinX)/2;
3044  const REAL middle=(mMaxX+mMinX)/2;
3045  mMinX= (long)(middle-halfrange*5./4.);
3046  mMaxX = (long)(middle+halfrange*5./4.);
3047  if(mX(nbPoint-1)>mX(0))
3048  {
3049  if(mMinX<mX(0)) mMinX=mX(0);
3050  if(mMaxX>mX(nbPoint-1)) mMaxX=mX(nbPoint-1);
3051  }
3052  else
3053  {
3054  if(mMinX<mX(nbPoint-1)) mMinX=mX(nbPoint-1);
3055  if(mMaxX>mX(0)) mMaxX=mX(0);
3056  }
3057  break;
3058  }
3059  case(42):// WXK_MULTIPLY
3060  {
3061  const REAL range=mMaxIntensity-mMinIntensity;
3062  mMaxIntensity=mMinIntensity+range*4./5.;
3063  break;
3064  }
3065  case(47):// WXK_DIVIDE
3066  {
3067  const REAL range=mMaxIntensity-mMinIntensity;
3068  mMaxIntensity=mMinIntensity+range*5./4.;
3069  break;
3070  }
3071  default:
3072  {
3073  VFN_DEBUG_MESSAGE("WXPowderPatternGraph::OnKeyDown(): no command for key #"<<event.GetKeyCode(),5);
3074  cout<<"WXPowderPatternGraph::OnKeyDown(): no command for key #"<<event.GetKeyCode()<<endl;
3075  }
3076  }
3077  mClockAxisLimits.Click();
3078  wxUpdateUIEvent ev(ID_POWDER_GRAPH_NEW_PATTERN);
3079  wxPostEvent(this,ev);
3080  event.Skip();
3081 }
3082 
3083 void WXPowderPatternGraph::OnSize(wxSizeEvent& event)
3084 {
3085  this->Refresh(false);
3086 }
3087 
3088 WXPowderPattern& WXPowderPatternGraph::GetWXPowderPattern(){return *mpPattern;}
3089 const WXPowderPattern& WXPowderPatternGraph::GetWXPowderPattern()const{return *mpPattern;}
3090 
3091 void WXPowderPatternGraph::SetPattern(const CrystVector_REAL &x,
3092  const CrystVector_REAL &obs,
3093  const CrystVector_REAL &calc,
3094  const CrystVector_REAL &sigma,
3095  const CrystVector_REAL &chi2Cumul)
3096 {
3097  VFN_DEBUG_ENTRY("WXPowderPatternGraph::SetPattern(x,obs,calc,sigma)",4)
3098  mMutex.Lock();
3099  mX=x;
3100  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF) mX*=RAD2DEG;
3101  mCalc=calc;
3102  //mCalc=SavitzkyGolay(obs,4,2);
3103  //mCalc *= -obs.max()/mCalc.max();
3104  mObs=obs;
3105  mSigma=sigma;
3106  mChi2Cumul=chi2Cumul;
3107  // Reset the zoom parameters, only for the first display or if the limits of the
3108  // full pattern have changed
3109  if( (mMaxX<0)
3110  ||(mpPattern->GetPowderPattern().GetClockPowderPatternPar()>mClockAxisLimits))
3111  {
3112  mMutex.Unlock();
3113  this->ResetAxisLimits();
3114  mMutex.Lock();
3115  }
3116 
3117  mvLabelList.clear();
3118  for(unsigned int i=0;i<mpPattern->GetPowderPattern().GetNbPowderPatternComponent();++i)
3119  mvLabelList.push_back(mpPattern->GetPowderPattern()
3120  .GetPowderPatternComponent(i).GetPatternLabelList());
3121 
3122  mMutex.Unlock();
3123  // If we only send an OnPaint event, only the parts which have been erased are redrawn
3124  // (under windows). SO we must force the complete Refresh of the window... in the
3125  // main thread of course...
3126  if(true==wxThread::IsMain())
3127  {
3128  this->Refresh(false);
3129  }
3130  else
3131  {
3132  wxUpdateUIEvent event(ID_POWDER_GRAPH_NEW_PATTERN);
3133  wxPostEvent(this,event);
3134  }
3135  //cout<<FormatVertVector<REAL>(x,obs,calc,sigma)<<endl;
3136  VFN_DEBUG_EXIT("WXPowderPatternGraph::SetPattern(x,obs,calc,sigma)"<<mX.numElements()<<","<<mCalc.numElements()<<","<<mObs.numElements()<<","<<mSigma.numElements()<<",",4)
3137 }
3138 
3139 void WXPowderPatternGraph::OnRedrawNewPattern(wxUpdateUIEvent& WXUNUSED(event))
3140 {
3141  VFN_DEBUG_MESSAGE("WXPowderPatternGraph::SetPattern()",5)
3142  this->Refresh(false);
3143 }
3144 
3146 {
3147  wxMutexLocker mlock(mMutex);
3148  mMaxIntensity=mObs.max();
3149  mMinIntensity=mObs.min();
3150  const float max=mObs.max();
3151  const float min=mObs.min();
3152  if(max>mMaxIntensity) mMaxIntensity=max;
3153  if(min<mMinIntensity) mMinIntensity=min;
3154  if(mMinIntensity<=0) mMinIntensity=max/1e6;
3155  mMaxIntensity=mMaxIntensity+(mMaxIntensity-mMinIntensity)*0.1;
3156  mMaxX=mX.max();
3157  mMinX=mX.min();
3158  mDefaultIntensityScale=true;
3159  mClockAxisLimits.Click();
3160  VFN_DEBUG_MESSAGE("WXPowderPatternGraph::ResetAxisLimits():"<<mMinIntensity<<","<<mMaxIntensity<<","<<mMinX<<","<<mMaxX,10)
3161 }
3162 long WXPowderPatternGraph::Data2ScreenX(const REAL x)const
3163 {
3164  wxCoord width,height;
3165  this->GetSize(&width, &height);
3166  REAL xs=x,minx=mMinX,maxx=mMaxX;
3167  if(xs<minx)xs=minx;
3168  if(xs>maxx)xs=maxx;
3169  float d,mind,maxd;
3170  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
3171  {
3172  d=2*mpPattern->GetPowderPattern().X2STOL(xs*DEG2RAD);
3173  mind=2*mpPattern->GetPowderPattern().X2STOL(minx*DEG2RAD);
3174  maxd=2*mpPattern->GetPowderPattern().X2STOL(maxx*DEG2RAD);
3175  }
3176  else
3177  {
3178  d=2*mpPattern->GetPowderPattern().X2STOL(xs);
3179  mind=2*mpPattern->GetPowderPattern().X2STOL(minx);
3180  maxd=2*mpPattern->GetPowderPattern().X2STOL(maxx);
3181  }
3182  if(mXScale==1) {xs=d;minx=mind;maxx=maxd;}
3183  if(mXScale==2) {xs=2*M_PI*d;minx=2*M_PI*mind;maxx=2*M_PI*maxd;}
3184  return (long)(mMargin*3+(xs-minx)*(width-3*mMargin)/(maxx-minx));
3185 }
3187 {
3188  return this->Data2ScreenX(mX(x));
3189 }
3190 long WXPowderPatternGraph::Data2ScreenY(const REAL y)const
3191 {
3192  wxCoord width,height;
3193  this->GetSize(&width, &height);
3194  REAL ys=y,miny=mMinIntensity,maxy=mMaxIntensity;
3195  if(ys<miny)ys=miny;
3196  if(ys>maxy)ys=maxy;
3197  if(mYScale==1) {ys=sqrt(ys) ;miny=sqrt(miny) ;maxy=sqrt(maxy);}
3198  if(mYScale==2) {ys=log10(ys);miny=log10(miny);maxy=log10(maxy);}
3199  return (long)(height-mMargin-(ys-miny)*(height-2*mMargin)/(maxy-miny));
3200 }
3201 REAL WXPowderPatternGraph::Screen2DataX(const long x)const
3202 {
3203  wxCoord width,height;
3204  this->GetSize(&width, &height);
3205  REAL minx=mMinX,maxx=mMaxX;
3206  float mind,maxd;
3207  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
3208  {
3209  mind=2*mpPattern->GetPowderPattern().X2STOL(minx*DEG2RAD);
3210  maxd=2*mpPattern->GetPowderPattern().X2STOL(maxx*DEG2RAD);
3211  }
3212  else
3213  {
3214  mind=2*mpPattern->GetPowderPattern().X2STOL(minx);
3215  maxd=2*mpPattern->GetPowderPattern().X2STOL(maxx);
3216  }
3217  if(mXScale==1)
3218  {
3219  minx=mind;
3220  maxx=maxd;
3221  REAL stol=(minx+(x-mMargin*3)*(maxx-minx)/(REAL)(width-3*mMargin))/2;
3222  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
3223  return mpPattern->GetPowderPattern().STOL2X(stol)*RAD2DEG;
3224  else
3225  return mpPattern->GetPowderPattern().STOL2X(stol);
3226  }
3227  if(mXScale==2)
3228  {
3229  minx=2*M_PI*mind;
3230  maxx=2*M_PI*maxd;
3231  REAL stol=(minx+(x-mMargin*3)*(maxx-minx)/(REAL)(width-3*mMargin))/(4*M_PI);
3232  if(mpPattern->GetPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
3233  return mpPattern->GetPowderPattern().STOL2X(stol)*RAD2DEG;
3234  else
3235  return mpPattern->GetPowderPattern().STOL2X(stol);
3236  }
3237  return mMinX+(x-mMargin*3)*(mMaxX-mMinX)/(REAL)(width-3*mMargin);
3238 }
3239 REAL WXPowderPatternGraph::Screen2DataY(const long y)const
3240 {
3241  wxCoord width,height;
3242  this->GetSize(&width, &height);
3243  REAL miny=mMinIntensity,maxy=mMaxIntensity;
3244  if(mYScale==1) {miny=sqrt(miny) ;maxy=sqrt(maxy);}
3245  if(mYScale==2) {miny=log10(miny);maxy=log10(maxy);}
3246  REAL ys=miny+(height-mMargin-y)*(maxy-miny)/(REAL)(height-2*mMargin);
3247  if(mYScale==1) ys=ys*ys;
3248  if(mYScale==2) ys=pow((float)10,(float)ys);
3249  return ys;
3250 }
3251 
3253 //
3254 // WXPowderPatternBackgound
3255 //
3257 static const long ID_POWDERBACKGROUND_GRID= WXCRYST_ID();
3258 static const long ID_POWDERBACKGROUND_NEWBAYESIAN= WXCRYST_ID();
3259 
3260 BEGIN_EVENT_TABLE(WXPowderPatternBackground, wxWindow)
3261  EVT_MENU(ID_POWDERBACKGROUND_IMPORT,
3262  WXPowderPatternBackground::OnMenuImportUserBackground)
3263  EVT_MENU(ID_POWDERBACKGROUND_OPTIMIZEBAYESIAN,
3264  WXPowderPatternBackground::OnMenuOptimizeBayesianBackground)
3265  EVT_GRID_CMD_CELL_CHANGE(ID_POWDERBACKGROUND_GRID,
3266  WXPowderPatternBackground::OnEditGridBackgroundPoint)
3267  EVT_MENU(ID_POWDERBACKGROUND_NEWBAYESIAN,
3268  WXPowderPatternBackground::OnMenuAutomaticBayesianBackground)
3269 END_EVENT_TABLE()
3270 
3272  PowderPatternBackground *b):
3273 WXRefinableObj(parent,b),mpPowderPatternBackground(b),mNeedUpdateUI(false),mIsSelfUpdating(false)
3274 {
3275  mpWXTitle->SetForegroundColour(wxColour(0,255,0));
3276  //Menu
3277  mpMenuBar->AddMenu("Object",ID_REFOBJ_MENU_OBJ);
3278  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDERBACKGROUND_IMPORT,"Import");
3279  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDERBACKGROUND_OPTIMIZEBAYESIAN,
3280  "Bayesian Optimization");
3281  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDERBACKGROUND_NEWBAYESIAN,
3282  "New Automatic Background (Change Number of Points)");
3283  VFN_DEBUG_MESSAGE(mpMenuBar->GetSize().GetWidth()<<","<<mpMenuBar->GetSize().GetHeight(),10);
3284  //mpSizer->SetItemMinSize(mpMenuBar,
3285  // mpMenuBar->GetSize().GetWidth(),
3286  // mpMenuBar->GetSize().GetHeight());
3287 
3288  #ifdef USE_BACKGROUND_MAXLIKE_ERROR
3289  WXCrystObjBasic* pFieldModelSigma=mpPowderPatternBackground
3290  ->GetPar("ML Model Error").wxCreate(this);
3291  mpSizer->Add(pFieldModelSigma,0,wxALIGN_LEFT);
3292  mList.Add(pFieldModelSigma);
3293  #endif
3294  // List of background points
3295  wxGridCellAttr* cellAttrFloat = new wxGridCellAttr;
3296  cellAttrFloat->SetRenderer(new wxGridCellFloatRenderer(10,3));
3297  cellAttrFloat->SetEditor(new wxGridCellFloatEditor(10,3));
3298 
3299  mpGridBackgroundPoint= new wxGrid(this,ID_POWDERBACKGROUND_GRID);
3300  mpGridBackgroundPoint->SetSize(400,300);
3301  mpGridBackgroundPoint->EnableScrolling(true,true);
3302  mpGridBackgroundPoint->SetSizeHints(-1,300,-1,300);
3303  mpGridBackgroundPoint->SetDefaultColSize(150);
3304  mpGridBackgroundPoint->CreateGrid(0,2);
3305  mpGridBackgroundPoint->SetColAttr(0,cellAttrFloat);
3306  mpGridBackgroundPoint->SetColAttr(1,cellAttrFloat->Clone());
3307  mpGridBackgroundPoint->SetColLabelValue(0,_T("Position"));
3308  mpGridBackgroundPoint->SetColLabelValue(1,_T("Intensity"));
3309  mpGridBackgroundPoint->AutoSizeRows();
3310  mpSizer->Add(mpGridBackgroundPoint,0,wxALIGN_LEFT);
3311  mpTopSizer->SetSizeHints(this);
3312  this->Layout();
3313  this->CrystUpdate(true);
3314 }
3315 void WXPowderPatternBackground::OnMenuImportUserBackground(wxCommandEvent & WXUNUSED(event))
3316 {
3317  VFN_DEBUG_MESSAGE("WXPowderPatternBackground::OnMenuImportUserBackground()",6)
3318  wxFileDialog *open= new wxFileDialog(this,_T("Choose background file with 2Theta Ibackgd"),
3319  _T(""),_T(""),_T("*.*"),wxFD_OPEN | wxFD_FILE_MUST_EXIST);
3320  if(open->ShowModal() != wxID_OK) return;
3321  mpPowderPatternBackground->ImportUserBackground(string(open->GetPath().ToAscii()));
3322  open->Destroy();
3323 }
3324 void WXPowderPatternBackground::OnMenuOptimizeBayesianBackground(wxCommandEvent & WXUNUSED(event))
3325 {
3326  VFN_DEBUG_ENTRY("WXPowderPatternBackground::OnMenuOptimizeBayesianBackground()",6)
3327  mpPowderPatternBackground->UnFixAllPar();
3328  mpPowderPatternBackground->OptimizeBayesianBackground();
3329  mpPowderPatternBackground->FixAllPar();
3330  this->CrystUpdate();
3331  VFN_DEBUG_EXIT("WXPowderPatternBackground::OnMenuOptimizeBayesianBackground()",6)
3332 }
3333 void WXPowderPatternBackground::OnMenuAutomaticBayesianBackground(wxCommandEvent & WXUNUSED(event))
3334 {
3335  VFN_DEBUG_ENTRY("WXPowderPatternBackground::OnMenuAutomaticBayesianBackground()",6)
3337 
3338  long nbPointSpline=20;
3339  wxString mes(_T("Number of Interpolation Points"));
3340  wxString s;
3341  s.Printf(_T("%ld"),nbPointSpline);
3342  wxTextEntryDialog dialog(this,mes,_T("Automatic Bayesian (David-Sivia) Background"),
3343  s,wxOK | wxCANCEL);
3344  if(wxID_OK!=dialog.ShowModal())
3345  {
3346  VFN_DEBUG_EXIT("WXPowderPatternBackground::OnMenuAutomaticBayesianBackground():Canceled",6)
3347  return;
3348  }
3349  dialog.GetValue().ToLong(&nbPointSpline);
3350  wxProgressDialog dlgProgress(_T("Automatic Bayesian Background"),_T("Automatic Background, Initializing..."),
3351  4,this,wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME|wxPD_CAN_ABORT);
3352  if(nbPointSpline<2) nbPointSpline=2;
3353  {
3354  CrystVector_REAL x(nbPointSpline),backgd(nbPointSpline);
3355  const CrystVector_REAL *pObs=&(mpPowderPatternBackground->GetParentPowderPattern().GetPowderPatternObs());
3356  const unsigned long nbPoint=mpPowderPatternBackground->GetParentPowderPattern().GetNbPoint();
3357  const float xmin=mpPowderPatternBackground->GetParentPowderPattern()
3358  .GetPowderPatternX()(0),
3359  xmax=mpPowderPatternBackground->GetParentPowderPattern()
3360  .GetPowderPatternX()(nbPoint-1);
3361  for(int i=0;i<nbPointSpline;i++)
3362  {// xmax is not necessarily > xmin, but in the right order (TOF)
3363  x(i)=xmin+(xmax-xmin)/(REAL)(nbPointSpline-1)*REAL(i);
3364  REAL x1=xmin+(xmax-xmin)/(REAL)(nbPointSpline-1)*REAL(i-.2);
3365  REAL x2=xmin+(xmax-xmin)/(REAL)(nbPointSpline-1)*REAL(i+.2);
3366  long n1=(long)(mpPowderPatternBackground->GetParentPowderPattern().X2Pixel(x1));
3367  long n2=(long)(mpPowderPatternBackground->GetParentPowderPattern().X2Pixel(x2));
3368  if(n1<0) n1=0;
3369  if(n2>(long)nbPoint)n2=nbPoint;
3370  backgd(i)=(*pObs)(n1);
3371  for(long j=n1;j<n2;j++)
3372  if((*pObs)(j)<backgd(i))backgd(i)=(*pObs)(j);
3373  }
3374  mpPowderPatternBackground->SetInterpPoints(x,backgd);
3375  }
3376  //mpPowderPatternBackground->GetParentPowderPattern().Prepare();
3377  mpPowderPatternBackground->UnFixAllPar();
3378  mpPowderPatternBackground->GetOption(0).SetChoice(0);//linear
3379  if(dlgProgress.Update(1,_T("Automatic Background: Optimizing Linear Model..."))==false) return;
3380  mpPowderPatternBackground->OptimizeBayesianBackground();
3381  mpPowderPatternBackground->GetOption(0).SetChoice(1);//spline
3382  if(dlgProgress.Update(2,_T("Automatic Background: Optimizing Spline Model..."))==false) return;
3383  mpPowderPatternBackground->OptimizeBayesianBackground();
3384  mpPowderPatternBackground->FixAllPar();
3385 
3386  this->CrystUpdate();
3387  VFN_DEBUG_EXIT("WXPowderPatternBackground::OnMenuAutomaticBayesianBackground()",6)
3388 }
3389 void WXPowderPatternBackground::OnEditGridBackgroundPoint(wxGridEvent &e)
3390 {
3391  if(mIsSelfUpdating) return;
3392  VFN_DEBUG_ENTRY("WXPowderPatternBackground::OnEditGridBackgroundPoint():"<<e.GetRow()<<","<<e.GetCol(),10)
3393  const long r=e.GetRow();
3394  const long c=e.GetCol();
3395  wxString s=mpGridBackgroundPoint->GetCellValue(r,c);
3396  if(s!=_T(""))
3397  {
3398  REAL f=1.0;
3399  if(mpPowderPatternBackground->GetParentPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)f=DEG2RAD;
3400  double d;
3401  s.ToDouble(&d);
3402  if(c==0)
3403  {
3404  if(d!=mBackgroundInterpPointX(r))
3405  mBackgroundInterpPointX(r)=d*f;
3406  }
3407  else
3408  {
3409  if(d!=mBackgroundInterpPointX(r))
3410  mBackgroundInterpPointIntensity(r)=d;
3411  }
3412 
3413  mpPowderPatternBackground->SetInterpPoints(mBackgroundInterpPointX,
3414  mBackgroundInterpPointIntensity);
3415  // The order of the points might have changed
3416  mBackgroundInterpPointX =*(mpPowderPatternBackground->GetInterpPoints().first);
3417  mBackgroundInterpPointIntensity=*(mpPowderPatternBackground->GetInterpPoints().second);
3418  }
3419  mNeedUpdateUI=true,
3420  this->UpdateUI();
3421  mpPowderPatternBackground->GetParentPowderPattern().UpdateDisplay();
3422  VFN_DEBUG_EXIT("WXPowderPatternBackground::OnEditGridBackgroundPoint():"<<e.GetRow()<<","<<e.GetCol(),10)
3423 }
3424 
3425 void WXPowderPatternBackground::CrystUpdate(const bool uui,const bool lock)
3426 {
3427  if(lock) mMutex.Lock();
3428  this->WXRefinableObj::CrystUpdate(uui,false);
3429  if(false==mpPowderPatternBackground->IsBeingRefined())
3430  {
3431  const long diff=mpPowderPatternBackground->GetInterpPoints().first->numElements()
3432  -mpGridBackgroundPoint->GetNumberRows();
3433  if(diff>0)
3434  {
3435  mNeedUpdateUI=true;
3436  mpGridBackgroundPoint->AppendRows(diff);
3437  }
3438  if(diff<0)
3439  {
3440  mNeedUpdateUI=true;
3441  mpGridBackgroundPoint->DeleteRows(0,-diff);
3442  }
3443  if(diff==0)
3444  if( (MaxDifference(mBackgroundInterpPointX ,
3445  *(mpPowderPatternBackground->GetInterpPoints().first )))
3446  ||(MaxDifference(mBackgroundInterpPointIntensity,
3447  *(mpPowderPatternBackground->GetInterpPoints().second))))
3448  mNeedUpdateUI=true;
3449  if(mNeedUpdateUI)
3450  {
3451  mBackgroundInterpPointX =*(mpPowderPatternBackground->GetInterpPoints().first);
3452  mBackgroundInterpPointIntensity=*(mpPowderPatternBackground->GetInterpPoints().second);
3453  }
3454  }
3455  if(lock) mMutex.Unlock();
3456 }
3457 
3459 {
3460  if(lock) mMutex.Lock();
3461  if(mNeedUpdateUI)
3462  {
3463  REAL f=1.0;
3464  if(mpPowderPatternBackground->GetParentPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)f=RAD2DEG;
3465  const long nb=mBackgroundInterpPointX.numElements();
3466  mIsSelfUpdating=true;
3467  for(long i=0;i<nb;++i)
3468  {
3469  wxString tmp;
3470  tmp.Printf(_T("%f"),f*mBackgroundInterpPointX(i));
3471  mpGridBackgroundPoint->SetCellValue(i,0,tmp);
3472  tmp.Printf(_T("%f"),mBackgroundInterpPointIntensity(i));
3473  mpGridBackgroundPoint->SetCellValue(i,1,tmp);
3474  }
3475  mIsSelfUpdating=false;
3476  }
3477 
3478  mNeedUpdateUI=false;
3479  this->WXRefinableObj::UpdateUI(false);
3480  if(lock) mMutex.Unlock();
3481 }
3482 
3483 bool WXPowderPatternBackground::Enable(bool e)
3484 {
3485  if(0!=mpGridBackgroundPoint) mpGridBackgroundPoint->Enable(e);
3486  return this->::wxWindow::Enable(e);
3487 }
3488 
3490 //
3491 // WXTexturePhaseMarchDollase
3492 //
3494 WXTexturePhaseMarchDollase::WXTexturePhaseMarchDollase(wxWindow *parent,
3495  TexturePhaseMarchDollase *pObj,
3496  TextureMarchDollase* pTex):
3497 WXCrystObjBasic(parent),mpTexturePhaseMarchDollase(pObj)
3498 {
3499  VFN_DEBUG_ENTRY("WXTexturePhaseMarchDollase::WXTexturePhaseMarchDollase()",5)
3500  mpSizer=new wxBoxSizer(wxHORIZONTAL);
3501  this->SetSizer(mpSizer);
3502  pTex->Print();
3503  WXCrystObjBasic* pFieldFraction=pTex->GetPar(&(pObj->mFraction)).WXCreate(this);
3504  mpSizer->Add(pFieldFraction,0,wxALIGN_LEFT);
3505  mList.Add(pFieldFraction);
3506 
3507  WXCrystObjBasic* pFieldMarch=pTex->GetPar(&(pObj->mMarchCoeff)).WXCreate(this);
3508  mpSizer->Add(pFieldMarch,0,wxALIGN_LEFT);
3509  mList.Add(pFieldMarch);
3510 
3511  WXCrystObjBasic* pFieldH=pTex->GetPar(&(pObj->mH)).WXCreate(this);
3512  mpSizer->Add(pFieldH,0,wxALIGN_LEFT);
3513  mList.Add(pFieldH);
3514 
3515  WXCrystObjBasic* pFieldK=pTex->GetPar(&(pObj->mK)).WXCreate(this);
3516  mpSizer->Add(pFieldK,0,wxALIGN_LEFT);
3517  mList.Add(pFieldK);
3518 
3519  WXCrystObjBasic* pFieldL=pTex->GetPar(&(pObj->mL)).WXCreate(this);
3520  mpSizer->Add(pFieldL,0,wxALIGN_LEFT);
3521  mList.Add(pFieldL);
3522 
3523  this->CrystUpdate(true);
3524  VFN_DEBUG_EXIT("WXTexturePhaseMarchDollase::WXTexturePhaseMarchDollase()",5)
3525 }
3526 
3527 WXTexturePhaseMarchDollase::~WXTexturePhaseMarchDollase()
3528 {
3529  mpTexturePhaseMarchDollase->WXNotifyDelete();
3530 }
3531 void WXTexturePhaseMarchDollase::CrystUpdate(const bool uui,const bool lock)
3532 {
3533  if(lock) mMutex.Lock();
3534  mList.CrystUpdate(uui,false);
3535  if(lock) mMutex.Unlock();
3536 }
3538 {
3539  if(lock) mMutex.Lock();
3540  mList.UpdateUI(false);
3541  if(lock) mMutex.Unlock();
3542 }
3543 
3545 //
3546 // WXTextureMarchDollase
3547 //
3549 BEGIN_EVENT_TABLE(WXTextureMarchDollase, wxWindow)
3550  EVT_MENU(ID_POWDERTEXTURE_MENU_ADDPHASE, WXTextureMarchDollase::OnAddTexturePhase)
3551  EVT_MENU(ID_POWDERTEXTURE_MENU_DELETEPHASE,WXTextureMarchDollase::OnDeleteTexturePhase)
3552  EVT_UPDATE_UI(ID_CRYST_UPDATEUI, WXRefinableObj::OnUpdateUI)
3553 END_EVENT_TABLE()
3554 
3556 WXRefinableObj(parent,(RefinableObj*)obj),mpTextureMarchDollase(obj)
3557 {
3558  VFN_DEBUG_ENTRY("WXTextureMarchDollase::WXTextureMarchDollase()",5)
3559  // Menu
3560  mpMenuBar->AddMenu("Phases",ID_REFOBJ_MENU_OBJ);
3561  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDERTEXTURE_MENU_ADDPHASE,
3562  "Add Phase");
3563  //existing phases
3564  WXRegistry<TexturePhaseMarchDollase> *pWXPhaseRegistry
3565  =mpTextureMarchDollase->mPhaseRegistry.WXCreate(this);
3566  mpSizer->Add(pWXPhaseRegistry,0,wxALIGN_LEFT);
3567  mList.Add(pWXPhaseRegistry);
3568  this->CrystUpdate(true);
3569  this->SetToolTip(_T("Texture for this crystalline phase.\n")
3570  _T("You can describe the preferred orientation using ")
3571  _T("the March-Dollase model (use the menu).\n\n")
3572  _T("Although possible, it is not recommended to enable ")
3573  _T("the global optimization of texture parameters, ")
3574  _T("as it is *extremely* slow"));
3575  VFN_DEBUG_EXIT("WXTextureMarchDollase::WXTextureMarchDollase()",5)
3576 }
3577 void WXTextureMarchDollase::OnAddTexturePhase(wxCommandEvent & WXUNUSED(event))
3578 {
3579  VFN_DEBUG_ENTRY("WXTextureMarchDollase::OnAddTexturePhase()",5)
3580  mpTextureMarchDollase->AddPhase(0.,1.,1,0,0);
3581  VFN_DEBUG_EXIT("WXTextureMarchDollase::OnAddTexturePhase()",5)
3582 }
3583 void WXTextureMarchDollase::OnDeleteTexturePhase(wxCommandEvent & WXUNUSED(event))
3584 {
3585 }
3586 
3588 //
3589 // WXTextureEllipsoid
3590 //
3592 WXTextureEllipsoid::WXTextureEllipsoid(wxWindow *parent, TextureEllipsoid *pObj):
3593 WXCrystObj(parent),mpTextureEllipsoid(pObj)
3594 {
3595  VFN_DEBUG_ENTRY("WXTextureEllipsoid::WXTextureEllipsoid()",6)
3596  mpWXTitle->SetLabel("Texture ellipsoid");
3597  mpWXTitle->SetForegroundColour(wxColour(0,0,255));
3598  // First line
3599  wxBoxSizer* sizer1=new wxBoxSizer(wxHORIZONTAL);
3600  WXCrystObjBasic* pFieldEPR1=mpTextureEllipsoid->GetPar((long)0).WXCreate(this);
3601  WXCrystObjBasic* pFieldEPR2=mpTextureEllipsoid->GetPar(1).WXCreate(this);
3602  WXCrystObjBasic* pFieldEPR3=mpTextureEllipsoid->GetPar(2).WXCreate(this);
3603  sizer1->Add(pFieldEPR1,0);
3604  sizer1->Add(pFieldEPR2,0);
3605  sizer1->Add(pFieldEPR3,0);
3606  mList.Add(pFieldEPR1);
3607  mList.Add(pFieldEPR2);
3608  mList.Add(pFieldEPR3);
3609  mpSizer->Add(sizer1);
3610  pFieldEPR1->SetToolTip(_T("Texture Ellipsoidal function parameters:\n")
3611  _T("Icorr = Iobs[ 1 + (EPR1*h^2 + EPR2*k^2 + EPR3*l^2 + EPR4*2hk + EPR5*2hl + EPR6*2kl) * 0.001d^2 ]^-1.5"));
3612  pFieldEPR2->SetToolTip(_T("Texture Ellipsoidal function parameters:\n")
3613  _T("Icorr = Iobs[ 1 + (EPR1*h^2 + EPR2*k^2 + EPR3*l^2 + EPR4*2hk + EPR5*2hl + EPR6*2kl) * 0.001d^2 ]^-1.5"));
3614  pFieldEPR3->SetToolTip(_T("Texture Ellipsoidal function parameters:\n")
3615  _T("Icorr = Iobs[ 1 + (EPR1*h^2 + EPR2*k^2 + EPR3*l^2 + EPR4*2hk + EPR5*2hl + EPR6*2kl) * 0.001d^2 ]^-1.5"));
3616  // Second line
3617  wxBoxSizer* sizer2=new wxBoxSizer(wxHORIZONTAL);
3618  WXCrystObjBasic* pFieldEPR4=mpTextureEllipsoid->GetPar(3).WXCreate(this);
3619  WXCrystObjBasic* pFieldEPR5=mpTextureEllipsoid->GetPar(4).WXCreate(this);
3620  WXCrystObjBasic* pFieldEPR6=mpTextureEllipsoid->GetPar(5).WXCreate(this);
3621  sizer2->Add(pFieldEPR4,0);
3622  sizer2->Add(pFieldEPR5,0);
3623  sizer2->Add(pFieldEPR6,0);
3624  mList.Add(pFieldEPR4);
3625  mList.Add(pFieldEPR5);
3626  mList.Add(pFieldEPR6);
3627  mpSizer->Add(sizer2);
3628  pFieldEPR4->SetToolTip(_T("Texture Ellipsoidal function parameters:\n")
3629  _T("Icorr = Iobs[ 1 + (EPR1*h^2 + EPR2*k^2 + EPR3*l^2 + EPR4*2hk + EPR5*2hl + EPR6*2kl) * 0.001d^2 ]^-1.5"));
3630  pFieldEPR5->SetToolTip(_T("Texture Ellipsoidal function parameters:\n")
3631  _T("Icorr = Iobs[ 1 + (EPR1*h^2 + EPR2*k^2 + EPR3*l^2 + EPR4*2hk + EPR5*2hl + EPR6*2kl) * 0.001d^2 ]^-1.5"));
3632  pFieldEPR6->SetToolTip(_T("Texture Ellipsoidal function parameters:\n")
3633  _T("Icorr = Iobs[ 1 + (EPR1*h^2 + EPR2*k^2 + EPR3*l^2 + EPR4*2hk + EPR5*2hl + EPR6*2kl) * 0.001d^2 ]^-1.5"));
3634 
3635  this->CrystUpdate(true);
3636  VFN_DEBUG_EXIT("WXTextureEllipsoid::WXTextureEllipsoid()",6)
3637 }
3638 WXTextureEllipsoid::~WXTextureEllipsoid()
3639 {
3640  mpTextureEllipsoid->WXNotifyDelete();
3641 }
3643 {
3644  return false;
3645 }
3646 
3647 
3649 //
3650 // WXPowderPatternDiffraction
3651 //
3653 static const long ID_POWDERDIFF_PROFILE= WXCRYST_ID();
3654 static const long ID_POWDERDIFF_PROFILE_PV= WXCRYST_ID();
3655 static const long ID_POWDERDIFF_PROFILE_PV_ANISO= WXCRYST_ID();
3656 static const long ID_POWDERDIFF_LEBAIL= WXCRYST_ID();
3657 static const long ID_POWDERDIFF_PROFILEFITTINGMODE= WXCRYST_ID();
3658 static const long ID_POWDERDIFF_USELOCALLATTICEPAR= WXCRYST_ID();
3659 
3660 BEGIN_EVENT_TABLE(WXPowderPatternDiffraction, wxWindow)
3661  EVT_BUTTON(ID_POWDERDIFF_CRYSTAL,WXPowderPatternDiffraction::OnChangeCrystal)
3662  EVT_MENU(ID_POWDERDIFF_SAVEHKLFCALC,
3663  WXPowderPatternDiffraction::OnMenuSaveHKLFcalc)
3664  EVT_MENU(ID_POWDERDIFF_PROFILE_PV, WXPowderPatternDiffraction::OnChangeProfile)
3665  EVT_MENU(ID_POWDERDIFF_PROFILE_PV_ANISO, WXPowderPatternDiffraction::OnChangeProfile)
3666  EVT_MENU(ID_POWDERDIFF_PROFILE_DEPV, WXPowderPatternDiffraction::OnChangeProfile)
3667  EVT_MENU(ID_POWDERDIFF_LEBAIL, WXPowderPatternDiffraction::OnLeBail)
3668  EVT_CHECKBOX(ID_POWDERDIFF_PROFILEFITTINGMODE,WXPowderPatternDiffraction::OnLeBail)
3669  EVT_CHECKBOX(ID_POWDERDIFF_USELOCALLATTICEPAR,WXPowderPatternDiffraction::OnFreezeLatticePar)
3670  EVT_UPDATE_UI(ID_CRYST_UPDATEUI, WXRefinableObj::OnUpdateUI)
3671 END_EVENT_TABLE()
3672 
3674  PowderPatternDiffraction *p):
3675 WXRefinableObj(parent,p),mpPowderPatternDiffraction(p),
3676 mFreezeLatticePar(false),mFrozenLatticePar(6),mNeedLayout(false)
3677 {
3678  VFN_DEBUG_ENTRY("WXPowderPatternDiffraction::WXPowderPatternDiffraction()",6)
3679  mpWXTitle->SetForegroundColour(wxColour(0,255,0));
3680  //Menu
3681  mpMenuBar->AddMenu("File",ID_REFOBJ_MENU_OBJ);
3682  mpMenuBar->AddMenuItem(ID_REFOBJ_MENU_OBJ,ID_POWDERDIFF_SAVEHKLFCALC,
3683  "Save HKL Fcalc");
3684  mpMenuBar->AddMenu("Profile",ID_POWDERDIFF_PROFILE);
3685  mpMenuBar->AddMenuItem(ID_POWDERDIFF_PROFILE,ID_POWDERDIFF_PROFILE_PV,
3686  "Pseudo-Voigt (X-Ray & monochromatic neutron)");
3687  mpMenuBar->AddMenuItem(ID_POWDERDIFF_PROFILE,ID_POWDERDIFF_PROFILE_PV_ANISO,
3688  "Anisotropic Pseudo-Voigt (X-Ray & monochromatic neutron)");
3689  mpMenuBar->AddMenuItem(ID_POWDERDIFF_PROFILE,ID_POWDERDIFF_PROFILE_DEPV,
3690  "Double-Exponential Pseudo-Voigt (neutron TOF)");
3691  mpMenuBar->GetMenu(ID_POWDERDIFF_PROFILE).AppendSeparator();
3692  mpMenuBar->AddMenuItem(ID_POWDERDIFF_PROFILE,ID_POWDERDIFF_LEBAIL,
3693  "Profile Fitting + Le Bail Extraction");
3694  //mpSizer->SetItemMinSize(mpMenuBar,
3695  // mpMenuBar->GetSize().GetWidth(),
3696  // mpMenuBar->GetSize().GetHeight());
3697  // Profile Fitting Mode
3698  mpProfileFittingMode= new wxCheckBox(this,ID_POWDERDIFF_PROFILEFITTINGMODE,
3699  _T("Profile Fitting (Le Bail) Mode"));
3700  mpSizer->Add(mpProfileFittingMode,0,wxALIGN_LEFT);
3701  // Crystal Choice
3702  mpFieldCrystal=new WXFieldChoice(this,ID_POWDERDIFF_CRYSTAL,"Crystal:",300);
3703  mpSizer->Add(mpFieldCrystal,0,wxALIGN_LEFT);
3704  mList.Add(mpFieldCrystal);
3705  mpFieldCrystal->SetToolTip(_T("Crystal structure for this diffraction phase\n")
3706  _T("Click on the button to select another structure"));
3707  // Freeze lattice par ?
3708  wxSizer *pSizerFreezePar=new wxBoxSizer(wxHORIZONTAL);
3709  mpFreezeLatticePar= new wxCheckBox(this,ID_POWDERDIFF_USELOCALLATTICEPAR, _T("Freeze lattice par."));
3710  pSizerFreezePar->Add(mpFreezeLatticePar);
3711  mpGridFrozenLatticePar=new wxGrid(this,-1,wxDefaultPosition,wxDefaultSize);
3712  mpGridFrozenLatticePar->SetColLabelSize(0);
3713  mpGridFrozenLatticePar->SetRowLabelSize(0);
3714  mpGridFrozenLatticePar->DisableDragRowSize();
3715  pSizerFreezePar->Add(mpGridFrozenLatticePar);
3716  mpGridFrozenLatticePar->SetDefaultEditor(new wxGridCellFloatEditor(7,4));
3717  mpGridFrozenLatticePar->SetDefaultRenderer(new wxGridCellFloatRenderer(7,4));
3718  mpGridFrozenLatticePar->EnableScrolling(false,false);
3719  mpGridFrozenLatticePar->ShowScrollbars(wxSHOW_SB_NEVER ,wxSHOW_SB_NEVER );
3720  mpGridFrozenLatticePar->CreateGrid(1,6);
3721  mpGridFrozenLatticePar->SetDefaultColSize(60);
3722  mpGridFrozenLatticePar->EnableEditing(false);
3723  mpSizer->AddSpacer(1);
3724  mpSizer->Add(pSizerFreezePar);
3725  mpSizer->AddSpacer(1);
3726 
3727  //Global Biso factor
3728  WXCrystObjBasic* fieldGlobalBiso
3729  =mpPowderPatternDiffraction->GetPar(&(mpPowderPatternDiffraction->mGlobalBiso))
3730  .WXCreate(this);
3731  mList.Add(fieldGlobalBiso);
3732  mpSizer->Add(fieldGlobalBiso);
3733  // Texture (March Dollase
3734  WXTextureMarchDollase* pTexMD
3735  =new WXTextureMarchDollase(this,&(mpPowderPatternDiffraction->mCorrTextureMarchDollase));
3736  mList.Add(pTexMD);
3737  mpSizer->Add(pTexMD);
3738  // Texture Ellipsoid
3739  WXTextureEllipsoid* pTexEllips
3740  =new WXTextureEllipsoid(this,&(mpPowderPatternDiffraction->mCorrTextureEllipsoid));
3741  mList.Add(pTexEllips);
3742  mpSizer->Add(pTexEllips);
3743  // Profile
3744 
3745  if(mpPowderPatternDiffraction->mpReflectionProfile!=0)
3746  {
3747  VFN_DEBUG_ENTRY("WXPowderPatternDiffraction::WXPowderPatternDiffraction()",6)
3748  WXCrystObjBasic* pWXProf=mpPowderPatternDiffraction
3749  ->mpReflectionProfile->WXCreate(this);
3750  mpSizer->Add(pWXProf);
3751  mList.Add(pWXProf);
3753  }
3754 
3755  this->CrystUpdate(true);
3756  VFN_DEBUG_EXIT("WXPowderPatternDiffraction::WXPowderPatternDiffraction()",6)
3757 }
3758 
3759 void WXPowderPatternDiffraction::OnChangeCrystal(wxCommandEvent & WXUNUSED(event))
3760 {
3761  VFN_DEBUG_MESSAGE("WXPowderPatternDiffraction::OnChangeCrystal()",6)
3763  int choice;
3764  Crystal *cryst=dynamic_cast<Crystal*>
3765  ( WXDialogChooseFromRegistry(gCrystalRegistry,(wxWindow*)this,
3766  "Choose a Crystal Structure:",choice));
3767  if(0==cryst) return;
3768  mpPowderPatternDiffraction->SetCrystal(*cryst);
3769  this->CrystUpdate(true);
3770 }
3771 void WXPowderPatternDiffraction::OnMenuSaveHKLFcalc(wxCommandEvent & WXUNUSED(event))
3772 {
3773  VFN_DEBUG_MESSAGE("WXPowderPatternDiffraction::OnMenuSaveHKLFcalc()",6)
3775  wxFileDialog save(this,_T("Choose a file to save to"),_T(""),_T(""),_T("*.txt"),wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
3776  if(save.ShowModal() != wxID_OK) return;
3777 
3778  ofstream out(save.GetPath().ToAscii());
3779  if(!out) return;//:TODO:
3780  mpPowderPatternDiffraction->PrintFhklCalc(out);
3781  out.close();
3782 }
3783 
3784 void WXPowderPatternDiffraction::CrystUpdate(const bool uui,const bool lock)
3785 {
3786  VFN_DEBUG_MESSAGE("WXPowderPatternDiffraction::CrystUpdate()",10)
3787  if(lock) mMutex.Lock();
3788  for(unsigned int i=0;i<6;i++) mFrozenLatticePar(i)=mpPowderPatternDiffraction->GetFrozenLatticePar(i);
3789  if(mFreezeLatticePar!=mpPowderPatternDiffraction->FreezeLatticePar())
3790  {
3791  mFreezeLatticePar=mpPowderPatternDiffraction->FreezeLatticePar();
3792  mNeedLayout=true;
3793  }
3794  this->WXRefinableObj::CrystUpdate(uui,false);
3795  if(lock) mMutex.Unlock();
3796 }
3797 
3799 {
3800  VFN_DEBUG_MESSAGE("WXPowderPatternDiffraction::UpdateUI()",10)
3801  if(lock) mMutex.Lock();
3802  mpFieldCrystal->SetValue(mpPowderPatternDiffraction->GetCrystal().GetName());
3803  mpProfileFittingMode->SetValue(mpPowderPatternDiffraction->GetExtractionMode());
3804  mpPowderPatternDiffraction->mCorrTextureEllipsoid.UpdateEllipsoidPar();
3805  mpGridFrozenLatticePar->Show(mFreezeLatticePar);
3806  if(mFreezeLatticePar)
3807  {
3808  for(unsigned int i=0;i<3;++i) mpGridFrozenLatticePar->SetCellValue(0, i, wxString::Format("%.4f",mFrozenLatticePar(i)));
3809  for(unsigned int i=3;i<6;++i) mpGridFrozenLatticePar->SetCellValue(0, i, wxString::Format("%.3f",mFrozenLatticePar(i)*180/M_PI));
3810  }
3811  mpFreezeLatticePar->SetValue(mFreezeLatticePar);
3812  if(mNeedLayout)
3813  {
3814  VFN_DEBUG_MESSAGE("WXPowderPatternDiffraction::UpdateUI():Layout !", 10)
3815  this->Layout();
3816  mNeedLayout=false;
3817  }
3818  if(lock) mMutex.Unlock();
3819  this->WXRefinableObj::UpdateUI(lock);
3820 }
3821 bool WXPowderPatternDiffraction::Enable(bool e)
3822 {
3823  if(0!=mpGridFrozenLatticePar) mpGridFrozenLatticePar->Enable(e);
3824  return this->::wxWindow::Enable(e);
3825 }
3826 
3827 void WXPowderPatternDiffraction::OnChangeProfile(wxCommandEvent & event)
3828 {
3829  VFN_DEBUG_ENTRY("WXPowderPatternDiffraction::OnChangeProfile()",6)
3830  bool add=false;
3831  if(event.GetId()==ID_POWDERDIFF_PROFILE_PV)
3832  {
3833  if(mpPowderPatternDiffraction->mpReflectionProfile==0)
3834  {
3835  ReflectionProfilePseudoVoigt *p= new ReflectionProfilePseudoVoigt;
3836  mpPowderPatternDiffraction->SetProfile(p);
3837  add=true;
3838  }
3839  else
3840  if(mpPowderPatternDiffraction->mpReflectionProfile->GetClassName()
3841  !="ReflectionProfilePseudoVoigt")
3842  {
3843  ReflectionProfilePseudoVoigt *p= new ReflectionProfilePseudoVoigt;
3844  if(mpPowderPatternDiffraction->mpReflectionProfile->GetClassName()=="ReflectionProfilePseudoVoigtAnisotropic")
3845  {
3846  p->GetPar("U").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("U").GetValue());
3847  p->GetPar("V").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("V").GetValue());
3848  p->GetPar("W").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("W").GetValue());
3849  p->GetPar("Eta0").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("Eta0").GetValue());
3850  p->GetPar("Eta1").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("Eta1").GetValue());
3851  p->GetPar("Asym0").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("Asym0").GetValue());
3852  p->GetPar("Asym1").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("Asym1").GetValue());
3853  p->GetPar("Asym2").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("Asym2").GetValue());
3854  }
3855  mpPowderPatternDiffraction->SetProfile(p);
3856  add=true;
3857  }
3858  }
3859  if(event.GetId()==ID_POWDERDIFF_PROFILE_PV_ANISO)
3860  {
3861  if(mpPowderPatternDiffraction->mpReflectionProfile==0)
3862  {
3863  ReflectionProfilePseudoVoigtAnisotropic *p= new ReflectionProfilePseudoVoigtAnisotropic;
3864  mpPowderPatternDiffraction->SetProfile(p);
3865  add=true;
3866  }
3867  else
3868  if(mpPowderPatternDiffraction->mpReflectionProfile->GetClassName()
3869  !="ReflectionProfilePseudoVoigtAnisotropic")
3870  {
3871  ReflectionProfilePseudoVoigtAnisotropic *p= new ReflectionProfilePseudoVoigtAnisotropic;
3872  if(mpPowderPatternDiffraction->mpReflectionProfile->GetClassName()=="ReflectionProfilePseudoVoigt")
3873  {
3874  p->GetPar("U").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("U").GetValue());
3875  p->GetPar("V").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("V").GetValue());
3876  p->GetPar("W").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("W").GetValue());
3877  p->GetPar("Eta0").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("Eta0").GetValue());
3878  p->GetPar("Eta1").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("Eta1").GetValue());
3879  p->GetPar("Asym0").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("Asym0").GetValue());
3880  p->GetPar("Asym1").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("Asym1").GetValue());
3881  p->GetPar("Asym2").SetValue(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("Asym2").GetValue());
3882  p->GetPar("X").SetValue(sqrt(mpPowderPatternDiffraction->mpReflectionProfile->GetPar("W").GetValue()));
3883  }
3884  mpPowderPatternDiffraction->SetProfile(p);
3885  add=true;
3886  }
3887  }
3888  if(event.GetId()==ID_POWDERDIFF_PROFILE_DEPV)
3889  {
3890  if(mpPowderPatternDiffraction->mpReflectionProfile==0)
3891  {
3892  ReflectionProfileDoubleExponentialPseudoVoigt *p=
3893  new ReflectionProfileDoubleExponentialPseudoVoigt
3894  (mpPowderPatternDiffraction->GetCrystal());
3895  mpPowderPatternDiffraction->SetProfile(p);
3896  add=true;
3897  }
3898  else
3899  if(mpPowderPatternDiffraction->mpReflectionProfile->GetClassName()
3900  !="ReflectionProfileDoubleExponentialPseudoVoigt")
3901  {
3902  ReflectionProfileDoubleExponentialPseudoVoigt *p=
3903  new ReflectionProfileDoubleExponentialPseudoVoigt
3904  (mpPowderPatternDiffraction->GetCrystal());
3905  mpPowderPatternDiffraction->SetProfile(p);
3906  add=true;
3907  }
3908  }
3909  if(add)
3910  {
3911  mpPowderPatternDiffraction->mpReflectionProfile->WXCreate(this);
3912  mList.Add(mpPowderPatternDiffraction->mpReflectionProfile->WXGet());
3913  mpSizer->Add(mpPowderPatternDiffraction->mpReflectionProfile->WXGet());
3914  wxTheApp->GetTopWindow()->Layout();
3915  wxTheApp->GetTopWindow()->SendSizeEvent();
3916  mpPowderPatternDiffraction->GetParentPowderPattern().UpdateDisplay();
3917  }
3918  VFN_DEBUG_EXIT("WXPowderPatternDiffraction::OnChangeProfile()",6)
3919 }
3920 
3922 static const long ID_PROFILEFITTING_RUN= WXCRYST_ID();
3923 static const long ID_PROFILEFITTING_RUN_MANUAL= WXCRYST_ID();
3924 static const long ID_PROFILEFITTING_EXPLORE_SPG= WXCRYST_ID();
3925 static const long ID_PROFILEFITTING_EXPLORE_SPG_QUICK= WXCRYST_ID();
3926 
3927 BEGIN_EVENT_TABLE(WXProfileFitting, wxWindow)
3928  EVT_BUTTON(ID_PROFILEFITTING_RUN, WXProfileFitting::OnFit)
3929  EVT_BUTTON(ID_PROFILEFITTING_RUN_MANUAL, WXProfileFitting::OnFit)
3930  EVT_BUTTON(ID_PROFILEFITTING_EXPLORE_SPG, WXProfileFitting::OnExploreSpacegroups)
3931  EVT_BUTTON(ID_PROFILEFITTING_EXPLORE_SPG_QUICK, WXProfileFitting::OnExploreSpacegroups)
3932 END_EVENT_TABLE()
3933 
3934 WXProfileFitting::WXProfileFitting(wxWindow *parent,PowderPattern *pPattern,PowderPatternDiffraction *pDiff):
3935 wxWindow(parent,-1),mpPattern(pPattern),mpDiff(pDiff),mLSQ("Profile Fitting object"),mpList(0)
3936 {
3937  wxBoxSizer *pSizer0=new wxBoxSizer(wxVERTICAL);
3938  this->SetSizer(pSizer0);
3939 
3940  wxNotebook *pNotebook = new wxNotebook(this, -1,wxDefaultPosition,wxSize(600,400));
3941  pSizer0->Add(pNotebook,0,wxALIGN_CENTER);
3942  // Quick interface
3943  wxWindow *pQuick=new wxWindow(pNotebook,-1);
3944  pNotebook->AddPage(pQuick,_T("Quick Fit"),true);
3945  wxBoxSizer *pSizer=new wxBoxSizer(wxVERTICAL);
3946 
3947  wxButton *pButton1=new wxButton(pQuick,ID_PROFILEFITTING_RUN,_T("Le Bail + Fit Profile !"));
3948  pSizer->Add(pButton1,0,wxALIGN_CENTER);
3949  if(mpDiff==0)
3950  {
3951  // List crystal phases
3952  wxArrayString choices;
3953  {
3954  unsigned int nb=mpPattern->GetNbPowderPatternComponent();
3955  for(unsigned int i=0;i<nb;++i)
3956  if(mpPattern->GetPowderPatternComponent(i).GetClassName()==string("PowderPatternDiffraction"))
3957  {
3958  pDiff=dynamic_cast<PowderPatternDiffraction*>(&(mpPattern->GetPowderPatternComponent(i)));
3959  if(pDiff!=0)
3960  {
3961  cout<<"WXProfileFitting::WXProfileFitting():"<<pDiff<<":"<<mpPattern->GetPowderPatternComponent(i).GetName()
3962  <<","<<pDiff->GetCrystal().GetName()<<endl;
3963  choices.Add(wxString::FromAscii(pDiff->GetCrystal().GetName().c_str())
3964  +wxString::Format(_T(", a=%6.3f b=%6.3f c=%6.3f"),
3965  pDiff->GetCrystal().GetLatticePar(0),
3966  pDiff->GetCrystal().GetLatticePar(1),
3967  pDiff->GetCrystal().GetLatticePar(2)));
3968  //cout<<"WXProfileFitting::WXProfileFitting():"<<choices[choices.Count()-1]<<","<<pDiff<<endl;
3969  }
3970  }
3971  }
3972  if(choices.GetCount()==0)
3973  {
3974  wxMessageBox(_T("To run Le Bail & Profile fitting, you \n")
3975  _T("need at least one crystalline phase !"),
3976  _T("Missing crystalline phase !"),
3977  wxYES_NO|wxICON_ERROR);
3978  this->GetParent()->Destroy();
3979  return;
3980  }
3981  if(choices.GetCount()==1)
3982  {
3983  cout<<"WXProfileFitting::WXProfileFitting():"<<choices[0]<<","<<pDiff<<endl;
3984  mpDiff=pDiff;
3985  }
3986  else
3987  {
3988  wxStaticText *pLabel=new wxStaticText(pQuick,-1,_T("Crystalline Phase to Fit:"));
3989  pSizer->Add(pLabel,0,wxALIGN_CENTER);
3990 
3991  mpList=new wxListBox(pQuick,-1,wxDefaultPosition,wxSize(-1,80),choices,wxLB_SINGLE);
3992  mpList->SetSelection(0);
3993  pSizer->Add(mpList,0,wxALIGN_CENTER);
3994  }
3995  }
3996 
3997  if(mpList!=0)
3998  {
3999  wxArrayInt selections;
4000  mpList->GetSelections(selections);
4001  const int choice=selections[0];
4002  int ct=0;
4003  unsigned int nb=mpPattern->GetNbPowderPatternComponent();
4004  for(unsigned int i=0;i<nb;++i)
4005  if(mpPattern->GetPowderPatternComponent(i).GetClassName()==string("PowderPatternDiffraction"))
4006  {
4007  pDiff=dynamic_cast<PowderPatternDiffraction*>(&(mpPattern->GetPowderPatternComponent(i)));
4008  cout<<"WXProfileFitting::WXProfileFitting():"<<pDiff<<":"<<mpPattern->GetPowderPatternComponent(i).GetName()<<endl;
4009  if(pDiff!=0)
4010  {
4011  if(ct==choice)
4012  {
4013  mpDiff=pDiff;
4014  cout<<"Chosen:"<<mpPattern->GetPowderPatternComponent(i).GetName()<<endl;
4015  break;
4016  }
4017  cout<<"Not chosen:"<<mpPattern->GetPowderPatternComponent(i).GetName()<<endl;
4018  }
4019  }
4020  }
4021  wxArrayString fitChoices;
4022  if(mpDiff->GetProfile().GetClassName()=="ReflectionProfileDoubleExponentialPseudoVoigt")
4023  {
4024  fitChoices.Add(_T("Fit Zero shift"));
4025  fitChoices.Add(_T("Fit Instrumental Width (alpha1,beta0,beta1)"));
4026  fitChoices.Add(_T("Fit Size/Strain Broadening (sigma1,gamma2)"));
4027  fitChoices.Add(_T("Fit Background"));
4028  fitChoices.Add(_T("Fit Unit Cell"));
4029  }
4030  else
4031  {
4032  fitChoices.Add(_T("Fit Zero shift"));
4033  fitChoices.Add(_T("Fit Constant Width"));
4034  fitChoices.Add(_T("Fit Variable Width"));
4035  fitChoices.Add(_T("Fit Gaussian-Lorentzian Mixing"));
4036  fitChoices.Add(_T("Fit Asymmetric parameters"));
4037  fitChoices.Add(_T("Fit Displacement+Transparency"));
4038  fitChoices.Add(_T("Fit Background"));
4039  fitChoices.Add(_T("Fit Unit Cell"));
4040  }
4041  mpFitCheckList=new wxCheckListBox(pQuick,-1,wxDefaultPosition,wxDefaultSize,fitChoices);
4042  if(mpDiff->GetProfile().GetClassName()=="ReflectionProfileDoubleExponentialPseudoVoigt")
4043  {
4044  mpFitCheckList->Check(0,false);
4045  mpFitCheckList->Check(1,false);
4046  mpFitCheckList->Check(2,true);
4047  mpFitCheckList->Check(3,true);
4048  mpFitCheckList->Check(4,true);
4049  }
4050  else
4051  {
4052  mpFitCheckList->Check(0,true);
4053  mpFitCheckList->Check(1,true);
4054  mpFitCheckList->Check(2,true);
4055  mpFitCheckList->Check(3,true);
4056  mpFitCheckList->Check(4,true);
4057  mpFitCheckList->Check(5,true);
4058  mpFitCheckList->Check(6,true);
4059  mpFitCheckList->Check(7,true);
4060  }
4061  pSizer->Add(mpFitCheckList,1,wxEXPAND|wxALIGN_CENTER);
4062 
4063  pQuick->SetSizer(pSizer);
4064  pSizer->SetSizeHints(pQuick);
4065  pQuick->Layout();
4066 
4067  // Manual interface
4068  // prepare LSQ object
4069  mLSQ.SetRefinedObj(pDiff->GetParentPowderPattern(),0,true,true);
4070  mLSQ.PrepareRefParList(true);
4071  //mLSQ.SetParIsUsed(gpRefParTypeObjCryst,false);
4072  //mLSQ.SetParIsUsed(gpRefParTypeScattDataScale,true);
4073  //mLSQ.SetParIsUsed(gpRefParTypeScattDataProfile,true);
4074  //mLSQ.SetParIsUsed(gpRefParTypeScattDataCorrPos,true);
4075  //mLSQ.SetParIsUsed(gpRefParTypeScattDataBackground,true);
4076  //mLSQ.SetParIsUsed(gpRefParTypeUnitCell,true);
4077  mLSQ.SetParIsUsed(gpRefParTypeScatt,false);
4078  mLSQ.SetParIsUsed(gpRefParTypeScattPow,false);
4079  //mLSQ.SetParIsFixed(gpRefParTypeObjCryst,true);
4080  //mLSQ.SetParIsFixed(gpRefParTypeScattDataScale,false);
4081  // wxLSQ object
4082  wxScrolledWindow *pManual=new wxScrolledWindow(pNotebook,-1,wxDefaultPosition,
4083  wxSize(400,250),wxHSCROLL | wxVSCROLL);
4084  wxBoxSizer *pSizerManual=new wxBoxSizer(wxVERTICAL);
4085 
4086  wxButton *pButton2=new wxButton(pManual,ID_PROFILEFITTING_RUN_MANUAL,_T("Le Bail + Fit Profile !"));
4087  pSizerManual->Add(pButton2,0,wxALIGN_CENTER);
4088  //pManual->SetSize(pQuick->GetSize());
4089  pSizerManual->Add(mLSQ.WXCreate(pManual),0,wxALIGN_CENTER);
4090  mLSQ.WXGet()->CrystUpdate(true,true);
4091  pManual->SetScrollRate(10,10);
4092  pManual->SetSizer(pSizerManual);
4093  pManual->Layout();
4094  pSizerManual->FitInside(pManual);
4095 
4096  pNotebook->AddPage(pManual,_T("Manual Fit"),true);
4097 
4098  // Spacegroup exploration
4099  wxScrolledWindow *pSpgExplor=new wxScrolledWindow(pNotebook,-1,wxDefaultPosition,
4100  wxSize(600,250),wxHSCROLL | wxVSCROLL);
4101  wxBoxSizer *pSizerSpgExplor=new wxBoxSizer(wxVERTICAL);
4102 
4103  wxButton *pButton3=new wxButton(pSpgExplor,ID_PROFILEFITTING_EXPLORE_SPG,_T("Try all possible spacegroups - Le Bail + Least Squares (SLOW)"));
4104  pSizerSpgExplor->Add(pButton3,0,wxALIGN_CENTER);
4105  wxButton *pButton4=new wxButton(pSpgExplor,ID_PROFILEFITTING_EXPLORE_SPG_QUICK,_T("Try all possible spacegroups - Le Bail only"));
4106  pSizerSpgExplor->Add(pButton4,0,wxALIGN_CENTER);
4107 
4108  pSpgExplor->SetSizer(pSizerSpgExplor);
4109  pSpgExplor->Layout();
4110  pSizerSpgExplor->FitInside(pSpgExplor);
4111 
4112  pNotebook->AddPage(pSpgExplor,_T("Spacegroup Explorer"),true);
4113 
4114  pNotebook->ChangeSelection(0);
4115  mpLog =new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(600,300),wxTE_MULTILINE|wxTE_READONLY|wxTE_DONTWRAP);
4116  mpLog->SetFont(wxFont(9,wxTELETYPE,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL));
4117  pSizer0->Add(mpLog,0,wxALIGN_CENTER|wxEXPAND);
4118 
4119 
4120  //pSizer0->Layout();
4121  pSizer0->SetSizeHints(this);
4122  //pSizer0->Fit(this);
4123  pSizer0->Fit(this->GetParent());
4124  this->Layout();
4125 }
4126 
4127 WXProfileFitting::~WXProfileFitting()
4128 {
4129  if(mpDiff!=0) mpDiff->SetExtractionMode(false);
4130  else
4131  {
4132  unsigned int nb=mpPattern->GetNbPowderPatternComponent();
4133  for(unsigned int i=0;i<nb;++i)
4134  if(mpPattern->GetPowderPatternComponent(i).GetClassName()==string("PowderPatternDiffraction"))
4135  {
4136  PowderPatternDiffraction *pDiff=dynamic_cast<PowderPatternDiffraction*>(&(mpPattern->GetPowderPatternComponent(i)));
4137  if(pDiff!=0) pDiff->SetExtractionMode(false);
4138  }
4139  }
4140  mpPattern->UpdateDisplay();
4141 }
4142 
4143 void WXProfileFitting::OnFit(wxCommandEvent &event)
4144 {
4145  // Map of crystalline phases to be fitted (or not)
4146  map<PowderPatternDiffraction *,bool> vpDiff;
4147  // Multiple phases can be fitted - which one was chosen ?
4148  if(mpList!=0)
4149  {
4150  wxArrayInt selections;
4151  mpList->GetSelections(selections);
4152  const int choice=selections[0];
4153  int ct=0;
4154  unsigned int nb=mpPattern->GetNbPowderPatternComponent();
4155  for(unsigned int i=0;i<nb;++i)
4156  if(mpPattern->GetPowderPatternComponent(i).GetClassName()==string("PowderPatternDiffraction"))
4157  {
4158  PowderPatternDiffraction *pDiff=dynamic_cast<PowderPatternDiffraction*>(&(mpPattern->GetPowderPatternComponent(i)));
4159  cout<<"WXProfileFitting::WXProfileFitting():"<<pDiff<<":"<<mpPattern->GetPowderPatternComponent(i).GetName()<<endl;
4160  if(pDiff!=0)
4161  {
4162  if(ct++==choice) vpDiff[pDiff]=true;
4163  else vpDiff[pDiff]=false;
4164  }
4165  }
4166  }
4167  else
4168  {// A single phase may have been pre-selected, but others may be present
4169  unsigned int nb=mpPattern->GetNbPowderPatternComponent();
4170  for(unsigned int i=0;i<nb;++i)
4171  if(mpPattern->GetPowderPatternComponent(i).GetClassName()==string("PowderPatternDiffraction"))
4172  {
4173  PowderPatternDiffraction *pDiff=dynamic_cast<PowderPatternDiffraction*>(&(mpPattern->GetPowderPatternComponent(i)));
4174  cout<<"WXProfileFitting::WXProfileFitting():"<<pDiff<<":"<<mpPattern->GetPowderPatternComponent(i).GetName()<<endl;
4175  if(pDiff!=0)
4176  {
4177  if(pDiff==mpDiff) vpDiff[pDiff]=true;
4178  else vpDiff[pDiff]=false;
4179  }
4180  }
4181  }
4182  #if 0
4183  if(mpDiff!=0) pDiff=mpDiff;
4184  else
4185  {
4186  unsigned int nb=mpPattern->GetNbPowderPatternComponent();
4187  unsigned int n=0;
4188  const unsigned int n0=mpList->GetSelection();
4189  for(unsigned int i=0;i<nb;++i)
4190  {
4191  if(mpPattern->GetPowderPatternComponent(i).GetClassName()==string("PowderPatternDiffraction"))
4192  {
4193  pDiff=dynamic_cast<PowderPatternDiffraction*>(&(mpPattern->GetPowderPatternComponent(i)));
4194  if(pDiff!=0)
4195  {
4196  if(n++==n0) break;
4197  }
4198  }
4199  }
4200  }
4201  #endif
4202  cout<<"Selected PowderPatternDiffraction:"<<mpDiff->GetName()<<","<<mpDiff->GetCrystal().GetName()<<endl;
4203 
4204  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4205  if(pos->second) pos->first->SetExtractionMode(true,true);
4206 
4207  mpLog->AppendText(wxString::Format(_T("Starting 20 Le Bail cycles\n")));
4208  wxProgressDialog dlgProgress(_T("Le Bail and Profile Fitting"),_T("Le Bail Fitting, cycle #0/20"),
4209  18,this,wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME|wxPD_CAN_ABORT);
4210  for(int i=0;i<10;++i)
4211  {
4212  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4213  if(pos->second)
4214  {// Only one should be in LeBail mode, but this code is general
4215  pos->first->ExtractLeBail(2);
4216  pos->first->GetParentPowderPattern().FitScaleFactorForRw();
4217  pos->first->GetParentPowderPattern().UpdateDisplay();
4218  }
4219  if(dlgProgress.Update(i,wxString::Format(_T("Le Bail Fitting, cycle #%d/20"),i*2))==false) return;
4220  }
4221  mpLog->AppendText(wxString::Format(_T(" => Rwp=%5.3f%%, GoF=%7.3f\n"),
4222  mpDiff->GetParentPowderPattern().GetRw()*100,
4223  mpDiff->GetParentPowderPattern().GetChi2()
4224  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4225 
4226  if(event.GetId()==ID_PROFILEFITTING_RUN)
4227  {
4228  bool fitzero=false,fitwidth0=false,fitwidth=false,fiteta=false,
4229  fitasym=false,fitdispltransp=false,fitbackgd=false,fitcell=false,
4230  fitanisotropic=false,
4231  fitTOFInstWidth=false,fitTOFBroadening=false;
4232 
4233  if(mpDiff->GetProfile().GetClassName()=="ReflectionProfileDoubleExponentialPseudoVoigt")
4234  {
4235  mpDiff->GetProfile().Print();
4236  fitzero=mpFitCheckList->IsChecked(0);
4237  fitTOFInstWidth=mpFitCheckList->IsChecked(1);
4238  fitTOFBroadening=mpFitCheckList->IsChecked(2);
4239  fitbackgd=mpFitCheckList->IsChecked(3);
4240  fitcell=mpFitCheckList->IsChecked(4);
4241  }
4242  else
4243  {
4244  fitzero=mpFitCheckList->IsChecked(0);
4245  fitwidth0=mpFitCheckList->IsChecked(1);
4246  fitwidth=mpFitCheckList->IsChecked(2);
4247  fiteta=mpFitCheckList->IsChecked(3);
4248  fitasym=mpFitCheckList->IsChecked(4);
4249  fitdispltransp=mpFitCheckList->IsChecked(5);
4250  fitbackgd=mpFitCheckList->IsChecked(6);
4251  fitcell=mpFitCheckList->IsChecked(7);
4252  }
4253  try{
4254  mLSQ.SetParIsFixed(gpRefParTypeScattDataScale,false);
4255 
4256  if(fitzero) mLSQ.SetParIsFixed(mpDiff->GetParentPowderPattern().GetPar("Zero"),false);
4257  if(fitwidth0)
4258  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4259  if(pos->second) mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("W"),false);
4260  if(fitwidth0)
4261  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4262  if((pos->second) && (pos->first->GetProfile().GetClassName()=="ReflectionProfilePseudoVoigtAnisotropic"))
4263  mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("X"),false);
4264  if(fitzero||fitwidth0)
4265  {
4266  mpLog->AppendText(wxString::Format(_T("Fitting zero shift && constant width\n")));
4267  if(dlgProgress.Update(11,_T("Fitting zero shift && constant width"))==false) return;
4268  mLSQ.Refine(5,true,false);
4269  mpDiff->ExtractLeBail(2);
4270  mpDiff->GetParentPowderPattern().UpdateDisplay();
4271  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4272  mpDiff->GetParentPowderPattern().GetRw()*100,
4273  mpDiff->GetParentPowderPattern().GetChi2()
4274  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4275  }
4276  if(fitwidth)
4277  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4278  if(pos->second) mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("U"),false);
4279  if(fitwidth)
4280  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4281  if(pos->second) mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("V"),false);
4282  if(fitwidth)
4283  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4284  if((pos->second) && (pos->first->GetProfile().GetClassName()=="ReflectionProfilePseudoVoigtAnisotropic"))
4285  mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("Y"),false);
4286  if(fitwidth)
4287  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4288  if((pos->second) && (pos->first->GetProfile().GetClassName()=="ReflectionProfilePseudoVoigtAnisotropic"))
4289  mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("P"),false);
4290  if(fiteta)
4291  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4292  if(pos->second) mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("Eta0"),false);
4293  if(fitwidth||fiteta)
4294  {
4295  mpLog->AppendText(wxString::Format(_T("Fitting width and gaussian/lorentzian fixed mix\n")));
4296  if(dlgProgress.Update(12,_T("Fitting variable width and gaussian/lorentzian fixed mix"))==false) return;
4297  mLSQ.Refine(5,true,false);
4298  mpDiff->ExtractLeBail(2);
4299  mpDiff->GetParentPowderPattern().UpdateDisplay();
4300  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4301  mpDiff->GetParentPowderPattern().GetRw()*100,
4302  mpDiff->GetParentPowderPattern().GetChi2()
4303  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4304  }
4305 
4306  if(fitTOFInstWidth)
4307  {// TOF
4308  mpDiff->GetProfile().Print();
4309  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4310  if(pos->second)
4311  {
4312  mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("Alpha1"),false);
4313  mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("Beta0"),false);
4314  mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("Beta1"),false);
4315  }
4316  mpLog->AppendText(wxString::Format(_T("Fitting TOF instrumental width (alpha1,beta0,beta1)\n")));
4317  if(dlgProgress.Update(12,_T("Fitting TOF instrumental width (alpha1,beta0,beta1)"))==false) return;
4318  mLSQ.Refine(5,true,false);
4319  mpDiff->ExtractLeBail(2);
4320  mpDiff->GetParentPowderPattern().UpdateDisplay();
4321  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4322  mpDiff->GetParentPowderPattern().GetRw()*100,
4323  mpDiff->GetParentPowderPattern().GetChi2()
4324  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4325  }
4326  if(fitTOFBroadening)
4327  {// TOF
4328  mpDiff->GetProfile().Print();
4329  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4330  if(pos->second)
4331  {
4332  mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("GaussianSigma1"),false);
4333  //mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("LorentzianGamma2"),false);
4334  //mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("GaussianSigma1"),0,1e6);
4335  //mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("LorentzianGamma2"),0,1e6);
4336  }
4337  mpLog->AppendText(wxString::Format(_T("Fitting size/strain broadening parameters (sigma1,gamma2)\n")));
4338  if(dlgProgress.Update(12,_T("Fitting size/strain broadening parameters (sigma1,gamma2)"))==false) return;
4339  mLSQ.Refine(5,true,false);
4340  mpDiff->ExtractLeBail(2);
4341  mpDiff->GetParentPowderPattern().UpdateDisplay();
4342  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4343  mpDiff->GetParentPowderPattern().GetRw()*100,
4344  mpDiff->GetParentPowderPattern().GetChi2()
4345  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4346  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4347  if(pos->second)
4348  mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("GaussianSigma1"),true);
4349  }
4350 
4351  if(fiteta) mLSQ.SetParIsFixed(mpDiff->GetProfile().GetPar("Eta1"),false);
4352  if(fiteta)
4353  {
4354  mpLog->AppendText(wxString::Format(_T("Fitting gaussian/lorentzian mix\n")));
4355  if(dlgProgress.Update(13,_T("Fitting variable width and gaussian/lorentzian mix"))==false) return;
4356  mLSQ.Refine(5,true,false);
4357  mpDiff->ExtractLeBail(2);
4358  mpDiff->GetParentPowderPattern().UpdateDisplay();
4359  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4360  mpDiff->GetParentPowderPattern().GetRw()*100,
4361  mpDiff->GetParentPowderPattern().GetChi2()
4362  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4363  }
4364 
4365  if(fitasym)
4366  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4367  if(pos->second) mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("Asym0"),false);
4368  if(fitasym)
4369  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4370  if(pos->second) mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("Asym1"),false);
4371  if(fitasym)
4372  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4373  if(pos->second) mLSQ.SetParIsFixed(pos->first->GetProfile().GetPar("Asym2"),false);
4374  if(fitdispltransp)
4375  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4376  if(pos->second) mLSQ.SetParIsFixed(pos->first->GetParentPowderPattern().GetPar("2ThetaDispl"),false);
4377  if(fitdispltransp)
4378  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4379  if(pos->second) mLSQ.SetParIsFixed(pos->first->GetParentPowderPattern().GetPar("2ThetaTransp"),false);
4380  if(fitdispltransp||fitasym)
4381  {
4382  mpLog->AppendText(wxString::Format(_T("Fitting assymetry and sample displacement/transparency\n")));
4383  if(dlgProgress.Update(14,_T("Fitting assymetry and sample displacement/transparency"))==false) return;
4384  mLSQ.Refine(5,true,false);
4385  mpDiff->ExtractLeBail(2);
4386  mpDiff->GetParentPowderPattern().UpdateDisplay();
4387  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4388  mpDiff->GetParentPowderPattern().GetRw()*100,
4389  mpDiff->GetParentPowderPattern().GetChi2()
4390  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4391  }
4392 
4393  if(fitbackgd)
4394  {
4395  mLSQ.SetParIsFixed(gpRefParTypeScattDataBackground,false);
4396  // Make sure points beyond max resolution are not optimized
4397  const unsigned int nbcomp= mpDiff->GetParentPowderPattern().GetNbPowderPatternComponent();
4398  for(unsigned int i=0;i<nbcomp;++i)
4399  if(mpDiff->GetParentPowderPattern().GetPowderPatternComponent(i).GetClassName()=="PowderPatternBackground")
4400  {
4401  PowderPatternBackground *pback=dynamic_cast<PowderPatternBackground *>
4402  (&(mpDiff->GetParentPowderPattern().GetPowderPatternComponent(i)));
4403  pback->FixParametersBeyondMaxresolution(mLSQ.GetCompiledRefinedObj());
4404  }
4405 
4406  mpLog->AppendText(wxString::Format(_T("Fitting background\n")));
4407  if(dlgProgress.Update(15,_T("Fitting background"))==false) return;
4408  mLSQ.Refine(5,true,false);
4409  mpDiff->ExtractLeBail(2);
4410  mpDiff->GetParentPowderPattern().UpdateDisplay();
4411  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4412  mpDiff->GetParentPowderPattern().GetRw()*100,
4413  mpDiff->GetParentPowderPattern().GetChi2()
4414  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4415  }
4416 
4417  if(fitcell)
4418  {
4419  mLSQ.SetParIsFixed(gpRefParTypeUnitCell,false);
4420 
4421  // Fix uc parameters of unrefined phases
4422  for(map<PowderPatternDiffraction *,bool>::iterator pos=vpDiff.begin();pos!=vpDiff.end();++pos)
4423  if(!(pos->second)) mLSQ.SetParIsFixed(pos->first->GetCrystal(),true);
4424 
4425  mpLog->AppendText(wxString::Format(_T("Fitting unit cell\n")));
4426  if(dlgProgress.Update(16,_T("Fitting unit cell"))==false) return;
4427  mLSQ.Refine(5,true,false);
4428  mpDiff->ExtractLeBail(2);
4429  mpDiff->GetParentPowderPattern().UpdateDisplay();
4430  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4431  mpDiff->GetParentPowderPattern().GetRw()*100,
4432  mpDiff->GetParentPowderPattern().GetChi2()
4433  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4434  }
4435  }
4436  catch(const ObjCrystException &except)
4437  {
4438  mpLog->AppendText(wxString::Format(_T(" OOPS : refinement diverged ! Aborting.\n")));
4439  }
4440  }
4441  else
4442  {// Manual fit
4443  try
4444  {
4445  mpLog->AppendText(wxString::Format(_T("Profile fitting (manual):\n")));
4446  mpLog->AppendText(wxString::Format(_T(" Initial values: Rwp=%6.3f%%, GoF=%7.3f\n"),
4447  mpDiff->GetParentPowderPattern().GetRw()*100,
4448  mpDiff->GetParentPowderPattern().GetChi2()
4449  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4450  mpLog->AppendText(wxString::Format(_T("3 LSQ cycles...\n")));
4451  mLSQ.Refine(3,true,false);
4452  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4453  mpDiff->GetParentPowderPattern().GetRw()*100,
4454  mpDiff->GetParentPowderPattern().GetChi2()
4455  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4456  mpLog->AppendText(wxString::Format(_T("2 Le Bail cycles...\n")));
4457  if(dlgProgress.Update(9,_T("Manual Le Bail + Profile fitting"))==false) return;
4458  mpDiff->ExtractLeBail(2);
4459  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4460  mpDiff->GetParentPowderPattern().GetRw()*100,
4461  mpDiff->GetParentPowderPattern().GetChi2()
4462  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4463  mpLog->AppendText(wxString::Format(_T("3 LSQ cycles...\n")));
4464  if(dlgProgress.Update(13,_T("Manual Le Bail + Profile fitting"))==false) return;
4465  mLSQ.Refine(3,true,false);
4466  if(dlgProgress.Update(17,_T("Manual Le Bail + Profile fitting"))==false) return;
4467  mpDiff->GetParentPowderPattern().UpdateDisplay();
4468  mpLog->AppendText(wxString::Format(_T(" => Rwp=%6.3f%%, GoF=%7.3f\n"),
4469  mpDiff->GetParentPowderPattern().GetRw()*100,
4470  mpDiff->GetParentPowderPattern().GetChi2()
4471  /mpDiff->GetParentPowderPattern().GetNbPointUsed()));
4472  }
4473  catch(const ObjCrystException &except)
4474  {
4475  mpLog->AppendText(wxString::Format(_T(" OOPS : refinement diverged ! Aborting.\n")));
4476  }
4477  }
4478  mLSQ.WXGet()->CrystUpdate(true,true);
4479  mpDiff->GetCrystal().UpdateDisplay();
4480 }
4481 
4482 struct SPGScore
4483 {
4484  SPGScore(const string &s, const REAL r, const REAL g, const unsigned int nbextinct):
4485  hm(s),rw(r),gof(g),nbextinct446(nbextinct)
4486  {};
4487  string hm;
4488  REAL rw,gof;
4489  unsigned int nbextinct446;
4490 };
4491 
4492 bool compareSPGScore(const SPGScore &s1, const SPGScore &s2)
4493 {
4494  return s1.gof < s2.gof;
4495 }
4496 
4497 std::vector<bool> spgExtinctionFingerprint(Crystal &c,cctbx::sgtbx::space_group &spg)
4498 {
4499  // We don't have the extinction symbol, so do it the stupid way
4500  std::vector<bool> fingerprint(5*5*7-1+6);
4501  long i=0;
4502  fingerprint[i++]=c.GetPar("a").IsUsed();
4503  fingerprint[i++]=c.GetPar("b").IsUsed();
4504  fingerprint[i++]=c.GetPar("c").IsUsed();
4505  fingerprint[i++]=c.GetPar("alpha").IsUsed();
4506  fingerprint[i++]=c.GetPar("beta").IsUsed();
4507  fingerprint[i++]=c.GetPar("gamma").IsUsed();
4508  for(long h=0;h<5;++h)
4509  for(long k=0;k<5;++k)
4510  for (long l=0;l<7;++l)
4511  {
4512  if((h+k+l)==0) continue;
4513  cctbx::miller::index<long> hkl(scitbx::vec3<long>(h,k,l));
4514  if(i>=fingerprint.size()) cout<<"WHOOOOOOOOOOOOOPS"<<endl;
4515  fingerprint[i++] =spg.is_sys_absent(hkl);
4516  }
4517  return fingerprint;
4518 }
4519 
4520 void WXProfileFitting::OnExploreSpacegroups(wxCommandEvent &event)
4521 {
4522  TAU_PROFILE("WXProfileFitting::OnExploreSpacegroups()","void (wxCommandEvent &)",TAU_DEFAULT);
4523  TAU_PROFILE_TIMER(timer1,"WXProfileFitting::OnExploreSpacegroups()LSQ-P1","", TAU_FIELD);
4524  TAU_PROFILE_TIMER(timer2,"WXProfileFitting::OnExploreSpacegroups()LSQ1","", TAU_FIELD);
4525  TAU_PROFILE_TIMER(timer3,"WXProfileFitting::OnExploreSpacegroups()LSQ2","", TAU_FIELD);
4526  PowderPatternDiffraction *pDiff=0;
4527  if(mpDiff!=0) pDiff=mpDiff;
4528  else
4529  {
4530  unsigned int nb=mpPattern->GetNbPowderPatternComponent();
4531  unsigned int n=0;
4532  const unsigned int n0=mpList->GetSelection();
4533  for(unsigned int i=0;i<nb;++i)
4534  {
4535  if(mpPattern->GetPowderPatternComponent(i).GetClassName()==string("PowderPatternDiffraction"))
4536  {
4537  pDiff=dynamic_cast<PowderPatternDiffraction*>(&(mpPattern->GetPowderPatternComponent(i)));
4538  if(pDiff!=0)
4539  {
4540  if(n++==n0) break;
4541  }
4542  }
4543  }
4544  }
4545  cout<<"Selected PowderPatternDiffraction:"<<pDiff->GetName()<<","<<pDiff->GetCrystal().GetName()<<endl;
4546 
4547  pDiff->SetExtractionMode(true,true);
4548  Crystal *pCrystal=&(pDiff->GetCrystal());
4549 
4550  // Keep initial lattice parameters & spg
4551  const REAL a=pCrystal->GetLatticePar(0),
4552  b=pCrystal->GetLatticePar(1),
4553  c=pCrystal->GetLatticePar(2),
4554  d=pCrystal->GetLatticePar(3),
4555  e=pCrystal->GetLatticePar(4),
4556  f=pCrystal->GetLatticePar(5);
4557  const string spgname=pCrystal->GetSpaceGroup().GetName();
4558  const string name=pCrystal->GetName();
4559 
4560  const cctbx::uctbx::unit_cell uc(scitbx::af::double6(a,b,c,d*RAD2DEG,e*RAD2DEG,f*RAD2DEG));
4561 
4562  cctbx::sgtbx::space_group_symbol_iterator it=cctbx::sgtbx::space_group_symbol_iterator();
4563 
4564  // First, count compatible spacegroups
4565  unsigned int nbspg=0;
4566  //unsigned int hmlen=0;
4567  for(;;)
4568  {
4569  cctbx::sgtbx::space_group_symbols s=it.next();
4570  if(s.number()==0) break;
4571  cctbx::sgtbx::space_group spg(s);
4572  if(spg.is_compatible_unit_cell(uc,0.01,0.1)) nbspg++;
4573  //if(s.universal_hermann_mauguin().size()>hmlen) hmlen=s.universal_hermann_mauguin().size();
4574  }
4575  mpLog->AppendText(wxString::Format(_T("Beginning spacegroup exploration... %u to go...\n"),nbspg));
4576  //cout<<"Max HM symbol length:"<<hmlen<<endl;
4577  unsigned int nbcycle=1;
4578  if(event.GetId()==ID_PROFILEFITTING_EXPLORE_SPG) nbcycle=3;
4579  wxProgressDialog dlgProgress(_T("Trying compatible spacegroups"),_T("Starting........\n......\n......"),
4580  nbspg*nbcycle,this,wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME|wxPD_CAN_ABORT);
4581 
4582  list<SPGScore> vSPG;
4583  // we don't have the extinction symbols, so do it the stupid way
4584  // create a fingerprint of systematically extinct reflections
4585  // for 0<H<5 0<K<5 0<L<7
4586  std::map<std::vector<bool>,SPGScore> vSPGExtinctionFingerprint;
4587  // Try & optimize every spacegroup
4588  it=cctbx::sgtbx::space_group_symbol_iterator();
4589  Chronometer chrono;
4590  chrono.start();
4591  bool user_stop=false;
4592  for(int i=0;;)
4593  {
4594  cctbx::sgtbx::space_group_symbols s=it.next();
4595  if(s.number()==0) break;
4596  cctbx::sgtbx::space_group spg(s);
4597  bool compat=spg.is_compatible_unit_cell(uc,0.01,0.1);
4598  if(compat)
4599  {
4600  i++;
4601  const string hm=s.universal_hermann_mauguin();
4602  cout<<s.number()<<","<<hm.c_str()<<","<<(int)compat<<endl;
4603  pCrystal->Init(a,b,c,d,e,f,hm,name);
4604  mpLog->AppendText(wxString::Format(_T(" (#%3d) %-14s:"),s.number(),wxString::FromAscii(hm.c_str()).c_str()));
4605  std::vector<bool> fgp=spgExtinctionFingerprint(*pCrystal,spg);
4606  std::map<std::vector<bool>,SPGScore>::iterator posfgp=vSPGExtinctionFingerprint.find(fgp);
4607  if(posfgp!=vSPGExtinctionFingerprint.end())
4608  {
4609  vSPG.push_back(SPGScore(hm.c_str(),posfgp->second.rw,posfgp->second.gof,posfgp->second.nbextinct446));
4610  cout<<"Spacegroup:"<<hm<<" has same extinctions as:"<<posfgp->second.hm<<endl;
4611  mpLog->AppendText(_T(" same as:")+wxString::FromAscii(posfgp->second.hm.c_str())+_T("\n"));
4612  }
4613  else
4614  {
4615  pDiff->GetParentPowderPattern().UpdateDisplay();
4616  for(unsigned int j=0;j<nbcycle;j++)
4617  {
4618  // First, Le Bail
4619  pDiff->SetExtractionMode(true,true);
4620  const float t0=chrono.seconds();
4621  cout<<"Doing Le Bail, t="<<FormatFloat(t0,6,2)<<"s";
4622  pDiff->ExtractLeBail(5);
4623  cout<<", dt="<<FormatFloat(chrono.seconds()-t0,6,2)<<"s"<<endl;
4624  pDiff->GetParentPowderPattern().FitScaleFactorForRw();
4625  if(event.GetId()==ID_PROFILEFITTING_EXPLORE_SPG)
4626  {// Perform LSQ
4627  LSQNumObj lsq;
4628  TAU_PROFILE_START(timer2);
4629  lsq.SetRefinedObj(pDiff->GetParentPowderPattern(),0,true,true);
4630  lsq.PrepareRefParList(true);
4631  lsq.SetParIsFixed(gpRefParTypeObjCryst,true);
4632  lsq.SetParIsFixed(gpRefParTypeScattDataScale,false);
4633  // Only do the full monty for P1, keep the parameters for other spacegroups
4634  if(s.number()==1) lsq.SetParIsFixed("Zero",false);
4635  lsq.SetParIsFixed(gpRefParTypeUnitCell,false);
4636  lsq.Refine(2,true,true);
4637  TAU_PROFILE_STOP(timer2);
4638  if(s.number()==1)
4639  {
4640  TAU_PROFILE_START(timer1);
4641  lsq.SetParIsFixed("2ThetaDispl",false);
4642  lsq.SetParIsFixed("2ThetaTransp",false);
4643  lsq.Refine(2,true,true);
4644  lsq.SetParIsFixed(gpRefParTypeScattDataBackground,false);
4645  // Fix background point beyond optimized domain
4646  const unsigned int nbcomp= pDiff->GetParentPowderPattern().GetNbPowderPatternComponent();
4647  for(unsigned int i=0;i<nbcomp;++i)
4648  if(pDiff->GetParentPowderPattern().GetPowderPatternComponent(i).GetClassName()=="PowderPatternBackground")
4649  {
4650  PowderPatternBackground *pback=dynamic_cast<PowderPatternBackground *>
4651  (&(pDiff->GetParentPowderPattern().GetPowderPatternComponent(i)));
4652  pback->FixParametersBeyondMaxresolution(lsq.GetCompiledRefinedObj());
4653  }
4654  lsq.Refine(2,true,false);
4655  TAU_PROFILE_STOP(timer1);
4656  }
4657  // restart from equal intensities
4658  pDiff->SetExtractionMode(true,true);
4659  pDiff->ExtractLeBail(5);
4660  TAU_PROFILE_START(timer3);
4661  lsq.Refine(3,true,true);
4662  TAU_PROFILE_STOP(timer3);
4663  //mpLog->AppendText(wxString::Format(_T("%5.2f%%/"),pDiff->GetParentPowderPattern().GetRw()*100));
4664  pDiff->GetParentPowderPattern().FitScaleFactorForRw();
4665  }
4666  pDiff->GetParentPowderPattern().UpdateDisplay();
4667  const REAL rw=pDiff->GetParentPowderPattern().GetRw()*100;
4668  const REAL gof=pDiff->GetParentPowderPattern().GetChi2()
4669  /(pDiff->GetParentPowderPattern().GetNbPointUsed()-pDiff->GetNbReflBelowMaxSinThetaOvLambda());
4670  if(dlgProgress.Update(i*nbcycle+j,wxString::FromAscii(hm.c_str())+wxString::Format(_T(" (cycle #%u)\n Rwp=%5.2f%%\n GoF=%9.2f"),
4671  j,rw,gof))==false) user_stop=true;
4672 
4673  if(user_stop) break;
4674  }
4675  if(user_stop) break;
4676  const REAL rw=pDiff->GetParentPowderPattern().GetRw()*100;
4677  const REAL gof=pDiff->GetParentPowderPattern().GetChi2()
4678  /(pDiff->GetParentPowderPattern().GetNbPointUsed()-pDiff->GetNbReflBelowMaxSinThetaOvLambda());
4679  unsigned int nbextinct446=0;
4680  for(unsigned int i=6;i<fgp.size();++i) nbextinct446+=(unsigned int)(fgp[i]);
4681  vSPG.push_back(SPGScore(hm.c_str(),rw,gof,nbextinct446));
4682  mpLog->AppendText(wxString::Format(_T(" Rwp= %5.2f%% GoF=%9.2f (%2u extinct refls)\n"),rw,gof,nbextinct446));
4683  vSPGExtinctionFingerprint.insert(make_pair(fgp,SPGScore(hm.c_str(),rw,gof,nbextinct446)));
4684  }
4685  }
4686  if(user_stop) break;
4687  }
4688  // sort results by GoF
4689  vSPG.sort(compareSPGScore);
4690  mpLog->AppendText(wxString::Format(_T("\n\n BEST Solutions, from min_GoF to 2*min_Gof:\n")));
4691  mpLog->AppendText(wxString::Format(_T("\n\'extinct refls\' gives the number of extinct reflections\n")));
4692  mpLog->AppendText(wxString::Format(_T("for 0<=H<=4 0<=K<=4 0<=L<=6 \n\n")));
4693  for(list<SPGScore>::const_iterator pos=vSPG.begin();pos!=vSPG.end();++pos)
4694  {
4695  if(pos->gof>(2*vSPG.begin()->gof)) break;
4696  mpLog->AppendText(wxString::Format(_T(" Rwp= %5.2f%% GoF=%9.2f: (extinct refls=%2u )"),pos->rw,pos->gof,pos->nbextinct446)+wxString::FromAscii(pos->hm.c_str())+_T(" \n"));
4697  }
4698  // Back to original spacegroup
4699  pCrystal->Init(a,b,c,d,e,f,spgname,name);
4700  pDiff->GetParentPowderPattern().UpdateDisplay();
4701  pDiff->SetExtractionMode(true,true);
4702  pDiff->ExtractLeBail(5);
4703  pDiff->GetParentPowderPattern().UpdateDisplay();
4704 }
4705 
4706 void WXPowderPatternDiffraction::OnLeBail(wxCommandEvent &event)
4707 {
4708  if((event.GetId()==ID_POWDERDIFF_PROFILEFITTINGMODE)&&(mpProfileFittingMode->GetValue()==false))
4709  {
4710  mpPowderPatternDiffraction->SetExtractionMode(false);
4711  mpPowderPatternDiffraction->GetParentPowderPattern().UpdateDisplay();
4712  return;
4713  }
4714  mpPowderPatternDiffraction->SetExtractionMode(true,false);
4715  wxFrame *pFrame=new wxFrame(this,-1,_T("Profile Fitting"));
4716  WXProfileFitting *pFit;
4717  pFit=new WXProfileFitting(pFrame,&(mpPowderPatternDiffraction->GetParentPowderPattern()),mpPowderPatternDiffraction);
4718  pFrame->Show(true);
4719 }
4720 
4722 {
4723  mpPowderPatternDiffraction->FreezeLatticePar(mpFreezeLatticePar->GetValue());
4724 }
4725 
4726 
4728 //
4729 // WXProfilePseudoVoigt
4730 //
4732 WXProfilePseudoVoigt::WXProfilePseudoVoigt(wxWindow *parent, ReflectionProfilePseudoVoigt *prof):
4733 WXCrystObj(parent),mpProfile(prof)
4734 {
4735  VFN_DEBUG_ENTRY("WXProfilePseudoVoigt::WXProfilePseudoVoigt()",6)
4736  mpWXTitle->SetLabel("Pseudo-Voigt profile");
4737  mpWXTitle->SetForegroundColour(wxColour(0,0,255));
4738  // Width
4739  wxBoxSizer* sizer1=new wxBoxSizer(wxHORIZONTAL);
4740  WXCrystObjBasic* pFieldCagliotiU=mpProfile->GetPar("U").WXCreate(this);
4741  WXCrystObjBasic* pFieldCagliotiV=mpProfile->GetPar("V").WXCreate(this);
4742  WXCrystObjBasic* pFieldCagliotiW=mpProfile->GetPar("W").WXCreate(this);;
4743  sizer1->Add(pFieldCagliotiU,0);
4744  sizer1->Add(pFieldCagliotiV,0);
4745  sizer1->Add(pFieldCagliotiW,0);
4746  mList.Add(pFieldCagliotiU);
4747  mList.Add(pFieldCagliotiV);
4748  mList.Add(pFieldCagliotiW);
4749  mpSizer->Add(sizer1);
4750  pFieldCagliotiU->SetToolTip(_T("Width Parameters (Caglioti's law):\n")
4751  _T("fwhm=[W+V*tan(theta)+U*tan^2(theta)]^1/2"));
4752  pFieldCagliotiV->SetToolTip(_T("Width Parameters (Caglioti's law):\n")
4753  _T("fwhm=[W+V*tan(theta)+U*tan^2(theta)]^1/2"));
4754  pFieldCagliotiW->SetToolTip(_T("Width Parameters (Caglioti's law):\n")
4755  _T("fwhm=[W+V*tan(theta)+U*tan^2(theta)]^1/2"));
4756  // Mixing parameter
4757  wxBoxSizer* sizer2=new wxBoxSizer(wxHORIZONTAL);
4758  WXCrystObjBasic* pFieldEta0=mpProfile->GetPar("Eta0").WXCreate(this);
4759  WXCrystObjBasic* pFieldEta1=mpProfile->GetPar("Eta1").WXCreate(this);
4760  sizer2->Add(pFieldEta0,0);
4761  sizer2->Add(pFieldEta1,0);
4762  mList.Add(pFieldEta0);
4763  mList.Add(pFieldEta1);
4764  mpSizer->Add(sizer2);
4765  pFieldEta0->SetToolTip(_T("Gaussian/Lorentzian mixing parameters:\n")
4766  _T(" PV(x) = eta*L(x) + (1-eta)*G(x)\n\n")
4767  _T("eta=Eta0+Eta11*2theta"));
4768  pFieldEta1->SetToolTip(_T("Gaussian/Lorentzian mixing parameters:\n")
4769  _T(" PV(x) = eta*L(x) + (1-eta)*G(x)\n\n")
4770  _T("eta=Eta0+Eta11*2theta"));
4771  // Asymmetry parameter
4772  wxBoxSizer* sizer3=new wxBoxSizer(wxHORIZONTAL);
4773  //WXCrystObjBasic* pFieldAsymA0=mpProfile->GetPar("AsymA0").WXCreate(this);
4774  //WXCrystObjBasic* pFieldAsymA1=mpProfile->GetPar("AsymA1").WXCreate(this);
4775  //WXCrystObjBasic* pFieldAsymB0=mpProfile->GetPar("AsymB0").WXCreate(this);
4776  //WXCrystObjBasic* pFieldAsymB1=mpProfile->GetPar("AsymB1").WXCreate(this);
4777  //sizer3->Add(pFieldAsymA0,0);
4778  //sizer3->Add(pFieldAsymA1,0);
4779  //sizer3->Add(pFieldAsymB0,0);
4780  //sizer3->Add(pFieldAsymB1,0);
4781  //mList.Add(pFieldAsymA0);
4782  //mList.Add(pFieldAsymA1);
4783  //mList.Add(pFieldAsymB0);
4784  //mList.Add(pFieldAsymB1);
4785  WXCrystObjBasic* pFieldAsym0=mpProfile->GetPar("Asym0").WXCreate(this);
4786  WXCrystObjBasic* pFieldAsym1=mpProfile->GetPar("Asym1").WXCreate(this);
4787  WXCrystObjBasic* pFieldAsym2=mpProfile->GetPar("Asym2").WXCreate(this);
4788  sizer3->Add(pFieldAsym0,0);
4789  sizer3->Add(pFieldAsym1,0);
4790  sizer3->Add(pFieldAsym2,0);
4791  mList.Add(pFieldAsym0);
4792  mList.Add(pFieldAsym1);
4793  mList.Add(pFieldAsym2);
4794  mpSizer->Add(sizer3);
4795 
4796  pFieldAsym0->SetToolTip(_T("Asymmetry parameters:\n\n")
4797  _T("A=A0+A1/sin(2theta)+A2/sin^2(2theta) "));
4798  pFieldAsym1->SetToolTip(_T("Asymmetry parameters:\n\n")
4799  _T("A=A0+A1/sin(2theta)+A2/sin^2(2theta) "));
4800  pFieldAsym2->SetToolTip(_T("Asymmetry parameters:\n\n")
4801  _T("A=A0+A1/sin(2theta)+A2/sin^2(2theta) "));
4802 
4803  this->CrystUpdate(true);
4804  VFN_DEBUG_EXIT("WXProfilePseudoVoigt::WXProfilePseudoVoigt()",6)
4805 }
4806 WXProfilePseudoVoigt::~WXProfilePseudoVoigt()
4807 {
4808  mpProfile->WXNotifyDelete();
4809 }
4811 {
4812  return false;
4813 }
4814 
4816 //
4817 // WXProfilePseudoVoigtAnisotropic
4818 //
4820 WXProfilePseudoVoigtAnisotropic::WXProfilePseudoVoigtAnisotropic(wxWindow *parent, ReflectionProfilePseudoVoigtAnisotropic *prof):
4821 WXCrystObj(parent),mpProfile(prof)
4822 {
4823  VFN_DEBUG_ENTRY("WXProfilePseudoVoigtAnisotropic::WXProfilePseudoVoigtAnisotropic()",6)
4824  mpWXTitle->SetLabel("Pseudo-Voigt Anisotropic profile");
4825  mpWXTitle->SetForegroundColour(wxColour(0,0,255));
4826  // Gaussian Width
4827  wxBoxSizer* sizer1=new wxBoxSizer(wxHORIZONTAL);
4828  WXCrystObjBasic* pFieldCagliotiU=mpProfile->GetPar("U").WXCreate(this);
4829  WXCrystObjBasic* pFieldCagliotiV=mpProfile->GetPar("V").WXCreate(this);
4830  WXCrystObjBasic* pFieldCagliotiW=mpProfile->GetPar("W").WXCreate(this);;
4831  WXCrystObjBasic* pFieldScherrerP=mpProfile->GetPar("P").WXCreate(this);;
4832  sizer1->Add(pFieldCagliotiU,0);
4833  sizer1->Add(pFieldCagliotiV,0);
4834  sizer1->Add(pFieldCagliotiW,0);
4835  sizer1->Add(pFieldScherrerP,0);
4836  mList.Add(pFieldCagliotiU);
4837  mList.Add(pFieldCagliotiV);
4838  mList.Add(pFieldCagliotiW);
4839  mList.Add(pFieldScherrerP);
4840  mpSizer->Add(sizer1);
4841  pFieldCagliotiU->SetToolTip(_T("Gaussian Width Parameters:\n")
4842  _T("fwhm=[W+V*tan(theta)+U*tan^2(theta)+P/cos^2(theta)]^1/2"));
4843  pFieldCagliotiV->SetToolTip(_T("Gaussian Width Parameters:\n")
4844  _T("fwhm=[W+V*tan(theta)+U*tan^2(theta)+P/cos^2(theta)]^1/2"));
4845  pFieldCagliotiW->SetToolTip(_T("Gaussian Width Parameters:\n")
4846  _T("fwhm=[W+V*tan(theta)+U*tan^2(theta)+P/cos^2(theta)]^1/2"));
4847  pFieldScherrerP->SetToolTip(_T("Gaussian Width Parameters:\n")
4848  _T("fwhm=[W+V*tan(theta)+U*tan^2(theta)+P/cos^2(theta)]^1/2"));
4849  // Lorentzian & Mixing parameter
4850  wxBoxSizer* sizer2=new wxBoxSizer(wxHORIZONTAL);
4851  WXCrystObjBasic* pFieldEta0=mpProfile->GetPar("Eta0").WXCreate(this);
4852  WXCrystObjBasic* pFieldEta1=mpProfile->GetPar("Eta1").WXCreate(this);
4853  WXCrystObjBasic* pFieldX=mpProfile->GetPar("X").WXCreate(this);
4854  WXCrystObjBasic* pFieldY=mpProfile->GetPar("Y").WXCreate(this);
4855  sizer2->Add(pFieldEta0,0);
4856  sizer2->Add(pFieldEta1,0);
4857  sizer2->Add(pFieldX,0);
4858  sizer2->Add(pFieldY,0);
4859  mList.Add(pFieldX);
4860  mList.Add(pFieldY);
4861  mList.Add(pFieldEta0);
4862  mList.Add(pFieldEta1);
4863  mpSizer->Add(sizer2);
4864  pFieldEta0->SetToolTip(_T("Gaussian/Lorentzian mixing parameters:\n")
4865  _T(" PV(x) = eta*L(x) + (1-eta)*G(x)\n\n")
4866  _T("eta=Eta0+Eta11*2theta"));
4867 
4868  pFieldEta1->SetToolTip(_T("Gaussian/Lorentzian mixing parameters:\n")
4869  _T(" PV(x) = eta*L(x) + (1-eta)*G(x)\n\n")
4870  _T("eta=Eta0+Eta1*2theta"));
4871 
4872  pFieldX->SetToolTip(_T("Lorentzian width:\n")
4873  _T(" FWHM(x) = X/cos(theta) + (Y + gam_L/sin^2(theta))*tan(theta)\n\n")
4874  _T("gam_L=gam_hh*H^2 + gam_kk*K^2 + gam_ll*L^2\n")
4875  _T(" +gam_hk*HK + gam_hl*HL + gam_kl*HL"));
4876 
4877  pFieldY->SetToolTip(_T("Lorentzian width:\n")
4878  _T(" FWHM(x) = X/cos(theta) + (Y + gam_L/sin^2(theta))*tan(theta)\n\n")
4879  _T("gam_L=gam_hh*H^2 + gam_kk*K^2 + gam_ll*L^2\n")
4880  _T(" +gam_hk*HK + gam_hl*HL + gam_kl*HL"));
4881 
4882  // Anisotropic coefficients
4883  wxBoxSizer* sizerA=new wxBoxSizer(wxHORIZONTAL);
4884  WXCrystObjBasic* pFieldGHH=mpProfile->GetPar("G_HH").WXCreate(this);
4885  WXCrystObjBasic* pFieldGKK=mpProfile->GetPar("G_KK").WXCreate(this);
4886  WXCrystObjBasic* pFieldGLL=mpProfile->GetPar("G_LL").WXCreate(this);
4887  WXCrystObjBasic* pFieldGHK=mpProfile->GetPar("G_HK").WXCreate(this);
4888  WXCrystObjBasic* pFieldGHL=mpProfile->GetPar("G_HL").WXCreate(this);
4889  WXCrystObjBasic* pFieldGKL=mpProfile->GetPar("G_KL").WXCreate(this);
4890  sizerA->Add(pFieldGHH,0);
4891  sizerA->Add(pFieldGKK,0);
4892  sizerA->Add(pFieldGLL,0);
4893  sizerA->Add(pFieldGHK,0);
4894  sizerA->Add(pFieldGHL,0);
4895  sizerA->Add(pFieldGKL,0);
4896  mList.Add(pFieldGHH);
4897  mList.Add(pFieldGKK);
4898  mList.Add(pFieldGLL);
4899  mList.Add(pFieldGHK);
4900  mList.Add(pFieldGHL);
4901  mList.Add(pFieldGKL);
4902  mpSizer->Add(sizerA);
4903  pFieldGHH->SetToolTip(_T("Lorentzian width:\n")
4904  _T(" FWHM(x) = X/cos(theta) + (Y + gam_L/sin^2(theta))*tan(theta)\n\n")
4905  _T("gam_L=gam_hh*H^2 + gam_kk*K^2 + gam_ll*L^2\n")
4906  _T(" +gam_hk*HK + gam_hl*HL + gam_kl*HL"));
4907  pFieldGKK->SetToolTip(_T("Lorentzian width:\n")
4908  _T(" FWHM(x) = X/cos(theta) + (Y + gam_L/sin^2(theta))*tan(theta)\n\n")
4909  _T("gam_L=gam_hh*H^2 + gam_kk*K^2 + gam_ll*L^2\n")
4910  _T(" +gam_hk*HK + gam_hl*HL + gam_kl*HL"));
4911  pFieldGLL->SetToolTip(_T("Lorentzian width:\n")
4912  _T(" FWHM(x) = X/cos(theta) + (Y + gam_L/sin^2(theta))*tan(theta)\n\n")
4913  _T("gam_L=gam_hh*H^2 + gam_kk*K^2 + gam_ll*L^2\n")
4914  _T(" +gam_hk*HK + gam_hl*HL + gam_kl*HL"));
4915  pFieldGHK->SetToolTip(_T("Lorentzian width:\n")
4916  _T(" FWHM(x) = X/cos(theta) + (Y + gam_L/sin^2(theta))*tan(theta)\n\n")
4917  _T("gam_L=gam_hh*H^2 + gam_kk*K^2 + gam_ll*L^2\n")
4918  _T(" +gam_hk*HK + gam_hl*HL + gam_kl*HL"));
4919  pFieldGHL->SetToolTip(_T("Lorentzian width:\n")
4920  _T(" FWHM(x) = X/cos(theta) + (Y + gam_L/sin^2(theta))*tan(theta)\n\n")
4921  _T("gam_L=gam_hh*H^2 + gam_kk*K^2 + gam_ll*L^2\n")
4922  _T(" +gam_hk*HK + gam_hl*HL + gam_kl*HL"));
4923  pFieldGKL->SetToolTip(_T("Lorentzian width:\n")
4924  _T(" FWHM(x) = X/cos(theta) + (Y + gam_L/sin^2(theta))*tan(theta)\n\n")
4925  _T("gam_L=gam_hh*H^2 + gam_kk*K^2 + gam_ll*L^2\n")
4926  _T(" +gam_hk*HK + gam_hl*HL + gam_kl*HL"));
4927 
4928  // Asymmetry parameters
4929  wxBoxSizer* sizer3=new wxBoxSizer(wxHORIZONTAL);
4930  WXCrystObjBasic* pFieldAsym0=mpProfile->GetPar("Asym0").WXCreate(this);
4931  WXCrystObjBasic* pFieldAsym1=mpProfile->GetPar("Asym1").WXCreate(this);
4932  WXCrystObjBasic* pFieldAsym2=mpProfile->GetPar("Asym2").WXCreate(this);
4933  sizer3->Add(pFieldAsym0,0);
4934  sizer3->Add(pFieldAsym1,0);
4935  sizer3->Add(pFieldAsym2,0);
4936  mList.Add(pFieldAsym0);
4937  mList.Add(pFieldAsym1);
4938  mList.Add(pFieldAsym2);
4939  mpSizer->Add(sizer3);
4940 
4941  pFieldAsym0->SetToolTip(_T("Asymmetry parameters:\n\n")
4942  _T("A=A0+A1/sin(2theta)+A2/sin^2(2theta) "));
4943  pFieldAsym1->SetToolTip(_T("Asymmetry parameters:\n\n")
4944  _T("A=A0+A1/sin(2theta)+A2/sin^2(2theta) "));
4945  pFieldAsym2->SetToolTip(_T("Asymmetry parameters:\n\n")
4946  _T("A=A0+A1/sin(2theta)+A2/sin^2(2theta) "));
4947 
4948  this->CrystUpdate(true);
4950 }
4951 
4952 WXProfilePseudoVoigtAnisotropic::~WXProfilePseudoVoigtAnisotropic()
4953 {
4954  mpProfile->WXNotifyDelete();
4955 }
4956 
4958 {
4959  return false;
4960 }
4961 
4963 //
4964 // WXProfileDoubleExponentialPseudoVoigt
4965 //
4967 WXProfileDoubleExponentialPseudoVoigt::WXProfileDoubleExponentialPseudoVoigt
4968  (wxWindow *parent, ReflectionProfileDoubleExponentialPseudoVoigt *prof):
4969 WXCrystObj(parent),mpProfile(prof)
4970 {
4971  VFN_DEBUG_ENTRY("WXProfileDoubleExponentialPseudoVoigt::WXProfileDoubleExponentialPseudoVoigt()",6)
4972  mpWXTitle->SetLabel("Double-Exponential Pseudo-Voigt profile (for neutron TOF)");
4973  mpWXTitle->SetForegroundColour(wxColour(0,0,255));
4974  // Instrumental
4975  wxBoxSizer* sizer1=new wxBoxSizer(wxHORIZONTAL);
4976  WXCrystObjBasic* pFieldCagliotiA0=mpProfile->GetPar("Alpha0").WXCreate(this);
4977  WXCrystObjBasic* pFieldCagliotiA =mpProfile->GetPar("Alpha1").WXCreate(this);
4978  WXCrystObjBasic* pFieldCagliotiB0=mpProfile->GetPar("Beta0").WXCreate(this);
4979  WXCrystObjBasic* pFieldCagliotiB1=mpProfile->GetPar("Beta1").WXCreate(this);
4980  sizer1->Add(pFieldCagliotiA0,0);
4981  sizer1->Add(pFieldCagliotiA,0);
4982  sizer1->Add(pFieldCagliotiB0,0);
4983  sizer1->Add(pFieldCagliotiB1,0);
4984  mList.Add(pFieldCagliotiA0);
4985  mList.Add(pFieldCagliotiA);
4986  mList.Add(pFieldCagliotiB0);
4987  mList.Add(pFieldCagliotiB1);
4988  mpSizer->Add(sizer1);
4989  // Instrumental
4990  wxBoxSizer* sizer2=new wxBoxSizer(wxHORIZONTAL);
4991  WXCrystObjBasic* pFieldSigma0=mpProfile->GetPar("GaussianSigma0").WXCreate(this);
4992  WXCrystObjBasic* pFieldSigma1=mpProfile->GetPar("GaussianSigma1").WXCreate(this);
4993  WXCrystObjBasic* pFieldSigma2=mpProfile->GetPar("GaussianSigma2").WXCreate(this);
4994  sizer2->Add(pFieldSigma0,0);
4995  sizer2->Add(pFieldSigma1,0);
4996  sizer2->Add(pFieldSigma2,0);
4997  mList.Add(pFieldSigma0);
4998  mList.Add(pFieldSigma1);
4999  mList.Add(pFieldSigma2);
5000  mpSizer->Add(sizer2);
5001  // Instrumental
5002  wxBoxSizer* sizer3=new wxBoxSizer(wxHORIZONTAL);
5003  WXCrystObjBasic* pFieldGamma0=mpProfile->GetPar("LorentzianGamma0").WXCreate(this);
5004  WXCrystObjBasic* pFieldGamma1=mpProfile->GetPar("LorentzianGamma1").WXCreate(this);
5005  WXCrystObjBasic* pFieldGamma2=mpProfile->GetPar("LorentzianGamma2").WXCreate(this);
5006  sizer3->Add(pFieldGamma0,0);
5007  sizer3->Add(pFieldGamma1,0);
5008  sizer3->Add(pFieldGamma2,0);
5009  mList.Add(pFieldGamma0);
5010  mList.Add(pFieldGamma1);
5011  mList.Add(pFieldGamma2);
5012  mpSizer->Add(sizer3);
5013 
5014  this->CrystUpdate(true);
5016 }
5017 WXProfileDoubleExponentialPseudoVoigt::~WXProfileDoubleExponentialPseudoVoigt()
5018 {
5019  mpProfile->WXNotifyDelete();
5020 }
5022 {
5023  return false;
5024 }
5025 
5026 }// namespace
5027 
void FitScaleFactorForR() const
Fit the scale(s) factor of each component to minimize R.
virtual void UpdateUI(const bool mutexlock=false)
Update the User Interface, if necessary.
void OnUpdate(wxCommandEvent &WXUNUSED(event))
Update the powder spectrum, at the user's request.
Texture correction using the March-Dollase model.
virtual void UpdateUI(const bool mutexlock=false)
Update the User Interface, if necessary.
T * WXDialogChooseFromRegistry(ObjRegistry< T > &reg, wxWindow *parent, const string &message, int &choice)
This function allows to pick up one object in a registry.
const CrystVector_REAL & GetPowderPatternCalc() const
Get the calculated powder pattern.
long Data2ScreenY(const REAL y) const
Convert Y data (intensity) coordinate to screen coordinate (pixel)
Pseudo-Voigt reflection profile, with 6-parameters anisotropic Lorentzian broadening and Toraya asymm...
virtual void UpdateDisplay() const
If there is an interface, this should be automatically be called each time there is a 'new...
Double-Exponential Pseudo-Voigt profile for TOF.
void WXCrystValidateAllUserInput()
This function validates all user input (in a WXField) not yet taken into account, if needs be...
Definition: wxCryst.cpp:257
const RefParType * gpRefParTypeScattDataCorrPos
Parameter type for correction to peak positions.
CrystMutex mMutex
Mutex used to lock data when preparing to update the UI in non-main thread.
Definition: wxCryst.h:189
void PrepareRefParList(const bool copy_param=false)
Prepare the full parameter list for the refinement.
Definition: LSQNumObj.cpp:816
Class to pick one choice...
Definition: wxCryst.h:482
const Radiation & GetRadiation() const
Neutron or x-ray experiment ?
virtual void UpdateUI(const bool mutexlock=false)
Update the User Interface, if necessary.
virtual bool OnChangeName(const int id)
When a WXFieldName has been changed by the user, it is handled here.
void OnRedrawNewPattern(wxUpdateUIEvent &WXUNUSED(event))
Redraw the pattern (special function to ensure complete redrawing under windows...)
void SetRefinedObj(RefinableObj &obj, const unsigned int LSQFuncIndex=0, const bool init=true, const bool recursive=false)
Choose the object to refine.
Definition: LSQNumObj.cpp:727
void OnLeBail(wxCommandEvent &event)
Perform Le Bail extraction.
void Add(WXCrystObjBasic *)
Add an object to the list.
Definition: wxCryst.cpp:199
Class to display a Powder Pattern (calc,obs) in a graphic window.
bool mNeedUpdateUI
Do we need to update the display ?
Definition: wxCryst.h:187
void ResetAxisLimits()
Reset the limits of the axis to full range.
virtual void UpdateUI(const bool mutexlock=false)
Update the User Interface, if necessary.
Simple chronometer class, with microsecond precision.
Definition: Chronometer.h:33
virtual bool OnChangeName(const int id)
When a WXFieldName has been changed by the user, it is handled here.
virtual void CrystUpdate(const bool updateUI=false, const bool mutexlock=false)
Get new values to be displayed from the underlying object, and raise flag if an UI update is necessar...
Class to display a Powder Pattern Background.
One texture phase for the March-Dollase model.
Algorithm class to find the correct indexing from observed peak positions.
Definition: Indexing.h:212
virtual void SetToolTip(const wxString &tip)
Set tooltip for this window.
Definition: wxCryst.cpp:179
virtual bool OnChangeName(const int id)
When a WXFieldName has been changed by the user, it is handled here.
void OnChangePeak(wxCommandEvent &WXUNUSED(event))
Add or remove peak.
Phase to compute a background contribution to a powder pattern using an interpolation.
std::map< wxWindowID, std::pair< wxPoint, wxSize > > gvWindowPosition
Used to remember window positions.
Definition: wxCryst.cpp:51
REAL GetChi2_Option() const
Return the conventionnal or integrated Chi^2, depending on the option.
float EstimateCellVolume(const float dmin, const float dmax, const float nbrefl, const CrystalSystem system, const CrystalCentering centering, const float kappa)
Estimate volume from number of peaks at a given dmin See J.
Definition: Indexing.cpp:45
Class to display a Powder Pattern Pseudo-Voigt Profile with Anisotropic broadening.
CrystalSystem
Different lattice types.
Definition: Indexing.h:38
Class to compute the contribution to a powder pattern from a crystalline phase.
WXFieldName * mpWXTitle
The title.
Definition: wxCryst.h:273
const RefParType * gpRefParTypeScattDataProfile
Type for reflection profile.
void SetPowderPatternObs(const CrystVector_REAL &obs)
Set observed powder pattern from vector array.
This displays all components of a ObjCryst++ Registry.
bool GetExtractionMode() const
Return true if in extraction mode, i.e. using extracted intensities instead of computed structure fac...
virtual void CrystUpdate(const bool updateUI=false, const bool mutexlock=false)
Get new values to be displayed from the underlying object, and raise flag if an UI update is necessar...
void CrystUpdate(const bool updateUI=false, const bool mutexlock=false)
Forces all objects in the list to update.
Definition: wxCryst.cpp:223
REAL GetR() const
Unweighted R-factor.
void OnMenuLeBail(wxCommandEvent &event)
Profile fitting & Le Bail intensity extraction.
Generic Refinable Object.
Definition: RefinableObj.h:752
WXCrystObjBasicList mList
All windows but the title and collapse button are in this list.
Definition: wxCryst.h:277
const RefParType * gpRefParTypeScattDataScale
Type for scattering data scale factors.
Class to store positions of observed reflections.
Definition: Indexing.h:114
Class to display the Preferred Orientation Correction using the March-Dollase parametrization.
ObjRegistry< Crystal > gCrystalRegistry("List of all Crystals")
Global registry for all Crystal objects.
Definition: Crystal.h:525
Class to display a Powder Pattern for a crystalline phase.
void SetParIsFixed(const std::string &parName, const bool fix)
Fix one parameter.
const RefParType * gpRefParTypeScattDataBackground
Parameter type for background intensity.
Abstract base class for all objects in wxCryst.
Definition: wxCryst.h:127
float Score(const PeakList &dhkl, const RecUnitCell &rpar, const unsigned int nbSpurious, const bool verbose, const bool storehkl, const bool storePredictedHKL)
Compute score for a candidate RecUnitCell and a PeakList.
Definition: Indexing.cpp:936
void OnPaint(wxPaintEvent &WXUNUSED(event))
Redraw the spectrum.
WX Class for PowderPattern objects.
void AddMenuItem(const int menuId, int id, const string &item, const string &help="", const bool checkable=false)
Add an entry to a menu.
Definition: wxCryst.cpp:928
void CalcPowderPattern() const
Calc the powder pattern.
REAL GetRw() const
Get the weighted R-factor.
REAL Screen2DataY(const long y) const
Convert Y screen coordinate (pixel) to data (intensity) coordinate.
const CrystVector_REAL & GetPowderPatternX() const
Get the vector of X (2theta or time-of-flight) coordinates.
virtual bool SetForegroundColour(const wxColour &colour)
Change the colour of the field's title.
Definition: wxCryst.cpp:291
void ImportPowderPatternCIF(const CIF &cif)
Import CIF powder pattern data.
virtual void CrystUpdate(const bool updateUI=false, const bool mutexlock=false)
Get new values to be displayed from the underlying object, and raise flag if an UI update is necessar...
WavelengthType GetWavelengthType() const
Get the Wavelength type (monochromatic, Alpha1+Alpha2, Time Of Flight...)
void AddPowderPatternComponent(PowderPatternComponent &)
Add a component (phase, backround) to this pattern.
WXCrystObj(wxWindow *parent, int orient=wxHORIZONTAL, bool showName=true)
Constructor, with a.
Definition: wxCryst.cpp:778
void UpdateUI(const bool mutexlock=false)
Update the User Interface, if necessary.
virtual bool OnChangeName(const int id)
When a WXFieldName has been changed by the user, it is handled here.
long Point2ScreenX(const long x) const
Convert X data (as data point index) to screen coordinate (pixel)
WXCrystObjBasic(wxWindow *parent)
Constructor.
Definition: wxCryst.cpp:129
void SetRadiationType(const RadiationType radiation)
Set the radiation type.
void OnMouseWheel(wxMouseEvent &event)
Wheel wan be used to scroll the pattern.
output a number as a formatted float:
Class to display a Powder Pattern Pseudo-Voigt Profile.
Base class for all displayed ObjCryst objects (with a title, and a sizer to stack objects)...
Definition: wxCryst.h:248
long Data2ScreenX(const REAL x) const
Convert X data (2theta) coordinate to screen coordinate (pixel)
virtual void CrystUpdate(const bool updateUI=false, const bool mutexlock=false)
Get new values to be displayed from the underlying object, and raise flag if an UI update is necessar...
Main CIF class - parses the stream and separates data blocks, comments, items, loops.
Definition: CIF.h:169
void SetPattern(const CrystVector_REAL &obs, const CrystVector_REAL &calc, const REAL tthetaMin, const REAL tthetaStep, const CrystVector_REAL &sigma, const CrystVector_REAL &chi2Cumul)
Update the pattern.
const CrystVector_REAL & GetPowderPatternObs() const
Get the observed powder pattern.
virtual void UpdateUI(const bool mutexlock=false)
Update the User Interface, if necessary.
const Crystal & GetCrystal() const
Const access to the data's crystal.
const CrystVector_REAL & GetChi2Cumul() const
Get the powder pattern cumulative Chi^2.
void AddMenu(const string &name, const int menuId, const string &help="")
Add a menu.
Definition: wxCryst.cpp:909
const CrystVector_REAL & GetPowderPatternVariance() const
Get the variance (obs+model) for each point of the powder pattern.
The base wxCryst class for all RefinableObj objects.
REAL Screen2DataX(const long x) const
Convert X screen coordinate (pixel) to data (2theta) coordinate.
Exception class for ObjCryst++ library.
Definition: General.h:119
Class to automatically assign a unique wxID to each window.
Definition: wxCryst.h:74
The namespace which includes all objects (crystallographic and algorithmic) in ObjCryst++.
Definition: Atom.cpp:47
wxBoxSizer * mpTopSizer
Top sizer including the title and WXCrystObj::mpSizer.
Definition: wxCryst.h:269
virtual const string & GetName() const
Name of the object.
unsigned long GetNbPoint() const
Number of points ?
void OnFreezeLatticePar(wxCommandEvent &event)
Freeze lattice parameter, which will not follow anymore the Crystal Unitcell values.
Class to display a Powder Pattern Pseudo-Voigt Profile.
Pseudo-Voigt reflection profile.
Crystal class: Unit cell, spacegroup, scatterers.
Definition: Crystal.h:97
void SetWavelengthType(const WavelengthType &type)
Set the Wavelength type (monochromatic, Alpha1+Alpha2, Time Of Flight...)
virtual void CrystUpdate(const bool updateUI=false, const bool mutexlock=false)
Get new values to be displayed from the underlying object, and raise flag if an UI update is necessar...
(Quick & dirty) Least-Squares Refinement Object with Numerical derivatives
Definition: LSQNumObj.h:37
REAL GetChi2() const
Return conventionnal Chi^2.
void FitScaleFactorForRw() const
Fit the scale(s) factor of each component to minimize Rw.
void ExportFullprof(const std::string &prefix) const
Export powder pattern & crystal structure in Fullprof format.
const RefParType * gpRefParTypeObjCryst
Top RefParType for the ObjCryst++ library.
void Refine(int nbCycle=1, bool useLevenbergMarquardt=false, const bool silent=false, const bool callBeginEndOptimization=true, const float minChi2var=0.01)
Do the refinement.
Definition: LSQNumObj.cpp:104
void UpdateUI(const bool mutexlock=false)
Forces all objects in the list to update.
Definition: wxCryst.cpp:233
void OnMouse(wxMouseEvent &event)
Display the Theta and intensity values at the mouse position, in the status bar.