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