FOX/ObjCryst++  2022
ScatteringData.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 /*
20 * source file for LibCryst++ ScatteringData class
21 *
22 */
23 
24 #include <cmath>
25 
26 #include <typeinfo>
27 
28 #include "cctbx/sgtbx/space_group.h"
29 #include "cctbx/miller/index_generator.h"
30 #include "cctbx/miller/sym_equiv.h"
31 #include "cctbx/eltbx/wavelengths.h"
32 
33 #include "ObjCryst/ObjCryst/ScatteringData.h"
34 #include "ObjCryst/Quirks/VFNDebug.h"
35 #include "ObjCryst/Quirks/VFNStreamFormat.h"
36 #include "ObjCryst/Quirks/Chronometer.h"
37 
38 #ifdef __WX__CRYST__
39  #include "ObjCryst/wxCryst/wxPowderPattern.h"
40  #include "ObjCryst/wxCryst/wxRadiation.h"
41 #endif
42 
43 #include <fstream>
44 #include <iomanip>
45 #include <stdio.h> //for sprintf()
46 
47 #ifdef HAVE_SSE_MATHFUN
48 #include "ObjCryst/Quirks/sse_mathfun.h"
49 #endif
50 
51 #define POSSIBLY_UNUSED(expr) (void)(expr)
52 
53 namespace ObjCryst
54 {
72 
73 const RefParType *gpRefParTypeRadiation=0;
74 const RefParType *gpRefParTypeRadiationWavelength=0;
75 
76 long NiftyStaticGlobalObjectsInitializer_ScatteringData::mCount=0;
77 
78 #ifndef HAVE_SSE_MATHFUN
79 //######################################################################
80 // Tabulated math functions for faster (&less precise) F(hkl) calculation
81 //These function are defined and used in cristallo-spacegroup.cpp
82 //Currently tabulating sine and cosine only
83 //######################################################################
84 
85 //static bool sLibCrystTabulCosineIsInit=false;
86 
87 //conversion value
88 static REAL sLibCrystTabulCosineRatio;
89 // Number of tabulated values of cosine between [0;2pi]
90 // 100 000 is far enough for a model search, yielding a maximum
91 // error less than .05%... 10000 should be enough, too, with (probably) a higher cache hit
92 #define sLibCrystNbTabulSine 8192
93 #define sLibCrystNbTabulSineMASK 8191
94 //storage of tabulated values of cosine, and a table with interlaced csoine/sine values
95 static REAL *spLibCrystTabulCosine;
96 static REAL *spLibCrystTabulCosineSine;
97 
98 void InitLibCrystTabulCosine()
99 {
100  VFN_DEBUG_MESSAGE("InitLibCrystTabulCosine()",10)
101  spLibCrystTabulCosine=new REAL[sLibCrystNbTabulSine];
102  spLibCrystTabulCosineSine=new REAL[sLibCrystNbTabulSine*2];
103  REAL *tmp=spLibCrystTabulCosine;
104  sLibCrystTabulCosineRatio=sLibCrystNbTabulSine/2./M_PI;
105  for(REAL i=0;i<sLibCrystNbTabulSine;i++) *tmp++ = cos(i/sLibCrystTabulCosineRatio);
106  tmp=spLibCrystTabulCosineSine;
107  for(REAL i=0;i<sLibCrystNbTabulSine;i++)
108  {
109  *tmp++ = cos(i/sLibCrystTabulCosineRatio);
110  *tmp++ = sin(i/sLibCrystTabulCosineRatio);
111  }
112 }
113 
114 void DeleteLibCrystTabulCosine()
115 {
116  delete[] spLibCrystTabulCosine;
117  delete[] spLibCrystTabulCosineSine;
118 }
119 
120 // Same for exponential calculations (used for global temperature factors)
121 static bool sLibCrystTabulExpIsInit=false;
122 static const long sLibCrystNbTabulExp=10000;
123 static const REAL sLibCrystMinTabulExp=-5.;
124 static const REAL sLibCrystMaxTabulExp=10.;
125 static REAL *spLibCrystTabulExp;
126 void InitLibCrystTabulExp()
127 {
128  VFN_DEBUG_MESSAGE("InitLibCrystTabulExp()",10)
129  spLibCrystTabulExp=new REAL[sLibCrystNbTabulExp];
130  REAL *tmp=spLibCrystTabulExp;
131  for(REAL i=0;i<sLibCrystNbTabulExp;i++)
132  *tmp++ = exp(sLibCrystMinTabulExp+i*(sLibCrystMaxTabulExp-sLibCrystMinTabulExp)/sLibCrystNbTabulExp);
133  sLibCrystTabulExpIsInit=true;
134 }
135 
136 void DeleteLibCrystTabulExp() { delete[] spLibCrystTabulExp;}
137 
138 //:KLUDGE: The allocated memory for cos and sin table is never freed...
139 // This should be done after the last ScatteringData object is deleted.
140 #endif
142 //
143 // Radiation
144 //
147 mWavelength(1),mXRayTubeName(""),mXRayTubeDeltaLambda(0.),
148 mXRayTubeAlpha2Alpha1Ratio(0.5),mLinearPolarRate(0)
149 {
150  mWavelength=1;
151  this->InitOptions();
152  mRadiationType.SetChoice(RAD_XRAY);
153  mClockMaster.AddChild(mClockWavelength);
154  mClockMaster.AddChild(mClockRadiation);
155  this->SetWavelengthType(WAVELENGTH_MONOCHROMATIC);
156 }
157 
158 Radiation::Radiation(const RadiationType rad,const REAL wavelength)
159 {
160  this->InitOptions();
161  mRadiationType.SetChoice(rad);
162  mWavelength=wavelength;
163  mXRayTubeName="";
164  mXRayTubeDeltaLambda=0.;//useless here
165  mXRayTubeAlpha2Alpha1Ratio=0.5;//useless here
166  mLinearPolarRate=0.95;//assume it's synchrotron ?
167  mClockMaster.AddChild(mClockWavelength);
168  mClockMaster.AddChild(mClockRadiation);
169  this->SetWavelengthType(WAVELENGTH_MONOCHROMATIC);
170 }
171 
172 Radiation::Radiation(const string &XRayTubeElementName,const REAL alpha2Alpha2ratio)
173 {
174  this->InitOptions();
175  this->SetWavelength(XRayTubeElementName,alpha2Alpha2ratio);
176  mClockMaster.AddChild(mClockWavelength);
177  mClockMaster.AddChild(mClockRadiation);
178 }
179 
181 mRadiationType(old.mRadiationType),
182 mWavelengthType(old.mWavelengthType),
183 mWavelength(old.mWavelength),
184 mXRayTubeName(old.mXRayTubeName),
185 mXRayTubeDeltaLambda(old.mXRayTubeDeltaLambda),
186 mXRayTubeAlpha2Alpha1Ratio(old.mXRayTubeAlpha2Alpha1Ratio),
187 mLinearPolarRate(old.mLinearPolarRate)
188 {
189  mClockWavelength.Click();
190  mClockMaster.AddChild(mClockWavelength);
191  mClockMaster.AddChild(mClockRadiation);
192  this->SetWavelengthType((WavelengthType)old.mWavelengthType.GetChoice());
193 }
194 
195 Radiation::~Radiation()
196 {}
197 
198 const string& Radiation::GetClassName() const
199 {
200  const static string className="Radiation";
201  return className;
202 }
203 
204 void Radiation::operator=(const Radiation &old)
205 {
211  mClockWavelength.Click();
212  mRadiationType.SetChoice(old.mRadiationType.GetChoice());
213  this->SetWavelengthType((WavelengthType) old.mWavelengthType.GetChoice());
214 }
215 
217 {return (RadiationType) mRadiationType.GetChoice();}
218 
220 {
221  mRadiationType.SetChoice(rad);
222  if(rad == RAD_NEUTRON) mLinearPolarRate=0;
223  if(rad == RAD_ELECTRON)
224  {
226  this->SetWavelengthType(WAVELENGTH_MONOCHROMATIC);
227  }
228  else this->UpdateDisplay();
229 }
230 
232 {
233  mWavelengthType.SetChoice((unsigned long) type);
234  if(type==WAVELENGTH_TOF)
235  {
236  this->SetRadiationType(RAD_NEUTRON);
237  this->GetPar("XRayTubeDeltaLambda").SetIsUsed(false);
238  this->GetPar("XRayTubeAlpha2Alpha1Ratio").SetIsUsed(false);
239  }
240  if(type==WAVELENGTH_ALPHA12)
241  {
242  this->SetRadiationType(RAD_XRAY);
243  this->GetPar("XRayTubeDeltaLambda").SetIsUsed(true);
244  this->GetPar("XRayTubeAlpha2Alpha1Ratio").SetIsUsed(true);
245  }
246  if(type==WAVELENGTH_MONOCHROMATIC)
247  {
248  this->GetPar("XRayTubeDeltaLambda").SetIsUsed(false);
249  this->GetPar("XRayTubeAlpha2Alpha1Ratio").SetIsUsed(false);
250  }
251  this->UpdateDisplay();
252 }
253 
255 {return (WavelengthType) mWavelengthType.GetChoice();}
256 
257 const CrystVector_REAL& Radiation::GetWavelength() const {return mWavelength;}
258 void Radiation::SetWavelength(const REAL l)
259 {
260  mWavelength.resize(1);
261  mWavelength=l;
262  mClockWavelength.Click();
263  this->GetPar("XRayTubeDeltaLambda").SetIsUsed(false);
264  this->GetPar("XRayTubeAlpha2Alpha1Ratio").SetIsUsed(false);
265 }
266 void Radiation::SetWavelength(const string &XRayTubeElementName,
267  const REAL alpha2Alpha2ratio)
268 {
269  VFN_DEBUG_MESSAGE("Radiation::SetWavelength(tubeName,ratio):",5)
270  mXRayTubeName=XRayTubeElementName;
271  this->SetRadiationType(RAD_XRAY);
272  mWavelength.resize(1);
274 
275  if(XRayTubeElementName.length() >=3) //:KLUDGE:
276  {
277  if(XRayTubeElementName=="CoA1")
278  {
279  mWavelength=1.78901;
280  this->SetWavelengthType(WAVELENGTH_MONOCHROMATIC);
281  }
282  else
283  {
284  try
285  {
286  cctbx::eltbx::wavelengths::characteristic ch(mXRayTubeName);
287  if(!ch.is_valid())
288  {
289  cout << "WARNING: could not interpret X-Ray tube name:"<<XRayTubeElementName<<endl
290  << " not modifying wavelength !"<<endl;
291  return;
292  }
293  mWavelength=ch.as_angstrom();
294  this->SetWavelengthType(WAVELENGTH_MONOCHROMATIC);
295  }
296  catch(cctbx::error)
297  {
298  cout << "WARNING: could not interpret X-Ray tube name:"<<XRayTubeElementName<<endl
299  << " not modifying wavelength !"<<endl;
300  return;
301  }
302  }
303  }
304  else
305  {
306  mXRayTubeAlpha2Alpha1Ratio=alpha2Alpha2ratio;
307  REAL lambda1 = 0, lambda2 = 0;
308  if(XRayTubeElementName=="Co")
309  {
310  lambda1=1.78901;
311  lambda2=1.79290;
312  }
313  else
314  {
315  try
316  {
317  cctbx::eltbx::wavelengths::characteristic ch(mXRayTubeName+"A1");
318  if(!ch.is_valid())
319  {
320  cout << "WARNING: could not interpret X-Ray tube name:"<<XRayTubeElementName<<endl
321  << " not modifying wavelength !"<<endl;
322  return;
323  }
324  lambda1=ch.as_angstrom();
325  cctbx::eltbx::wavelengths::characteristic ch2(mXRayTubeName+"A2");
326  if(!ch2.is_valid())
327  {
328  cout << "WARNING: could not interpret X-Ray tube name:"<<XRayTubeElementName<<endl
329  << " not modifying wavelength !"<<endl;
330  return;
331  }
332  lambda2=ch2.as_angstrom();
333  }
334  catch(cctbx::error)
335  {
336  cout << "WARNING: could not interpret X-Ray tube name:"<<XRayTubeElementName<<endl
337  << " not modifying wavelength !"<<endl;
338  return;
339  }
340  }
341  mXRayTubeDeltaLambda=lambda2-lambda1;
342  mWavelength=lambda1
344  VFN_DEBUG_MESSAGE("Radiation::SetWavelength("<<XRayTubeElementName<<","<<alpha2Alpha2ratio<<"):", 10)
345  this->SetWavelengthType(WAVELENGTH_ALPHA12);
346  }
347  mClockWavelength.Click();
348 }
349 
351 
353 
354 
355 const RefinableObjClock& Radiation::GetClockWavelength() const {return mClockWavelength;}
357 
358 void Radiation::Print()const
359 {
360  VFN_DEBUG_MESSAGE("Radiation::Print():"<<this->GetName(),5)
361  cout << "Radiation:" << " " ;
362 
363  switch(mRadiationType.GetChoice())
364  {
365  case RAD_NEUTRON: cout<< "Neutron,";break;
366  case RAD_XRAY: cout<< "X-Ray,";break;
367  case RAD_ELECTRON: cout<< "Electron,";break;
368  }
369 
370  cout << "Wavelength=" <<" ";
371  switch(mWavelengthType.GetChoice())
372  {
373  case WAVELENGTH_MONOCHROMATIC: cout<< "monochromatic:"<<" "<<mWavelength(0) <<endl;break;
374  case WAVELENGTH_ALPHA12: cout << "tube:"<<" "<<mXRayTubeName<<", Alpha1/Alpha2= "
375  << mXRayTubeAlpha2Alpha1Ratio<<endl;break;
376  case WAVELENGTH_MAD: cout<< "mad"<<" "<<endl;break;
377  case WAVELENGTH_DAFS: cout<< "dafs"<<" "<<endl;break;
378  case WAVELENGTH_LAUE: cout<< "laue"<<" "<<endl;break;
379  case WAVELENGTH_TOF: cout<< "Time Of Flight"<<" "<<endl;break;
380  }
381 }
382 
383 REAL Radiation::GetLinearPolarRate()const{return mLinearPolarRate;}
384 
385 void Radiation::SetLinearPolarRate(const REAL f){mLinearPolarRate=f;}
386 
387 void Radiation::InitOptions()
388 {
389  static string RadiationTypeName;
390  static string RadiationTypeChoices[3];
391  static string WavelengthTypeName;
392  static string WavelengthTypeChoices[3];
393 
394  static bool needInitNames=true;
395  if(true==needInitNames)
396  {
397  RadiationTypeName="Radiation";
398  RadiationTypeChoices[0]="Neutron";
399  RadiationTypeChoices[1]="X-Ray";
400  RadiationTypeChoices[2]="Electron";
401 
402  WavelengthTypeName="Spectrum";
403  WavelengthTypeChoices[0]="Monochromatic";
404  WavelengthTypeChoices[1]="X-Ray Tube";
405  WavelengthTypeChoices[2]="Time Of Flight";
406  //WavelengthTypeChoices[2]="MAD";
407  //WavelengthTypeChoices[3]="DAFS";
408  //WavelengthTypeChoices[4]="LAUE";
409 
410  needInitNames=false;//Only once for the class
411  }
412  mRadiationType.Init(3,&RadiationTypeName,RadiationTypeChoices);
413  mWavelengthType.Init(3,&WavelengthTypeName,WavelengthTypeChoices);
414  this->AddOption(&mRadiationType);
415  this->AddOption(&mWavelengthType);
416 
417  {//Fixed by default
418  RefinablePar tmp("Wavelength",mWavelength.data(),0.05,20.,
419  gpRefParTypeRadiationWavelength,REFPAR_DERIV_STEP_ABSOLUTE,
420  true,true,true,false,1.0);
421  tmp.SetDerivStep(1e-4);
422  tmp.AssignClock(mClockWavelength);
423  this->AddPar(tmp);
424  }
425  {//Fixed by default
426  RefinablePar tmp("XRayTubeDeltaLambda",&mXRayTubeDeltaLambda,0.001,20.,
427  gpRefParTypeRadiationWavelength,REFPAR_DERIV_STEP_ABSOLUTE,
428  true,true,true,false,1.0);
429  tmp.SetDerivStep(1e-4);
430  tmp.AssignClock(mClockWavelength);
431  this->AddPar(tmp);
432  }
433  {//Fixed by default
434  RefinablePar tmp("XRayTubeAlpha2Alpha1Ratio",&mXRayTubeAlpha2Alpha1Ratio,0.5,0.5,
435  gpRefParTypeRadiationWavelength,REFPAR_DERIV_STEP_ABSOLUTE,
436  true,true,true,false,1.0);
437  tmp.SetDerivStep(1e-4);
438  tmp.AssignClock(mClockWavelength);
439  this->AddPar(tmp);
440  }
441 }
442 
443 #ifdef __WX__CRYST__
444 WXCrystObjBasic* Radiation::WXCreate(wxWindow* parent)
445 {
446  //:TODO: Check mpWXCrystObj==0
447  mpWXCrystObj=new WXRadiation(parent,this);
448  return mpWXCrystObj;
449 }
450 #endif
451 
453 //
454 // ScatteringData
455 //
457 
458 ScatteringData::ScatteringData():
459 mNbRefl(0),
460 mpCrystal(0),mGlobalBiso(0),mUseFastLessPreciseFunc(false),
461 mIgnoreImagScattFact(false),mMaxSinThetaOvLambda(10)
462 {
463  VFN_DEBUG_MESSAGE("ScatteringData::ScatteringData()",10)
464  {//This should be done elsewhere...
465  RefinablePar tmp("Global Biso",&mGlobalBiso,-1.,1.,
466  gpRefParTypeScattPowTemperatureIso,REFPAR_DERIV_STEP_ABSOLUTE,
467  true,true,true,false,1.0);
468  tmp.SetDerivStep(1e-4);
469  tmp.AssignClock(mClockGlobalBiso);
470  this->AddPar(tmp);
471  }
472  mClockMaster.AddChild(mClockHKL);
473  mClockMaster.AddChild(mClockGlobalBiso);
474  mClockMaster.AddChild(mClockNbReflUsed);
475  mClockMaster.AddChild(mClockFhklObsSq);
476 }
477 
478 ScatteringData::ScatteringData(const ScatteringData &old):
479 mNbRefl(old.mNbRefl),
480 mpCrystal(old.mpCrystal),mUseFastLessPreciseFunc(old.mUseFastLessPreciseFunc),
481 //Do not copy temporary arrays
482 mClockHKL(old.mClockHKL),
483 mIgnoreImagScattFact(old.mIgnoreImagScattFact),
484 mMaxSinThetaOvLambda(old.mMaxSinThetaOvLambda)
485 {
486  VFN_DEBUG_MESSAGE("ScatteringData::ScatteringData(&old)",10)
487  mClockStructFactor.Reset();
488  mClockTheta.Reset();
489  mClockScattFactor.Reset();
490  mClockScattFactorResonant.Reset();
491  mClockThermicFact.Reset();
492  this->SetHKL(old.GetH(),old.GetK(),old.GetL());
493  VFN_DEBUG_MESSAGE("ScatteringData::ScatteringData(&old):End",5)
494  {//This should be done elsewhere...
495  RefinablePar tmp("Global Biso",&mGlobalBiso,-1.,1.,
496  gpRefParTypeScattPowTemperatureIso,REFPAR_DERIV_STEP_ABSOLUTE,
497  true,true,true,false,1.0);
498  tmp.SetDerivStep(1e-4);
499  tmp.AssignClock(mClockGlobalBiso);
500  this->AddPar(tmp);
501  }
502  mClockMaster.AddChild(mClockHKL);
503  mClockMaster.AddChild(mClockGlobalBiso);
504  mClockMaster.AddChild(mClockNbReflUsed);
505  mClockMaster.AddChild(mClockFhklObsSq);
506 }
507 
508 ScatteringData::~ScatteringData()
509 {
510  VFN_DEBUG_MESSAGE("ScatteringData::~ScatteringData()",10)
511 }
512 
513 void ScatteringData::SetHKL(const CrystVector_REAL &h,
514  const CrystVector_REAL &k,
515  const CrystVector_REAL &l)
516 {
517  const_cast<const ScatteringData*>(this)->ScatteringData::SetHKL(h,k,l);
518 }
519 
520 void ScatteringData::SetHKL(const CrystVector_REAL &h,
521  const CrystVector_REAL &k,
522  const CrystVector_REAL &l) const
523 {
524  VFN_DEBUG_ENTRY("ScatteringData::SetHKL(h,k,l)",5)
525  mNbRefl=h.numElements();
526  mH=h;
527  mK=k;
528  mL=l;
529  mClockHKL.Click();
530  this->PrepareHKLarrays();
531  VFN_DEBUG_EXIT("ScatteringData::SetHKL(h,k,l):End",5)
532 }
533 
534 void ScatteringData::GenHKLFullSpace2(const REAL maxSTOL,const bool unique)
535 {
536  const_cast<const ScatteringData*>(this)->ScatteringData::GenHKLFullSpace2(maxSTOL, unique);
537 }
538 
539 void ScatteringData::GenHKLFullSpace2(const REAL maxSTOL,const bool unique) const
540 {
541  //(*fpObjCrystInformUser)("Generating Full HKL list...");
542  VFN_DEBUG_ENTRY("ScatteringData::GenHKLFullSpace2()",5)
543  TAU_PROFILE("ScatteringData::GenHKLFullSpace2()","void (REAL,bool)",TAU_DEFAULT);
544  if(0==mpCrystal)
545  {
546  throw ObjCrystException("ScatteringData::GenHKLFullSpace2() \
547  no crystal assigned yet to this ScatteringData object.");
548  }
549  cctbx::uctbx::unit_cell uc=cctbx::uctbx::unit_cell(scitbx::af::double6(mpCrystal->GetLatticePar(0),
552  mpCrystal->GetLatticePar(3)*RAD2DEG,
553  mpCrystal->GetLatticePar(4)*RAD2DEG,
554  mpCrystal->GetLatticePar(5)*RAD2DEG));
555  cctbx::miller::index_generator igen(uc,
556  this->GetCrystal().GetSpaceGroup().GetCCTbxSpg().type(),
557  !(this->IsIgnoringImagScattFact()),
558  1/(2*maxSTOL));
559  if(unique)
560  {
561  mNbRefl=0;
562  CrystVector_long H(mNbRefl);
563  CrystVector_long K(mNbRefl);
564  CrystVector_long L(mNbRefl);
565  mMultiplicity.resize(mNbRefl);
566  for(;;)
567  {
568  if(mNbRefl==H.numElements())
569  {
570  H.resizeAndPreserve(mNbRefl+100);
571  K.resizeAndPreserve(mNbRefl+100);
572  L.resizeAndPreserve(mNbRefl+100);
573  mMultiplicity.resizeAndPreserve(mNbRefl+100);
574  }
575  cctbx::miller::index<> h = igen.next();
576  if (h.is_zero()) break;
577  H(mNbRefl)=h[0];
578  K(mNbRefl)=h[1];
579  L(mNbRefl)=h[2];
580  cctbx::miller::sym_equiv_indices sei(this->GetCrystal().GetSpaceGroup().GetCCTbxSpg(),h);
581  mMultiplicity(mNbRefl)=sei.multiplicity(!(this->IsIgnoringImagScattFact()));
582  mNbRefl++;
583  }
584  H.resizeAndPreserve(mNbRefl);
585  K.resizeAndPreserve(mNbRefl);
586  L.resizeAndPreserve(mNbRefl);
587  mMultiplicity.resizeAndPreserve(mNbRefl);
588  this->SetHKL(H,K,L);
589  this->SortReflectionBySinThetaOverLambda(maxSTOL);
590  }
591  else
592  {
593  mNbRefl=0;
594  CrystVector_long H(mNbRefl);
595  CrystVector_long K(mNbRefl);
596  CrystVector_long L(mNbRefl);
597  mMultiplicity.resize(mNbRefl);
598  for(;;)
599  {
600  cctbx::miller::index<> h = igen.next();
601  if (h.is_zero()) break;
602  cctbx::miller::sym_equiv_indices sei(this->GetCrystal().GetSpaceGroup().GetCCTbxSpg(),h);
603  for(int i=0;i<sei.multiplicity(true);i++)
604  {
605  cctbx::miller::index<> k = sei(i).h();
606  if(mNbRefl==H.numElements())
607  {
608  H.resizeAndPreserve(mNbRefl+100);
609  K.resizeAndPreserve(mNbRefl+100);
610  L.resizeAndPreserve(mNbRefl+100);
611  mMultiplicity.resizeAndPreserve(mNbRefl+100);
612  }
613  mMultiplicity(mNbRefl)=sei.multiplicity(!(this->IsIgnoringImagScattFact()));
614  H(mNbRefl)=k[0];
615  K(mNbRefl)=k[1];
616  L(mNbRefl++)=k[2];
617  }
618  }
619  H.resizeAndPreserve(mNbRefl);
620  K.resizeAndPreserve(mNbRefl);
621  L.resizeAndPreserve(mNbRefl);
622  mMultiplicity.resizeAndPreserve(mNbRefl);
623  this->SetHKL(H,K,L);
624  this->SortReflectionBySinThetaOverLambda(maxSTOL);
625  }
626  mClockHKL.Click();
627  /*{
628  char buf [200];
629  sprintf(buf,"Generating Full HKL list...Done (kept %d reflections)",(int)mNbRefl);
630  (*fpObjCrystInformUser)((string)buf);
631  }*/
632  VFN_DEBUG_EXIT("ScatteringData::GenHKLFullSpace2():End",5)
633 }
634 
635 void ScatteringData::GenHKLFullSpace(const REAL maxTheta,const bool useMultiplicity)
636 {
637  const_cast<const ScatteringData*>(this)->ScatteringData::GenHKLFullSpace(maxTheta, useMultiplicity);
638 }
639 
640 void ScatteringData::GenHKLFullSpace(const REAL maxTheta,const bool useMultiplicity) const
641 {
642  VFN_DEBUG_ENTRY("ScatteringData::GenHKLFullSpace()",5)
643  if(this->GetRadiation().GetWavelength()(0) <=.01)
644  {
645  throw ObjCrystException("ScatteringData::GenHKLFullSpace() \
646  no wavelength assigned yet to this ScatteringData object.");;
647  }
648  this->GenHKLFullSpace2(sin(maxTheta)/this->GetRadiation().GetWavelength()(0),useMultiplicity);
649  VFN_DEBUG_EXIT("ScatteringData::GenHKLFullSpace()",5)
650 }
651 
653 
655 {
656  VFN_DEBUG_MESSAGE("ScatteringData::SetCrystal()",5)
657  if(mpCrystal!=0) mpCrystal->DeRegisterClient(*this);
658  mpCrystal=&crystal;
659  this->AddSubRefObj(crystal);
660  crystal.RegisterClient(*this);
666 }
668 
670 
671 bool ScatteringData::HasCrystal()const {return mpCrystal!=0;}
672 
673 long ScatteringData::GetNbRefl() const {return mNbRefl;}
674 
675 const CrystVector_REAL& ScatteringData::GetH() const {return mH;}
676 const CrystVector_REAL& ScatteringData::GetK() const {return mK;}
677 const CrystVector_REAL& ScatteringData::GetL() const {return mL;}
678 
679 const CrystVector_REAL& ScatteringData::GetH2Pi() const {return mH2Pi;}
680 const CrystVector_REAL& ScatteringData::GetK2Pi() const {return mK2Pi;}
681 const CrystVector_REAL& ScatteringData::GetL2Pi() const {return mH2Pi;}
682 
683 const CrystVector_REAL& ScatteringData::GetReflX() const
684 {
685  VFN_DEBUG_ENTRY("ScatteringData::GetReflX()",1)
686  this->CalcSinThetaLambda();
687  VFN_DEBUG_EXIT("ScatteringData::GetReflX()",1)
688  return mX;
689 }
690 const CrystVector_REAL& ScatteringData::GetReflY() const
691 {
692  VFN_DEBUG_ENTRY("ScatteringData::GetReflY()",1)
693  this->CalcSinThetaLambda();
694  VFN_DEBUG_EXIT("ScatteringData::GetReflY()",1)
695  return mY;
696 }
697 const CrystVector_REAL& ScatteringData::GetReflZ() const
698 {
699  VFN_DEBUG_ENTRY("ScatteringData::GetReflZ()",1)
700  this->CalcSinThetaLambda();
701  VFN_DEBUG_EXIT("ScatteringData::GetReflZ()",1)
702  return mZ;
703 }
704 
705 const CrystVector_REAL& ScatteringData::GetSinThetaOverLambda()const
706 {
707  VFN_DEBUG_ENTRY("ScatteringData::GetSinThetaOverLambda()",1)
708  this->CalcSinThetaLambda();
709  VFN_DEBUG_EXIT("ScatteringData::GetSinThetaOverLambda()",1)
710  return mSinThetaLambda;
711 }
712 
713 const CrystVector_REAL& ScatteringData::GetTheta()const
714 {
715  VFN_DEBUG_ENTRY("ScatteringData::GetTheta()",1)
716  this->CalcSinThetaLambda();
717  VFN_DEBUG_EXIT("ScatteringData::GetTheta()",1)
718  return mTheta;
719 }
720 
722 {
723  return mClockTheta;
724 }
725 
726 const CrystVector_REAL& ScatteringData::GetFhklCalcSq() const
727 {
728  VFN_DEBUG_ENTRY("ScatteringData::GetFhklCalcSq()",2)
729  this->CalcStructFactor();
731  #ifdef __LIBCRYST_VECTOR_USE_BLITZ__
732  mFhklCalcSq=pow2(mFhklCalcReal)+pow2(mFhklCalcImag);
733  #else
734  const REAL *pr,*pi;
735  REAL *p;
736  pr=mFhklCalcReal.data();
737  pi=mFhklCalcImag.data();
738  p=mFhklCalcSq.data();
739  for(long i=0;i<mNbReflUsed;i++)
740  {
741  *p++ = *pr * *pr + *pi * *pi;
742  pr++;
743  pi++;
744  }
745  for(long i=mNbReflUsed;i<mNbRefl;i++) *p++ = 0;
746  #endif
748  VFN_DEBUG_EXIT("ScatteringData::GetFhklCalcSq()",2)
749  return mFhklCalcSq;
750 }
751 
752 std::map<RefinablePar*, CrystVector_REAL>& ScatteringData::GetFhklCalcSq_FullDeriv(std::set<RefinablePar *> &vPar)
753 {
754  TAU_PROFILE("ScatteringData::GetFhklCalcSq_FullDeriv()","void ()",TAU_DEFAULT);
755  VFN_DEBUG_ENTRY("ScatteringData::GetFhklCalcSq()",2)
756  this->CalcStructFactor_FullDeriv(vPar);
757  mFhklCalcSq_FullDeriv[0]=this->GetFhklCalcSq();
758  mFhklCalcSq_FullDeriv.clear();// :TODO: avoid complete clear
759  const REAL *pr,*pi,*prd,*pid;
760  REAL *p;
761  for(std::set<RefinablePar *>::iterator par=vPar.begin();par!=vPar.end();par++)
762  {
763  if((*par)==0) continue;
764  if(mFhklCalcReal_FullDeriv[*par].size()==0)
765  {
766  mFhklCalcSq_FullDeriv[*par].resize(0);
767  continue;
768  }
769  mFhklCalcSq_FullDeriv[*par].resize(mNbRefl);//Should use mNbRefleUsed instead ?
770  pr=mFhklCalcReal.data();
771  pi=mFhklCalcImag.data();
772  prd=mFhklCalcReal_FullDeriv[*par].data();
773  pid=mFhklCalcImag_FullDeriv[*par].data();
774  p=mFhklCalcSq_FullDeriv[*par].data();
775  for(long i=0;i<mNbReflUsed;i++)
776  *p++ = 2*(*pr++ * *prd++ + *pi++ * *pid++);
777  for(long i=mNbReflUsed;i<mNbRefl;i++) *p++ = 0;
778  }
779  VFN_DEBUG_EXIT("ScatteringData::GetFhklCalcSq()",2)
780  return mFhklCalcSq_FullDeriv;
781 }
782 
783 const CrystVector_REAL& ScatteringData::GetFhklCalcReal() const
784 {
785  VFN_DEBUG_ENTRY("ScatteringData::GetFhklCalcReal()",2)
786  this->CalcStructFactor();
787  VFN_DEBUG_EXIT("ScatteringData::GetFhklCalcReal()",2)
788  return mFhklCalcReal;
789 }
790 
791 const CrystVector_REAL& ScatteringData::GetFhklCalcImag() const
792 {
793  VFN_DEBUG_ENTRY("ScatteringData::GetFhklCalcImag()",2)
794  this->CalcStructFactor();
795  VFN_DEBUG_EXIT("ScatteringData::GetFhklCalcImag()",2)
796  return mFhklCalcImag;
797 }
798 
799 const CrystVector_REAL& ScatteringData::GetFhklObsSq() const
800 {
801  return mFhklObsSq;
802 }
803 
804 void ScatteringData::SetFhklObsSq(const CrystVector_REAL &obs)
805 {
806  if(obs.numElements() != mNbRefl)
807  throw ObjCrystException("ScatteringData::SetFhklObsSq(): incorrect number of reflections !");
808  mFhklObsSq = obs;
810 }
811 
812 const map<const ScatteringPower*,CrystVector_REAL>& ScatteringData::GetScatteringFactor() const
813 {
814  this->CalcScattFactor();
815  return mvScatteringFactor;
816 }
817 
818 CrystVector_REAL ScatteringData::GetWavelength()const {return this->GetRadiation().GetWavelength();}
819 #if 0
820 void ScatteringData::SetUseFastLessPreciseFunc(const bool useItOrNot)
821 {
822  mUseFastLessPreciseFunc=useItOrNot;
825 }
826 #endif
828 {
829  VFN_DEBUG_MESSAGE("ScatteringData::SetIsIgnoringImagScattFact():"<<b,10)
833 }
835 
836 void ScatteringData::PrintFhklCalc(ostream &os)const
837 {
838  VFN_DEBUG_ENTRY("ScatteringData::PrintFhklCalc()",5)
839  this->GetFhklCalcSq();
840  CrystVector_REAL theta;
841  theta=mTheta;
842  theta *= RAD2DEG;
843  os <<" Number of reflections:"<<mNbRefl<<endl;
844  os <<" H K L F(hkl)^2 Re(F) Im(F)";
845  os <<" Theta 1/2d"<<endl;
846  os << FormatVertVectorHKLFloats<REAL>
847  (mH,mK,mL,mFhklCalcSq,mFhklCalcReal,mFhklCalcImag,theta,mSinThetaLambda,12,4,mNbReflUsed);
848  VFN_DEBUG_EXIT("ScatteringData::PrintFhklCalc()",5)
849 }
850 
852 {
853  VFN_DEBUG_ENTRY("ScatteringData::PrintFhklCalcDetail()",5)
854  this->GetFhklCalcSq();
855  CrystVector_REAL theta;
856  theta=mTheta;
857  theta *= RAD2DEG;
858  vector<const CrystVector_REAL *> v;
859  v.push_back(&mH);
860  v.push_back(&mK);
861  v.push_back(&mL);
862  v.push_back(&mSinThetaLambda);
863  v.push_back(&theta);
864  v.push_back(&mFhklCalcSq);
865  v.push_back(&mFhklCalcReal);
866  v.push_back(&mFhklCalcImag);
867  os <<" Number of reflections:"<<mNbRefl<<endl;
868  os <<" H K L 1/2d Theta F(hkl)^2";
869  os <<" Re(F) Im(F) ";
870  vector<CrystVector_REAL> sf;
871  sf.resize(mvRealGeomSF.size()*2);
872  long i=0;
873  for(map<const ScatteringPower*,CrystVector_REAL>::const_iterator
874  pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos)
875  {
876  os << FormatString("Re(F)_"+pos->first->GetName(),14)
877  << FormatString("Im(F)_"+pos->first->GetName(),14);
878  cout<<pos->first->GetName()<<":"<<pos->first->GetForwardScatteringFactor(RAD_XRAY)<<endl;
879  sf[2*i] = mvRealGeomSF[pos->first];
880  sf[2*i] *= mvScatteringFactor[pos->first];
881  sf[2*i] *= mvTemperatureFactor[pos->first];
882  sf[2*i+1] = mvImagGeomSF[pos->first];
883  sf[2*i+1] *= mvScatteringFactor[pos->first];
884  sf[2*i+1] *= mvTemperatureFactor[pos->first];
885  v.push_back(&(sf[2*i]));
886  v.push_back(&(sf[2*i+1]));
887  //v.push_back(mvRealGeomSF[pos->first]);
888  //v.push_back(mvImagGeomSF[pos->first]);
889  //v.push_back(mvScatteringFactor[pos->first]);
890  i++;
891  }
892  os<<endl;
893  os << FormatVertVectorHKLFloats<REAL>(v,12,4,mNbReflUsed);
894  VFN_DEBUG_EXIT("ScatteringData::PrintFhklCalcDetail()",5)
895 }
896 
897 void ScatteringData::BeginOptimization(const bool allowApproximations,
898  const bool enableRestraints)
899 {
900  if(mUseFastLessPreciseFunc!=allowApproximations)
901  {
905  }
906  mUseFastLessPreciseFunc=allowApproximations;
907  this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints);
908 }
910 {
911  if(mOptimizationDepth==1)
912  {
913  if(mUseFastLessPreciseFunc==true)
914  {
918  }
920  }
922 }
923 
925 {
926  if(mUseFastLessPreciseFunc!=allow)
927  {
931  }
934 }
935 
937 {
938  VFN_DEBUG_ENTRY("ScatteringData::PrepareHKLarrays()"<<mNbRefl<<" reflections",5)
939  mFhklCalcReal.resize(mNbRefl);
940  mFhklCalcImag.resize(mNbRefl);
941  mFhklCalcSq.resize(mNbRefl);
942  mFhklCalcReal=0;
943  mFhklCalcImag=0;
944  mFhklCalcSq=0;
945 
946  mIntH=mH;
947  mIntK=mK;
948  mIntL=mL;
949 
950  mH2Pi=mH;
951  mK2Pi=mK;
952  mL2Pi=mL;
953  mH2Pi*=(2*M_PI);
954  mK2Pi*=(2*M_PI);
955  mL2Pi*=(2*M_PI);
956 
957  // If we extracted some intensities, try to keep them.
958  // Do not do this if the number of reflections changed too much, if there is no crystal
959  // structure associated, or if the spacegroup changed.
960  bool noSpgChange=false;
962  if( (mFhklObsSq.numElements()>0) && (abs(mFhklObsSq.numElements()-mNbRefl)<(0.1*mNbRefl)) && (noSpgChange) )
963  mFhklObsSq.resizeAndPreserve(mNbRefl);
964  else mFhklObsSq.resize(0);
966 
968 
970  for(long i=0;i<mNbRefl;i++)
971  {
974  }
975  /*
976  {
977  mpCrystal->GetSpaceGroup().Print();
978  for(long i=0;i<mNbRefl;i++)
979  {
980  cout<<mIntH(i)<<" "<<mIntK(i)<<" "<<mIntL(i)<<" "<<mExpectedIntensityFactor(i)<<endl;
981  }
982  }
983  */
984 
985  mClockHKL.Click();
986  VFN_DEBUG_EXIT("ScatteringData::PrepareHKLarrays()"<<mNbRefl<<" reflections",5)
987 }
988 
992 {
993  if(this->IsBeingRefined()) return mNbReflUsed;
994  VFN_DEBUG_MESSAGE("ScatteringData::GetNbReflBelowMaxSinThetaOvLambda()",4)
995  this->CalcSinThetaLambda();
996  if((mNbReflUsed>0)&&(mNbReflUsed<mNbRefl))
997  {
1000  }
1001 
1003  return mNbReflUsed;
1004  long i;
1005  for(i=0;i<mNbRefl;i++) if(mSinThetaLambda(i)>mMaxSinThetaOvLambda) break;
1006  if(i!=mNbReflUsed)
1007  {
1008  mNbReflUsed=i;
1010  VFN_DEBUG_MESSAGE("->Changed Max sin(theta)/lambda="<<mMaxSinThetaOvLambda\
1011  <<" nb refl="<<mNbReflUsed,4)
1012  }
1013  return mNbReflUsed;
1014 }
1016 {return mClockNbReflUsed;}
1017 
1018 CrystVector_long ScatteringData::SortReflectionBySinThetaOverLambda(const REAL maxSTOL) const
1019 {
1020  TAU_PROFILE("ScatteringData::SortReflectionBySinThetaOverLambda()","void ()",TAU_DEFAULT);
1021  VFN_DEBUG_ENTRY("ScatteringData::SortReflectionBySinThetaOverLambda()",5)
1022  this->CalcSinThetaLambda();
1023  CrystVector_long sortedSubs;
1024  sortedSubs=SortSubs(mSinThetaLambda);
1025  CrystVector_long oldH,oldK,oldL,oldMult;
1026  oldH=mH;
1027  oldK=mK;
1028  oldL=mL;
1029  oldMult=mMultiplicity;
1030  long subs;
1031  long shift=0;
1032 
1033  //get rid of [0,0,0] reflection
1034  VFN_DEBUG_MESSAGE("ScatteringData::SortReflectionBySinThetaOverLambda() 1",2)
1035  if(0==mSinThetaLambda(sortedSubs(0)))
1036  {
1037  shift=1;
1038  mNbRefl -= 1;
1039  mH.resize(mNbRefl);
1040  mK.resize(mNbRefl);
1041  mL.resize(mNbRefl);
1042  mMultiplicity.resize(mNbRefl);
1043  }
1044  VFN_DEBUG_MESSAGE("ScatteringData::SortReflectionBySinThetaOverLambda() 2",2)
1045  for(long i=0;i<mNbRefl;i++)
1046  {
1047  subs=sortedSubs(i+shift);
1048  mH(i)=oldH(subs);
1049  mK(i)=oldK(subs);
1050  mL(i)=oldL(subs);
1051  mMultiplicity(i)=oldMult(subs);
1052  }
1053  mClockHKL.Click();
1054  VFN_DEBUG_MESSAGE("ScatteringData::SortReflectionBySinThetaOverLambda() 3",2)
1055  this->PrepareHKLarrays();
1056  this->CalcSinThetaLambda();
1057 
1058  VFN_DEBUG_MESSAGE("ScatteringData::SortReflectionBySinThetaOverLambda() 4",2)
1059  if(0<maxSTOL)
1060  {
1061  VFN_DEBUG_MESSAGE("ScatteringData::SortReflectionBySinThetaOverLambda() 5"<<maxSTOL,2)
1062  long maxSubs=0;
1063  VFN_DEBUG_MESSAGE(" "<< mIntH(maxSubs)<<" "<< mIntK(maxSubs)<<" "<< mIntL(maxSubs)<<" "<<mSinThetaLambda(maxSubs),1)
1064  for(maxSubs=0;mSinThetaLambda(maxSubs)<maxSTOL;maxSubs++)
1065  {
1066  VFN_DEBUG_MESSAGE(" "<< mIntH(maxSubs)<<" "<< mIntK(maxSubs)<<" "<< mIntL(maxSubs)<<" "<<mSinThetaLambda(maxSubs),1)
1067  if(maxSubs==(mNbRefl-1))
1068  {
1069  maxSubs=mNbRefl;
1070  break;
1071  }
1072  }
1073  if(maxSubs==mNbRefl)
1074  {
1075  VFN_DEBUG_EXIT("ScatteringData::SortReflectionBySinThetaOverLambda():"<<mNbRefl<<" reflections",5)
1076  return sortedSubs;
1077  }
1078  mNbRefl=maxSubs;
1079  mH.resizeAndPreserve(mNbRefl);
1080  mK.resizeAndPreserve(mNbRefl);
1081  mL.resizeAndPreserve(mNbRefl);
1082  mMultiplicity.resizeAndPreserve(mNbRefl);
1083  sortedSubs.resizeAndPreserve(mNbRefl);
1084  mClockHKL.Click();
1085  this->PrepareHKLarrays();
1086  }
1087  VFN_DEBUG_EXIT("ScatteringData::SortReflectionBySinThetaOverLambda():"<<mNbRefl<<" reflections",5)
1088  return sortedSubs;
1089 }
1090 
1092 {
1093  TAU_PROFILE("ScatteringData::EliminateExtinctReflections()","void ()",TAU_DEFAULT);
1094  VFN_DEBUG_ENTRY("ScatteringData::EliminateExtinctReflections()",7)
1095 
1096  long nbKeptRefl=0;
1097  CrystVector_long subscriptKeptRefl(mNbRefl);
1098  subscriptKeptRefl=0;
1099  for(long j=0;j<mNbRefl;j++)
1100  {
1101  if( this->GetCrystal().GetSpaceGroup().IsReflSystematicAbsent(mH(j),mK(j),mL(j))==false )
1102  subscriptKeptRefl(nbKeptRefl++)=j;
1103  }
1104  VFN_DEBUG_MESSAGE("ScatteringData::EliminateExtinctReflections():4",5)
1105  //Keep only the elected reflections
1106  mNbRefl=nbKeptRefl;
1107  {
1108  CrystVector_long oldH,oldK,oldL;
1109  CrystVector_int oldMulti;
1110  long subs;
1111 
1112  oldH=mH;
1113  oldK=mK;
1114  oldL=mL;
1115  oldMulti=mMultiplicity;
1116 
1117  mMultiplicity.resize(mNbRefl);
1118  mH.resize(mNbRefl);
1119  mK.resize(mNbRefl);
1120  mL.resize(mNbRefl);
1121  for(long i=0;i<mNbRefl;i++)
1122  {
1123  subs=subscriptKeptRefl(i);
1124  mH(i)=oldH(subs);
1125  mK(i)=oldK(subs);
1126  mL(i)=oldL(subs);
1127  mMultiplicity(i)=oldMulti(subs);
1128  }
1129  }
1130  this->PrepareHKLarrays();
1131  VFN_DEBUG_EXIT("ScatteringData::EliminateExtinctReflections():End",7)
1132  return subscriptKeptRefl;
1133 }
1134 
1136 {
1137  if(mClockTheta>mClockMaster) return;
1138  if( 0 == mpCrystal) throw ObjCrystException("ScatteringData::CalcSinThetaLambda() \
1139  Cannot compute sin(theta)/lambda : there is no crystal affected to this \
1140  ScatteringData object yet.");
1141 
1142  if( 0 == this->GetNbRefl()) throw ObjCrystException("ScatteringData::CalcSinThetaLambda() \
1143  Cannot compute sin(theta)/lambda : there are no reflections !");
1144 
1145  if( (mClockTheta>this->GetRadiation().GetClockWavelength())
1149 
1150  VFN_DEBUG_ENTRY("ScatteringData::CalcSinThetaLambda()",3)
1151  TAU_PROFILE("ScatteringData::CalcSinThetaLambda()","void (bool)",TAU_DEFAULT);
1152  mSinThetaLambda.resize(mNbRefl);
1153 
1154  const CrystMatrix_REAL bMatrix= this->GetBMatrix();
1155  mX.resize(this->GetNbRefl());
1156  mY.resize(this->GetNbRefl());
1157  mZ.resize(this->GetNbRefl());
1158  for(int i=0;i<this->GetNbRefl();i++)
1159  { //:TODO: faster,nicer
1160  mX(i)=bMatrix(0,0)*mH(i)+bMatrix(0,1)*mK(i)+bMatrix(0,2)*mL(i);
1161  mY(i)=bMatrix(1,0)*mH(i)+bMatrix(1,1)*mK(i)+bMatrix(1,2)*mL(i);
1162  mZ(i)=bMatrix(2,0)*mH(i)+bMatrix(2,1)*mK(i)+bMatrix(2,2)*mL(i);
1163  }
1164  //cout << bMatrix << endl << xyz<<endl;
1165  for(int i=0;i< (this->GetNbRefl());i++)
1166  mSinThetaLambda(i)=sqrt(pow(mX(i),2)+pow(mY(i),2)+pow(mZ(i),2))/2;
1167 
1168  #if 0
1169  // Direct calculation from a,b,c,alpha,beta,gamma
1170  const REAL a=mpCrystal->GetLatticePar(0);
1171  const REAL b=mpCrystal->GetLatticePar(1);
1172  const REAL c=mpCrystal->GetLatticePar(2);
1173  const REAL ca=cos(mpCrystal->GetLatticePar(3));
1174  const REAL sa=sin(mpCrystal->GetLatticePar(3));
1175  const REAL cb=cos(mpCrystal->GetLatticePar(4));
1176  const REAL sb=sin(mpCrystal->GetLatticePar(4));
1177  const REAL cg=cos(mpCrystal->GetLatticePar(5));
1178  const REAL sg=sin(mpCrystal->GetLatticePar(5));
1179  for(int i=0;i< (this->GetNbRefl());i++)
1180  {
1181  const REAL h=mH(i),k=mK(i),l=mL(i);
1182  mSinThetaLambda(i)=0.5*sqrt((h*h/(a*a)*sa*sa+k*k/(b*b)*sb*sb+l*l/(c*c)*sg*sg+2*k*l/(b*c)*(cb*cg-ca)+2*l*h/(c*a)*(cg*ca-cb)+2*h*k/(a*b)*(ca*cb-cg))/(1-ca*ca-cb*cb-cg*cg+2*ca*cb*cg));
1183  }
1184  #endif
1185 
1186 
1187  if(this->GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF)
1188  {
1189  if(this->GetRadiation().GetWavelength()(0) > 0)
1190  {
1191  mTheta.resize(mNbRefl);
1192  for(int i=0;i< (this->GetNbRefl());i++)
1193  {
1194  if( (mSinThetaLambda(i)*this->GetRadiation().GetWavelength()(0))>1)
1195  {
1196  //:KLUDGE: :TODO:
1197  mTheta(i)=M_PI;
1198  /*
1199  ofstream out("log.txt");
1200  out << "Error when computing Sin(theta) :"
1201  << "i="<<i<<" ,mSinThetaLambda(i)="<<mSinThetaLambda(i)
1202  << " ,this->GetRadiation().GetWavelength()(0)="
1203  << this->GetRadiation().GetWavelength()(0)
1204  << " ,H="<<mH(i)
1205  << " ,K="<<mK(i)
1206  << " ,L="<<mL(i)
1207  <<endl;
1208  out.close();
1209  abort();
1210  */
1211  }
1212  else
1213  {
1214  mTheta(i)=asin(mSinThetaLambda(i)*this->GetRadiation().GetWavelength()(0));
1215  }
1216  }
1217  } else
1218  {
1219  cout << "Wavelength not given in ScatteringData::CalcSinThetaLambda() !" <<endl;
1220  throw 0;
1221  }
1222  }
1223  else mTheta.resize(0);
1224 
1225  mClockTheta.Click();
1226  VFN_DEBUG_EXIT("ScatteringData::CalcSinThetaLambda()",3)
1227 }
1228 
1229 REAL ScatteringData::CalcSinThetaLambda(REAL h, REAL k, REAL l)const
1230 {
1231  const CrystMatrix_REAL bMatrix= this->GetBMatrix();
1232  const REAL x=bMatrix(0,0)*h+bMatrix(0,1)*k+bMatrix(0,2)*l;
1233  const REAL y=bMatrix(1,0)*h+bMatrix(1,1)*k+bMatrix(1,2)*l;
1234  const REAL z=bMatrix(2,0)*h+bMatrix(2,1)*k+bMatrix(2,2)*l;
1235  return sqrt(x*x+y*y+z*z)/2;
1236 }
1237 
1238 const CrystMatrix_REAL& ScatteringData::GetBMatrix() const
1239 {
1240  return this->GetCrystal().GetBMatrix();
1241 }
1242 
1244 {
1245  //if(mClockScattFactor>mClockMaster) return;
1246  if( (mClockScattFactor>this->GetRadiation().GetClockWavelength())
1251  TAU_PROFILE("ScatteringData::CalcScattFactor()","void (bool)",TAU_DEFAULT);
1252  VFN_DEBUG_ENTRY("ScatteringData::CalcScattFactor()",4)
1253  this->CalcResonantScattFactor();
1254  mvScatteringFactor.clear();
1255  for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--)
1256  {
1257  const ScatteringPower *pScattPow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i));
1258  mvScatteringFactor[pScattPow]=pScattPow->GetScatteringFactor(*this);
1259  //Directly add Fprime
1260  mvScatteringFactor[pScattPow]+= this->mvFprime[pScattPow];
1261  VFN_DEBUG_MESSAGE("-> H K L sin(t/l) f0+f'"
1263  mvScatteringFactor[pScattPow],10,4,mNbReflUsed),1);
1264  }
1266  VFN_DEBUG_EXIT("ScatteringData::CalcScattFactor()",4)
1267 }
1268 
1270 {
1271  //if(mClockThermicFact>mClockMaster) return;
1272  if( (mClockThermicFact>this->GetRadiation().GetClockWavelength())
1277  TAU_PROFILE("ScatteringData::CalcTemperatureFactor()","void (bool)",TAU_DEFAULT);
1278  VFN_DEBUG_ENTRY("ScatteringData::CalcTemperatureFactor()",4)
1279  mvTemperatureFactor.clear();
1280  for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--)
1281  {
1282  const ScatteringPower *pScattPow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i));
1283  mvTemperatureFactor[pScattPow]=pScattPow->GetTemperatureFactor(*this);
1284  VFN_DEBUG_MESSAGE("-> H K L sin(t/l) DebyeWaller"<<endl
1286  mvTemperatureFactor[pScattPow],10,4,mNbReflUsed),1);
1287  }
1289  VFN_DEBUG_EXIT("ScatteringData::CalcTemperatureFactor()",4)
1290 }
1291 
1293 {
1295  &&(mClockScattFactorResonant>this->GetRadiation().GetClockWavelength())) return;
1296  VFN_DEBUG_ENTRY("ScatteringData::CalcResonantScattFactor()",4)
1297  TAU_PROFILE("ScatteringData::CalcResonantScattFactor()","void (bool)",TAU_DEFAULT);
1298 
1299  mvFprime.clear();
1300  mvFsecond.clear();
1301  if(this->GetRadiation().GetWavelength()(0) == 0)
1302  {
1303  VFN_DEBUG_EXIT("ScatteringData::CalcResonantScattFactor()->Lambda=0. fprime=fsecond=0",4)
1304  return;
1305  }
1306  else
1307  {
1308  for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--)
1309  {
1310  const ScatteringPower *pScattPow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i));
1311  mvFprime [pScattPow]=pScattPow->GetResonantScattFactReal(*this)(0);
1312  mvFsecond[pScattPow]=pScattPow->GetResonantScattFactImag(*this)(0);
1313  }
1314  }
1316  VFN_DEBUG_EXIT("ScatteringData::CalcResonantScattFactor()",4)
1317 }
1318 
1320 {
1321  this->GetNbReflBelowMaxSinThetaOvLambda();//update mNbReflUsed, also recalc sin(theta)/lambda
1327  VFN_DEBUG_MESSAGE("ScatteringData::CalcGlobalTemperatureFactor()",2)
1328  TAU_PROFILE("ScatteringData::CalcGlobalTemperatureFactor()","void ()",TAU_DEFAULT);
1329 
1331  //if(true==mUseFastLessPreciseFunc) //:TODO:
1332  {
1333  }
1334  //else
1335  {
1336  const REAL *stol=this->GetSinThetaOverLambda().data();
1337  REAL *fact=mGlobalTemperatureFactor.data();
1338  for(long i=0;i<mNbReflUsed;i++) {*fact++ = exp(-mGlobalBiso * *stol * *stol);stol++;}
1339  }
1341 }
1342 
1344 {
1345  this->GetNbReflBelowMaxSinThetaOvLambda();//check mNbReflUsed, also recalc sin(theta)/lambda
1346  if(mClockStructFactor>mClockMaster) return;
1347 
1348  //:TODO: Anisotropic Thermic factors
1349  //TAU_PROFILE_TIMER(timer1,"ScatteringData::CalcStructFactor1:Prepare","", TAU_FIELD);
1350  //TAU_PROFILE_TIMER(timer2,"ScatteringData::CalcStructFactor2:GeomStructFact","", TAU_FIELD);
1351  //TAU_PROFILE_TIMER(timer3,"ScatteringData::CalcStructFactor3:Scatt.Factors","", TAU_FIELD);
1352  //TAU_PROFILE_TIMER(timer4,"ScatteringData::CalcStructFactor4:Finish,DynCorr","", TAU_FIELD);
1353 
1354  //TAU_PROFILE_START(timer1);
1355 
1356  const long nbRefl=this->GetNbRefl();
1357  this->CalcSinThetaLambda();
1358  //TAU_PROFILE_STOP(timer1);
1359  //TAU_PROFILE_START(timer2);
1360  this->CalcGeomStructFactor();
1361  //TAU_PROFILE_STOP(timer2);
1362  //TAU_PROFILE_START(timer3);
1363  this->CalcScattFactor();
1364  this->CalcResonantScattFactor();
1365  this->CalcTemperatureFactor();
1367  this->CalcLuzzatiFactor();
1368  this->CalcStructFactVariance();
1369  //TAU_PROFILE_STOP(timer3);
1370 
1371  //OK, really must recompute SFs?
1372  VFN_DEBUG_MESSAGE("ScatteringData::CalcStructFactor():Fhkl Recalc ?"<<endl
1373  <<"mClockStructFactor<mClockGlobalTemperatureFact"<<(bool)(mClockStructFactor<mClockGlobalTemperatureFact)<<endl
1374  <<"mClockStructFactor<mClockGeomStructFact" <<(bool)(mClockStructFactor<mClockGeomStructFact)<<endl
1375  <<"mClockStructFactor<mClockScattFactorResonant" <<(bool)(mClockStructFactor<mClockScattFactorResonant)<<endl
1376  <<"mClockStructFactor<mClockThermicFact" <<(bool)(mClockStructFactor<mClockThermicFact)<<endl
1377  <<"mClockStructFactor<mClockLuzzatiFactor" <<(bool)(mClockStructFactor<mClockLuzzatiFactor)<<endl
1378  ,2)
1383  &&(mClockStructFactor>mClockFhklCalcVariance)
1384  &&(mClockStructFactor>mClockLuzzatiFactor)) return;
1385  VFN_DEBUG_ENTRY("ScatteringData::CalcStructFactor()",3)
1386  TAU_PROFILE("ScatteringData::CalcStructFactor()","void ()",TAU_DEFAULT);
1387  //TAU_PROFILE_START(timer4);
1388  //reset Fcalc
1389  mFhklCalcReal.resize(nbRefl);
1390  mFhklCalcImag.resize(nbRefl);
1391  mFhklCalcReal=0;
1392  mFhklCalcImag=0;
1393  //Add all contributions
1394  for(map<const ScatteringPower*,CrystVector_REAL>::const_iterator pos=mvRealGeomSF.begin();
1395  pos!=mvRealGeomSF.end();++pos)
1396  {
1397  const ScatteringPower* pScattPow=pos->first;
1398  VFN_DEBUG_MESSAGE("ScatteringData::CalcStructFactor():Fhkl Recalc, "<<pScattPow->GetName(),2)
1399  const REAL * RESTRICT pGeomR=mvRealGeomSF[pScattPow].data();
1400  const REAL * RESTRICT pGeomI=mvImagGeomSF[pScattPow].data();
1401  const REAL * RESTRICT pScatt=mvScatteringFactor[pScattPow].data();
1402  const REAL * RESTRICT pTemp=mvTemperatureFactor[pScattPow].data();
1403 
1404  REAL * RESTRICT pReal=mFhklCalcReal.data();
1405  REAL * RESTRICT pImag=mFhklCalcImag.data();
1406 
1407  VFN_DEBUG_MESSAGE("->mvRealGeomSF[i] "
1408  <<mvRealGeomSF[pScattPow].numElements()<<"elements",2)
1409  VFN_DEBUG_MESSAGE("->mvImagGeomSF[i] "
1410  <<mvImagGeomSF[pScattPow].numElements()<<"elements",2)
1411  VFN_DEBUG_MESSAGE("->mvScatteringFactor[i]"
1412  <<mvScatteringFactor[pScattPow].numElements()<<"elements",1)
1413  VFN_DEBUG_MESSAGE("->mvTemperatureFactor[i]"
1414  <<mvTemperatureFactor[pScattPow].numElements()<<"elements",1)
1415  VFN_DEBUG_MESSAGE("->mFhklCalcReal "<<mFhklCalcReal.numElements()<<"elements",2)
1416  VFN_DEBUG_MESSAGE("->mFhklCalcImag "<<mFhklCalcImag.numElements()<<"elements",2)
1417  VFN_DEBUG_MESSAGE("-> H K L sin(t/l) Re(F) Im(F) scatt Temp->"<<pScattPow->GetName(),1)
1418 
1419  VFN_DEBUG_MESSAGE(FormatVertVectorHKLFloats<REAL>(mH,mK,mL,mSinThetaLambda,
1420  mvRealGeomSF[pScattPow],
1421  mvImagGeomSF[pScattPow],
1422  mvScatteringFactor[pScattPow],
1423  mvTemperatureFactor[pScattPow],10,4,mNbReflUsed
1424  ),1);
1425  if(mvLuzzatiFactor[pScattPow].numElements()>0)
1426  {// using maximum likelihood
1427  const REAL* RESTRICT pLuzzati=mvLuzzatiFactor[pScattPow].data();
1428  if(false==mIgnoreImagScattFact)
1429  {
1430  const REAL fsecond=mvFsecond[pScattPow];
1431  VFN_DEBUG_MESSAGE("->fsecond= "<<fsecond,10)
1432  for(long j=mNbReflUsed;j>0;j--)
1433  {
1434  VFN_DEBUG_MESSAGE("-->"<<j<<" "<<*pReal<<" "<<*pImag<<" "<<*pGeomR<<" "<<*pGeomI<<" "<<*pScatt<<" "<<*pTemp,1)
1435  *pReal++ += (*pGeomR * *pScatt - *pGeomI * fsecond)* *pTemp * *pLuzzati;
1436  *pImag++ += (*pGeomI++ * *pScatt++ + *pGeomR++ * fsecond)* *pTemp++ * *pLuzzati++;
1437  }
1438  }
1439  else
1440  {
1441  for(long j=mNbReflUsed;j>0;j--)
1442  {
1443  *pReal++ += *pGeomR++ * *pTemp * *pScatt * *pLuzzati;
1444  *pImag++ += *pGeomI++ * *pTemp++ * *pScatt++ * *pLuzzati++;
1445  }
1446  }
1447  VFN_DEBUG_MESSAGE("ScatteringData::CalcStructFactor():"<<mIgnoreImagScattFact
1448  <<",f\"="<<mvFsecond[pScattPow]<<endl<<
1450  mvRealGeomSF[pScattPow],
1451  mvImagGeomSF[pScattPow],
1452  mvScatteringFactor[pScattPow],
1453  mvTemperatureFactor[pScattPow],
1454  mvLuzzatiFactor[pScattPow],
1455  mFhklCalcReal,
1456  mFhklCalcImag,10,4,mNbReflUsed
1457  ),2);
1458  }
1459  else
1460  {
1461  if(false==mIgnoreImagScattFact)
1462  {
1463  const REAL fsecond=mvFsecond[pScattPow];
1464  VFN_DEBUG_MESSAGE("->fsecond= "<<fsecond,2)
1465  for(long j=mNbReflUsed;j>0;j--)
1466  {
1467  *pReal += (*pGeomR * *pScatt - *pGeomI * fsecond)* *pTemp;
1468  *pImag += (*pGeomI * *pScatt + *pGeomR * fsecond)* *pTemp;
1469  VFN_DEBUG_MESSAGE("-->"<<j<<" "<<*pReal<<" "<<*pImag<<" "<<*pGeomR<<" "<<*pGeomI<<" "<<*pScatt<<" "<<*pTemp,1)
1470  pGeomR++;pGeomI++;pTemp++;pScatt++;pReal++;pImag++;
1471  }
1472  }
1473  else
1474  {
1475  for(long j=mNbReflUsed;j>0;j--)
1476  {
1477  *pReal++ += *pGeomR++ * *pTemp * *pScatt;
1478  *pImag++ += *pGeomI++ * *pTemp++ * *pScatt++;
1479  }
1480  }
1481  VFN_DEBUG_MESSAGE(FormatVertVectorHKLFloats<REAL>(mH,mK,mL,mSinThetaLambda,
1482  mvRealGeomSF[pScattPow],
1483  mvImagGeomSF[pScattPow],
1484  mvScatteringFactor[pScattPow],
1485  mvTemperatureFactor[pScattPow],
1486  mFhklCalcReal,
1487  mFhklCalcImag,10,4,mNbReflUsed
1488  ),2);
1489  }
1490  }
1491  //TAU_PROFILE_STOP(timer4);
1492  {
1493  //this->CalcGlobalTemperatureFactor();
1494  if(mGlobalTemperatureFactor.numElements()>0)
1495  {//else for some reason it's useless
1496  REAL *pReal=mFhklCalcReal.data();
1497  REAL *pImag=mFhklCalcImag.data();
1498  const REAL *pTemp=mGlobalTemperatureFactor.data();
1499  for(long j=0;j<mNbReflUsed;j++)
1500  {
1501  *pReal++ *= *pTemp;
1502  *pImag++ *= *pTemp++;
1503  }
1504  }
1505  }
1507 
1508  VFN_DEBUG_EXIT("ScatteringData::CalcStructFactor()",3)
1509 }
1510 
1511 void ScatteringData::CalcStructFactor_FullDeriv(std::set<RefinablePar *> &vPar)
1512 {
1513  TAU_PROFILE("ScatteringData::CalcStructFactor_FullDeriv()","void ()",TAU_DEFAULT);
1515  this->CalcSinThetaLambda();
1516  this->CalcGeomStructFactor_FullDeriv(vPar);
1517  this->CalcStructFactor();//called after CalcGeomStructFactor_FullDeriv, so that CalcGeomStructFactor is not redone
1518 
1519  mFhklCalcReal_FullDeriv.clear();//:TODO: avoid full clear
1520  mFhklCalcImag_FullDeriv.clear();
1521  mFhklCalcReal_FullDeriv[0]=mFhklCalcReal;
1522  mFhklCalcImag_FullDeriv[0]=mFhklCalcImag;
1523  for(std::set<RefinablePar*>::iterator par=vPar.begin();par!=vPar.end();++par)
1524  {
1525  if(*par==0) continue;
1526  if((*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeScatt)==false)
1527  {//:TODO: allow derivatives from other parameters (ML, temperature factors, etc..)
1528  // No derivatives -> empty vectors
1529  mFhklCalcReal_FullDeriv[*par].resize(0);
1530  mFhklCalcImag_FullDeriv[*par].resize(0);
1531  continue;
1532  }
1533  for(map<const ScatteringPower*,CrystVector_REAL>::const_iterator pos=mvRealGeomSF.begin();
1534  pos!=mvRealGeomSF.end();++pos)
1535  {
1536  const ScatteringPower* pScattPow=pos->first;
1537  if(mvRealGeomSF_FullDeriv[*par][pScattPow].size()==0)
1538  {
1539  continue;//null derivative, so the array was empty
1540  }
1541  if(mFhklCalcReal_FullDeriv[*par].size()==0)
1542  {
1543  mFhklCalcReal_FullDeriv[*par].resize(mNbRefl);
1544  mFhklCalcImag_FullDeriv[*par].resize(mNbRefl);
1545  mFhklCalcReal_FullDeriv[*par]=0;
1546  mFhklCalcImag_FullDeriv[*par]=0;
1547  }
1548  const REAL * RESTRICT pGeomRd=mvRealGeomSF_FullDeriv[*par][pScattPow].data();
1549  const REAL * RESTRICT pGeomId=mvImagGeomSF_FullDeriv[*par][pScattPow].data();
1550  const REAL * RESTRICT pScatt=mvScatteringFactor[pScattPow].data();
1551  const REAL * RESTRICT pTemp=mvTemperatureFactor[pScattPow].data();
1552 
1553  REAL * RESTRICT pReal=mFhklCalcReal_FullDeriv[*par].data();
1554  REAL * RESTRICT pImag=mFhklCalcImag_FullDeriv[*par].data();
1555  if(mvLuzzatiFactor[pScattPow].numElements()>0)
1556  {// using maximum likelihood
1557  const REAL* RESTRICT pLuzzati=mvLuzzatiFactor[pScattPow].data();
1558  if(false==mIgnoreImagScattFact)
1559  {
1560  const REAL fsecond=mvFsecond[pScattPow];
1561  for(long j=mNbReflUsed;j>0;j--)
1562  {
1563  *pReal++ += (*pGeomRd * *pScatt - *pGeomId * fsecond)* *pTemp * *pLuzzati;
1564  *pImag++ += (*pGeomId++ * *pScatt++ + *pGeomRd++ * fsecond)* *pTemp++ * *pLuzzati++;
1565  }
1566  }
1567  else
1568  {
1569  for(long j=mNbReflUsed;j>0;j--)
1570  {
1571  *pReal++ += *pGeomRd++ * *pTemp * *pScatt * *pLuzzati;
1572  *pImag++ += *pGeomId++ * *pTemp++ * *pScatt++ * *pLuzzati++;
1573  }
1574  }
1575  }
1576  else
1577  {
1578  if(false==mIgnoreImagScattFact)
1579  {
1580  const REAL fsecond=mvFsecond[pScattPow];
1581  for(long j=mNbReflUsed;j>0;j--)
1582  {
1583  *pReal += (*pGeomRd * *pScatt - *pGeomId * fsecond)* *pTemp;
1584  *pImag += (*pGeomId * *pScatt + *pGeomRd * fsecond)* *pTemp;
1585  pGeomRd++;pGeomId++;pTemp++;pScatt++;pReal++;pImag++;
1586  }
1587  }
1588  else
1589  {
1590  for(long j=mNbReflUsed;j>0;j--)
1591  {
1592  *pReal++ += *pGeomRd++ * *pTemp * *pScatt;
1593  *pImag++ += *pGeomId++ * *pTemp++ * *pScatt++;
1594  }
1595  }
1596  }
1597  }
1598  //TAU_PROFILE_STOP(timer4);
1599  {
1600  //this->CalcGlobalTemperatureFactor();
1601  if( (mGlobalTemperatureFactor.numElements()>0)
1602  &&(mFhklCalcReal_FullDeriv[*par].size()>0)
1603  &&(mFhklCalcImag_FullDeriv[*par].size()>0))
1604  {//else for some reason it's useless
1605  REAL * RESTRICT pReal=mFhklCalcReal_FullDeriv[*par].data();
1606  REAL * RESTRICT pImag=mFhklCalcImag_FullDeriv[*par].data();
1607  const REAL *pTemp=mGlobalTemperatureFactor.data();
1608  for(long j=0;j<mNbReflUsed;j++)
1609  {
1610  *pReal++ *= *pTemp;
1611  *pImag++ *= *pTemp++;
1612  }
1613  }
1614  }
1615  }
1616  #if 0
1617  std::vector<const CrystVector_REAL*> v;
1618  v.push_back(&mH);
1619  v.push_back(&mK);
1620  v.push_back(&mL);
1621  std::map<RefinablePar*, CrystVector_REAL> oldDerivR,oldDerivI;
1622  for(std::set<RefinablePar*>::iterator par=vPar.begin();par!=vPar.end();++par)
1623  {
1624  const REAL step=(*par)->GetDerivStep();
1625  (*par)->Mutate(step);
1626  this->CalcStructFactor();
1627  oldDerivR[*par]=mFhklCalcReal;
1628  oldDerivI[*par]=mFhklCalcImag;
1629  (*par)->Mutate(-2*step);
1630  this->CalcStructFactor();
1631  oldDerivR[*par]-=mFhklCalcReal;
1632  oldDerivR[*par]/=2*step;
1633  oldDerivI[*par]-=mFhklCalcImag;
1634  oldDerivI[*par]/=2*step;
1635  (*par)->Mutate(step);
1636 
1637  v.push_back(&(mFhklCalcReal_FullDeriv[*par]));
1638  v.push_back(&(oldDerivR[*par]));
1639  v.push_back(&(mFhklCalcImag_FullDeriv[*par]));
1640  v.push_back(&(oldDerivI[*par]));
1641  if(v.size()>14) break;
1642  }
1643  cout<<"############################ Fhkl Deriv Real, Imag ##############################"
1644  <<endl<<FormatVertVectorHKLFloats<REAL>(v,14,4,20)
1645  <<"############################ END Fhkl Deriv Real, Imag ##############################"<<endl;
1646  //exit(0);
1647  #endif
1648 }
1649 
1651 {
1652  // This also updates the ScattCompList if necessary.
1653  const ScatteringComponentList *pScattCompList
1654  =&(this->GetCrystal().GetScatteringComponentList());
1660  TAU_PROFILE("ScatteringData::GeomStructFactor()","void (Vx,Vy,Vz,data,M,M,bool)",TAU_DEFAULT);
1661  VFN_DEBUG_ENTRY("ScatteringData::GeomStructFactor(Vx,Vy,Vz,...)",3)
1662  VFN_DEBUG_MESSAGE("-->Using fast functions:"<<mUseFastLessPreciseFunc,2)
1663  VFN_DEBUG_MESSAGE("-->Number of translation vectors:"
1664  <<this->GetCrystal().GetSpaceGroup().GetNbTranslationVectors()-1,2)
1665  VFN_DEBUG_MESSAGE("-->Has an inversion Center:"
1666  <<this->GetCrystal().GetSpaceGroup().HasInversionCenter(),2)
1667  VFN_DEBUG_MESSAGE("-->Number of symetry operations (w/o transl&inv cent.):"\
1668  <<this->GetCrystal().GetSpaceGroup().GetNbSymmetrics(true,true),2)
1669  VFN_DEBUG_MESSAGE("-->Number of Scattering Components :"
1670  <<this->GetCrystal().GetScatteringComponentList().GetNbComponent(),2)
1671  VFN_DEBUG_MESSAGE("-->Number of reflections:"
1672  <<this->GetNbRefl()<<" (actually used:"<<mNbReflUsed<<")",2)
1673  #ifdef __DEBUG__
1674  static long counter=0;
1675  VFN_DEBUG_MESSAGE("-->Number of GeomStructFactor calculations so far:"<<counter++,3)
1676  #endif
1677 
1678  //:TODO: implement for geometrical structure factor calculation
1679  //bool useGeomStructFactor=mUseGeomStructFactor;
1680 
1681  //if((mfpRealGeomStructFactor==0)||(mfpImagGeomStructFactor==0)) useGeomStructFactor=false ;
1682 
1683  //if(useGeomStructFactor==true)
1684  //{
1685  // (*mfpRealGeomStructFactor)(x,y,z,data.H2Pi(),data.K2Pi(),data.L2Pi(),rsf);
1686  // if(this->IsCentrosymmetric())return;
1687  // (*mfpImagGeomStructFactor)(x,y,z,data.H2Pi(),data.K2Pi(),data.L2Pi(),isf);
1688  // return;
1689  //}
1690  //else
1691  {
1692  const SpaceGroup *pSpg=&(this->GetCrystal().GetSpaceGroup());
1693 
1694  const int nbSymmetrics=pSpg->GetNbSymmetrics(true,true);
1695  const int nbTranslationVectors=pSpg->GetNbTranslationVectors();
1696  const long nbComp=pScattCompList->GetNbComponent();
1697  const std::vector<SpaceGroup::TRx> *pTransVect=&(pSpg->GetTranslationVectors());
1698  CrystMatrix_REAL allCoords(nbSymmetrics,3);
1699  CrystVector_REAL tmpVect(mNbReflUsed);
1700  #ifndef HAVE_SSE_MATHFUN
1701  const int nbRefl=this->GetNbRefl();
1702  CrystVector_long intVect(nbRefl);//not used if mUseFastLessPreciseFunc==false
1703  #endif
1704  // which scattering powers are actually used ?
1705  map<const ScatteringPower*,bool> vUsed;
1706  // Add existing previously used scattering power to the test;
1707  for(map<const ScatteringPower*,CrystVector_REAL>::const_iterator pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos)
1708  vUsed[pos->first]=false;// this will be changed to true later if they are actually used
1709 
1710  for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--)
1711  {// Here we make sure scattering power that only contribute ghost atoms are taken into account
1712  const ScatteringPower*pow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i));
1713  if(pow->GetMaximumLikelihoodNbGhostAtom()>0) vUsed[pow]=true;
1714  else vUsed[pow]=false;
1715  }
1716  for(long i=0;i<nbComp;i++)
1717  vUsed[(*pScattCompList)(i).mpScattPow]=true;
1718  //Resize all arrays and set them to 0
1719  for(map<const ScatteringPower*,bool>::const_iterator pos=vUsed.begin();pos!=vUsed.end();++pos)
1720  {
1721  if(pos->second)
1722  {// this will create the entry if it does not already exist
1723  mvRealGeomSF[pos->first].resize(mNbReflUsed);
1724  mvImagGeomSF[pos->first].resize(mNbReflUsed);
1725  mvRealGeomSF[pos->first]=0;
1726  mvImagGeomSF[pos->first]=0;
1727  }
1728  else
1729  {// erase entries that are not useful any more (e.g. ScatteringPower that were
1730  // used but are not any more).
1731  map<const ScatteringPower*,CrystVector_REAL>::iterator
1732  poubelle=mvRealGeomSF.find(pos->first);
1733  if(poubelle!=mvRealGeomSF.end()) mvRealGeomSF.erase(poubelle);
1734  poubelle=mvImagGeomSF.find(pos->first);
1735  if(poubelle!=mvImagGeomSF.end()) mvImagGeomSF.erase(poubelle);
1736  }
1737  }
1738 
1739  REAL centrMult=1.0;
1740  if(true==pSpg->HasInversionCenter()) centrMult=2.0;
1741  for(long i=0;i<nbComp;i++)
1742  {
1743  VFN_DEBUG_MESSAGE("ScatteringData::GeomStructFactor(),comp"<<i,3)
1744  const REAL x=(*pScattCompList)(i).mX;
1745  const REAL y=(*pScattCompList)(i).mY;
1746  const REAL z=(*pScattCompList)(i).mZ;
1747  const ScatteringPower *pScattPow=(*pScattCompList)(i).mpScattPow;
1748  const REAL popu= (*pScattCompList)(i).mOccupancy
1749  *(*pScattCompList)(i).mDynPopCorr
1750  *centrMult;
1751 
1752  allCoords=pSpg->GetAllSymmetrics(x,y,z,true,true);
1753  if((true==pSpg->HasInversionCenter()) && (false==pSpg->IsInversionCenterAtOrigin()))
1754  {
1755  const REAL STBF=2.*pSpg->GetCCTbxSpg().inv_t().den();
1756  for(int j=0;j<nbSymmetrics;j++)
1757  {
1758  //The phase of the structure factor will be wrong
1759  //This is fixed a bit further...
1760  allCoords(j,0) -= ((REAL)pSpg->GetCCTbxSpg().inv_t()[0])/STBF;
1761  allCoords(j,1) -= ((REAL)pSpg->GetCCTbxSpg().inv_t()[1])/STBF;
1762  allCoords(j,2) -= ((REAL)pSpg->GetCCTbxSpg().inv_t()[2])/STBF;
1763  }
1764  }
1765  for(int j=0;j<nbSymmetrics;j++)
1766  {
1767  VFN_DEBUG_MESSAGE("ScatteringData::GeomStructFactor(),comp #"<<i<<", sym #"<<j,3)
1768 
1769  #ifndef HAVE_SSE_MATHFUN
1770  if(mUseFastLessPreciseFunc==true)
1771  {
1772  REAL * RESTRICT rrsf=mvRealGeomSF[pScattPow].data();
1773  REAL * RESTRICT iisf=mvImagGeomSF[pScattPow].data();
1774 
1775  const long intX=(long)(allCoords(j,0)*sLibCrystNbTabulSine);
1776  const long intY=(long)(allCoords(j,1)*sLibCrystNbTabulSine);
1777  const long intZ=(long)(allCoords(j,2)*sLibCrystNbTabulSine);
1778 
1779  const long * RESTRICT intH=mIntH.data();
1780  const long * RESTRICT intK=mIntK.data();
1781  const long * RESTRICT intL=mIntL.data();
1782 
1783  long * RESTRICT tmpInt=intVect.data();
1784  // :KLUDGE: using a AND to bring back within [0;sLibCrystNbTabulSine[ may
1785  // not be portable, depending on the model used to represent signed integers
1786  // a test should be added to throw up in that case.
1787  //
1788  // This work if we are using "2's complement" to represent negative numbers,
1789  // but not with a "sign magnitude" approach
1790  for(int jj=mNbReflUsed;jj>0;jj--)
1791  *tmpInt++ = (*intH++ * intX + *intK++ * intY + *intL++ *intZ)
1792  &sLibCrystNbTabulSineMASK;
1793  if(false==pSpg->HasInversionCenter())
1794  {
1795 
1796  tmpInt=intVect.data();
1797  for(int jj=mNbReflUsed;jj>0;jj--)
1798  {
1799  const REAL *pTmp=&spLibCrystTabulCosineSine[*tmpInt++ <<1];
1800  *rrsf++ += popu * *pTmp++;
1801  *iisf++ += popu * *pTmp;
1802  }
1803 
1804  }
1805  else
1806  {
1807  tmpInt=intVect.data();
1808  for(int jj=mNbReflUsed;jj>0;jj--)
1809  *rrsf++ += popu * spLibCrystTabulCosine[*tmpInt++];
1810  }
1811  }
1812  else
1813  #endif
1814  {
1815  const REAL x=allCoords(j,0);
1816  const REAL y=allCoords(j,1);
1817  const REAL z=allCoords(j,2);
1818  const REAL *hh=mH2Pi.data();
1819  const REAL *kk=mK2Pi.data();
1820  const REAL *ll=mL2Pi.data();
1821 
1822  #ifdef HAVE_SSE_MATHFUN
1823  #if 0
1824  // This not much faster and is incorrect (does not take into account sign of h k l)
1825 
1826  //cout<<__FILE__<<":"<<__LINE__<<":"<<mMaxHKL<<","<<mMaxH<<","<<mMaxK<<","<<mMaxL<<":"<<mNbReflUsed<<endl;
1827  // cos&sin for 2pix 2piy 2piz
1828  static const float twopi=6.283185307179586f;
1829  sincos_ps(_mm_mul_ps(_mm_load1_ps(&twopi),_mm_set_ps(x,y,z,0)),cnxyz0,snxyz0);
1830  // harmonics: cos&sin for 2npix 2npiy 2npiz
1831  for(long k=1;k<mMaxHKL;k++)
1832  {
1833  cnxyz0[k]=_mm_sub_ps(_mm_mul_ps(cnxyz0[k-1],cnxyz0[0]),_mm_mul_ps(snxyz0[k-1],snxyz0[0]));//cos((n+1)x)=cos(nx)cos(x)-sin(nx)sinx
1834  snxyz0[k]=_mm_add_ps(_mm_mul_ps(snxyz0[k-1],cnxyz0[0]),_mm_mul_ps(cnxyz0[k-1],snxyz0[0]));//sin((n+1)x)=sin(nx)cos(x)+cos(nx)sinx
1835  }
1836  //
1837  for(long k=0;k<4;++k){*(pcnxyz0+k)=1.0f;*(psnxyz0+k)=0.0f;}
1838  for(long k=1;k<mMaxHKL;k++)
1839  {
1840  _mm_store_ps(pcnxyz0+4*k,cnxyz0[k-1]);
1841  _mm_store_ps(psnxyz0+4*k,snxyz0[k-1]);
1842  }
1843  // Actual structure factor calculations
1844  if(false==pSpg->HasInversionCenter())
1845  {// Slow ?
1846  REAL *rsf=mvRealGeomSF[pScattPow].data();
1847  REAL *isf=mvImagGeomSF[pScattPow].data();
1848  const long *h=mIntH.data();
1849  const long *k=mIntK.data();
1850  const long *l=mIntL.data();
1851  int jj;
1852  const v4sf v4popu=_mm_set1_ps(popu);
1853  for(jj=mNbReflUsed;jj>3;jj-=4)
1854  {
1855  //cout<<__FILE__<<":"<<__LINE__<<":"<<mNbReflUsed<<","<<jj<<"("<<*h<<','<<*k<<","<<*l<<")"<<endl;
1856  const v4sf ck=_mm_set_ps(pcnxyz0[(*(k))*4+1],pcnxyz0[(*(k+1))*4+1],pcnxyz0[(*(k+2))*4+1],pcnxyz0[(*(k+3))*4+1]);//cos 2pi kx =ck
1857  const v4sf cl=_mm_set_ps(pcnxyz0[(*(l))*4+1],pcnxyz0[(*(l+1))*4+1],pcnxyz0[(*(l+2))*4+1],pcnxyz0[(*(l+3))*4+1]);//cos 2pi lz =cl
1858  const v4sf sk=_mm_set_ps(psnxyz0[(*(k))*4+1],psnxyz0[(*(k+1))*4+1],psnxyz0[(*(k+2))*4+1],psnxyz0[(*(k+3))*4+1]);//sin 2pi kx =sk
1859  const v4sf sl=_mm_set_ps(psnxyz0[(*(l))*4+1],psnxyz0[(*(l+1))*4+1],psnxyz0[(*(l+2))*4+1],psnxyz0[(*(l+3))*4+1]);//sin 2pi lz =sl
1860  #define CH _mm_set_ps(pcnxyz0[*(h)*4],pcnxyz0[*(h+1)*4],pcnxyz0[*(h+2)*4],pcnxyz0[*(h+3)*4])
1861  #define SH _mm_set_ps(psnxyz0[*(h)*4],psnxyz0[*(h+1)*4],psnxyz0[*(h+2)*4],psnxyz0[*(h+3)*4])
1862  // popu *( ch*( ck*cl - sk*sl) - sh*( ck*sl + sk*cl))
1863  _mm_store_ps(rsf,_mm_mul_ps(v4popu,_mm_sub_ps(_mm_mul_ps(CH,_mm_sub_ps(_mm_mul_ps(ck,cl),_mm_mul_ps(sk,sl))),_mm_mul_ps(SH,_mm_add_ps(_mm_mul_ps(ck,sl),_mm_mul_ps(sk,cl))))));
1864  // popu *( sh*( ck*cl - sk*sl) + ch*( ck*sl + sk*cl))
1865  _mm_store_ps(isf,_mm_mul_ps(v4popu,_mm_add_ps(_mm_mul_ps(SH,_mm_sub_ps(_mm_mul_ps(ck,cl),_mm_mul_ps(sk,sl))),_mm_mul_ps(CH,_mm_add_ps(_mm_mul_ps(ck,sl),_mm_mul_ps(sk,cl))))));
1866  rsf+=4;isf+=4;h+=4;k+=4,l+=4;
1867  }
1868  for(;jj>0;jj--)
1869  {
1870  const float ch=pcnxyz0[*h *4];
1871  const float sh=psnxyz0[*h++ *4];
1872  const float ck=pcnxyz0[*k *4+1];
1873  const float sk=psnxyz0[*k++ *4+1];
1874  const float cl=pcnxyz0[*l *4+2];
1875  const float sl=psnxyz0[*l++ *4+2];
1876  *rsf++ += popu*(ch*(ck*cl-sk*sl)-sh*(sk*cl+ck*sl));
1877  *isf++ += popu*(sh*(ck*cl-sk*sl)+ch*(sk*cl+ck*sl));
1878  }
1879  }
1880  else
1881  {
1882  REAL *rsf=mvRealGeomSF[pScattPow].data();
1883  const long *h=mIntH.data();
1884  const long *k=mIntK.data();
1885  const long *l=mIntL.data();
1886  int jj;
1887  const v4sf v4popu=_mm_set1_ps(popu);
1888  for(jj=mNbReflUsed;jj>3;jj-=4)
1889  {
1890  //cout<<__FILE__<<":"<<__LINE__<<":"<<mNbReflUsed<<","<<jj<<"("<<*h<<','<<*k<<","<<*l<<")"<<endl;
1891  const v4sf ck=_mm_set_ps(pcnxyz0[(*(k))*4+1],pcnxyz0[(*(k+1))*4+1],pcnxyz0[(*(k+2))*4+1],pcnxyz0[(*(k+3))*4+1]);//cos 2pi kx =ck
1892  const v4sf cl=_mm_set_ps(pcnxyz0[(*(l))*4+1],pcnxyz0[(*(l+1))*4+1],pcnxyz0[(*(l+2))*4+1],pcnxyz0[(*(l+3))*4+1]);//cos 2pi lz =cl
1893  const v4sf sk=_mm_set_ps(psnxyz0[(*(k))*4+1],psnxyz0[(*(k+1))*4+1],psnxyz0[(*(k+2))*4+1],psnxyz0[(*(k+3))*4+1]);//sin 2pi kx =sk
1894  const v4sf sl=_mm_set_ps(psnxyz0[(*(l))*4+1],psnxyz0[(*(l+1))*4+1],psnxyz0[(*(l+2))*4+1],psnxyz0[(*(l+3))*4+1]);//sin 2pi lz =sl
1895  #define CH _mm_set_ps(pcnxyz0[*(h)*4],pcnxyz0[*(h+1)*4],pcnxyz0[*(h+2)*4],pcnxyz0[*(h+3)*4])
1896  #define SH _mm_set_ps(psnxyz0[*(h)*4],psnxyz0[*(h+1)*4],psnxyz0[*(h+2)*4],psnxyz0[*(h+3)*4])
1897  // popu *( ch*( ck*cl - sk*sl) - sh*( ck*sl + sk*cl))
1898  _mm_store_ps(rsf,_mm_mul_ps(v4popu,_mm_sub_ps(_mm_mul_ps(CH,_mm_sub_ps(_mm_mul_ps(ck,cl),_mm_mul_ps(sk,sl))),_mm_mul_ps(SH,_mm_add_ps(_mm_mul_ps(ck,sl),_mm_mul_ps(sk,cl))))));
1899  rsf+=4;h+=4;k+=4,l+=4;
1900  }
1901  for(;jj>0;jj--)
1902  {
1903  const float ch=pcnxyz0[*h *4];
1904  const float sh=psnxyz0[*h++ *4];
1905  const float ck=pcnxyz0[*k *4+1];
1906  const float sk=psnxyz0[*k++ *4+1];
1907  const float cl=pcnxyz0[*l *4+2];
1908  const float sl=psnxyz0[*l++ *4+2];
1909  *rsf++ += popu*(ch*(ck*cl-sk*sl)-sh*(sk*cl+ck*sl));
1910  }
1911  }
1912 
1913 
1914  #else
1915  const v4sf v4x=_mm_load1_ps(&x);
1916  const v4sf v4y=_mm_load1_ps(&y);
1917  const v4sf v4z=_mm_load1_ps(&z);
1918  const v4sf v4popu=_mm_load1_ps(&popu);// Can't multiply directly a vector by a scalar ?
1919  if(false==pSpg->HasInversionCenter())
1920  {
1921  REAL *rsf=mvRealGeomSF[pScattPow].data();
1922  REAL *isf=mvImagGeomSF[pScattPow].data();
1923  int jj=mNbReflUsed;
1924  for(;jj>3;jj-=4)
1925  {
1926  v4sf v4sin,v4cos;
1927 // sincos_ps(_mm_setr_ps(*(hh )*x+ *(kk )*y + *(ll )*z,
1928 // *(hh+1)*x+ *(kk+1)*y + *(ll+1)*z,
1929 // *(hh+2)*x+ *(kk+2)*y + *(ll+2)*z,
1930 // *(hh+3)*x+ *(kk+3)*y + *(ll+3)*z),&v4sin,&v4cos);
1931  sincos_ps(_mm_add_ps(_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(hh),v4x),
1932  _mm_mul_ps(_mm_loadu_ps(kk),v4y)
1933  ),
1934  _mm_mul_ps(_mm_loadu_ps(ll),v4z)
1935  ),&v4sin,&v4cos);// A bit faster
1936  _mm_storeu_ps(rsf,_mm_add_ps(_mm_mul_ps(v4cos,v4popu),_mm_loadu_ps(rsf)));
1937  _mm_storeu_ps(isf,_mm_add_ps(_mm_mul_ps(v4sin,v4popu),_mm_loadu_ps(isf)));
1938 
1939  hh+=4;kk+=4;ll+=4;rsf+=4;isf+=4;
1940  }
1941  for(;jj>0;jj--)
1942  {
1943  const REAL tmp = *hh++ * x + *kk++ * y + *ll++ *z;
1944  *rsf++ += popu * cos(tmp);
1945  *isf++ += popu * sin(tmp);
1946  }
1947  }
1948  else
1949  {
1950  REAL *rsf=mvRealGeomSF[pScattPow].data();
1951  int jj=mNbReflUsed;
1952  for(;jj>3;jj-=4)
1953  {
1954 // const v4sf v4cos=cos_ps(_mm_setr_ps(*(hh )*x+ *(kk )*y + *(ll )*z,
1955 // *(hh+1)*x+ *(kk+1)*y + *(ll+1)*z,
1956 // *(hh+2)*x+ *(kk+2)*y + *(ll+2)*z,
1957 // *(hh+3)*x+ *(kk+3)*y + *(ll+3)*z));
1958  const v4sf v4cos=cos_ps(_mm_add_ps(_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(hh),v4x),
1959  _mm_mul_ps(_mm_loadu_ps(kk),v4y)
1960  ),
1961  _mm_mul_ps(_mm_loadu_ps(ll),v4z)));
1962  _mm_storeu_ps(rsf,_mm_add_ps(_mm_loadu_ps(rsf),_mm_mul_ps(v4cos,v4popu)));
1963  hh+=4;kk+=4;ll+=4;rsf+=4;
1964  }
1965  for(;jj>0;jj--)
1966  {
1967  const REAL tmp = *hh++ * x + *kk++ * y + *ll++ *z;
1968  *rsf++ += popu * cos(tmp);
1969  }
1970  }
1971  #endif
1972  #else
1973  REAL *tmp=tmpVect.data();
1974  for(int jj=0;jj<mNbReflUsed;jj++) *tmp++ = *hh++ * x + *kk++ * y + *ll++ *z;
1975 
1976  REAL *sf=mvRealGeomSF[pScattPow].data();
1977  tmp=tmpVect.data();
1978 
1979  for(int jj=0;jj<mNbReflUsed;jj++) *sf++ += popu * cos(*tmp++);
1980 
1981  if(false==pSpg->HasInversionCenter())
1982  {
1983  sf=mvImagGeomSF[pScattPow].data();
1984  tmp=tmpVect.data();
1985  for(int jj=0;jj<mNbReflUsed;jj++) *sf++ += popu * sin(*tmp++);
1986  }
1987  #endif
1988  }
1989  }
1990  }//for all components...
1991  if(nbTranslationVectors > 1)
1992  {
1993  tmpVect=1;
1994  if( (pSpg->GetSpaceGroupNumber()>= 143) && (pSpg->GetSpaceGroupNumber()<= 167))
1995  {//Special case for trigonal groups R3,...
1996  REAL * RESTRICT p1=tmpVect.data();
1997  const REAL * RESTRICT hh=mH2Pi.data();
1998  const REAL * RESTRICT kk=mK2Pi.data();
1999  const REAL * RESTRICT ll=mL2Pi.data();
2000  for(long j=mNbReflUsed;j>0;j--) *p1++ += 2*cos((*hh++ - *kk++ - *ll++)/3.);
2001  }
2002  else
2003  {
2004  for(int j=1;j<nbTranslationVectors;j++)
2005  {
2006  const REAL x=(*pTransVect)[j].tr[0];
2007  const REAL y=(*pTransVect)[j].tr[1];
2008  const REAL z=(*pTransVect)[j].tr[2];
2009  REAL *p1=tmpVect.data();
2010  const REAL *hh=mH2Pi.data();
2011  const REAL *kk=mK2Pi.data();
2012  const REAL *ll=mL2Pi.data();
2013  for(long j=mNbReflUsed;j>0;j--) *p1++ += cos(*hh++ *x + *kk++ *y + *ll++ *z );
2014  }
2015  }
2016  for(map<const ScatteringPower*,CrystVector_REAL>::iterator
2017  pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos)
2018  pos->second *= tmpVect;
2019 
2020  if(false==pSpg->HasInversionCenter())
2021  for(map<const ScatteringPower*,CrystVector_REAL>::iterator
2022  pos=mvImagGeomSF.begin();pos!=mvImagGeomSF.end();++pos)
2023  pos->second *= tmpVect;
2024  }
2025  if(true==pSpg->HasInversionCenter())
2026  {
2027  // we already multiplied real geom struct factor by 2
2028  if(false==pSpg->IsInversionCenterAtOrigin())
2029  {
2030  VFN_DEBUG_MESSAGE("ScatteringData::GeomStructFactor(Vx,Vy,Vz):\
2031  Inversion Center not at the origin...",2)
2032  //fix the phase of each reflection when the inversion center is not
2033  //at the origin, using :
2034  // Re(F) = RSF*cos(2pi(h*Xc+k*Yc+l*Zc))
2035  // Re(F) = RSF*sin(2pi(h*Xc+k*Yc+l*Zc))
2036  //cout << "Glop Glop"<<endl;
2037  const REAL STBF=2*pSpg->GetCCTbxSpg().inv_t().den();
2038  {
2039  const REAL xc=((REAL)pSpg->GetCCTbxSpg().inv_t()[0])/STBF;
2040  const REAL yc=((REAL)pSpg->GetCCTbxSpg().inv_t()[1])/STBF;
2041  const REAL zc=((REAL)pSpg->GetCCTbxSpg().inv_t()[2])/STBF;
2042  #ifdef __LIBCRYST_VECTOR_USE_BLITZ__
2043  tmpVect = mH2Pi() * xc + mK2PI() * yc + mL2PI() * zc;
2044  #else
2045  {
2046  const REAL * RESTRICT hh=mH2Pi.data();
2047  const REAL * RESTRICT kk=mK2Pi.data();
2048  const REAL * RESTRICT ll=mL2Pi.data();
2049  REAL * RESTRICT ttmpVect=tmpVect.data();
2050  for(long ii=mNbReflUsed;ii>0;ii--)
2051  *ttmpVect++ = *hh++ * xc + *kk++ * yc + *ll++ * zc;
2052  }
2053  #endif
2054  }
2055  CrystVector_REAL cosTmpVect;
2056  CrystVector_REAL sinTmpVect;
2057  cosTmpVect=cos(tmpVect);
2058  sinTmpVect=sin(tmpVect);
2059 
2060  map<const ScatteringPower*,CrystVector_REAL>::iterator posi=mvImagGeomSF.begin();
2061  map<const ScatteringPower*,CrystVector_REAL>::iterator posr=mvRealGeomSF.begin();
2062  for(;posi!=mvImagGeomSF.end();)
2063  {
2064  posi->second = posr->second;
2065  posi->second *= sinTmpVect;
2066  posr->second *= cosTmpVect;
2067  posi++;posr++;
2068  }
2069  }
2070  }
2071  }
2072  //cout << FormatVertVector<REAL>(*mvRealGeomSF,*mvImagGeomSF)<<endl;
2074  VFN_DEBUG_EXIT("ScatteringData::GeomStructFactor(Vx,Vy,Vz,...)",3)
2075 }
2076 void ScatteringData::CalcGeomStructFactor_FullDeriv(std::set<RefinablePar*> &vPar)
2077 {
2078  TAU_PROFILE("ScatteringData::CalcGeomStructFactor_FullDeriv()","void (..)",TAU_DEFAULT);
2079  TAU_PROFILE_TIMER(timer1,"ScatteringData::CalcGeomStructFactor_FullDeriv:1-ScattCompList deriv","", TAU_FIELD);
2080  TAU_PROFILE_TIMER(timer2,"ScatteringData::CalcGeomStructFactor_FullDeriv:2-Geom SF","", TAU_FIELD);
2081  this->CalcGeomStructFactor();//:TODO: avoid calling CalcGeomStructFactor()
2082  //:TODO: this->GetCrystal().GetScatteringComponentList_FullDeriv()
2083  const ScatteringComponentList *pScattCompList
2084  =&(this->GetCrystal().GetScatteringComponentList());
2085 
2086  const SpaceGroup *pSpg=&(this->GetCrystal().GetSpaceGroup());
2087 
2088  const int nbSymmetrics=pSpg->GetNbSymmetrics(true,true);
2089  const int nbTranslationVectors=pSpg->GetNbTranslationVectors();
2090  const unsigned long nbComp=pScattCompList->GetNbComponent();
2091  const std::vector<SpaceGroup::TRx> *pTransVect=&(pSpg->GetTranslationVectors());
2092  CrystMatrix_REAL allCoords(nbSymmetrics,3);
2093 
2094  const bool hasinv=pSpg->HasInversionCenter();
2095 
2096  TAU_PROFILE_START(timer1);
2097  // Calculate derivatives of the scattering component list vs all parameters
2098  std::map<RefinablePar*,CrystVector_REAL> vdx,vdy,vdz,vdocc;
2099  for(std::set<RefinablePar*>::iterator par=vPar.begin();par!=vPar.end();++par)
2100  {// :TODO: get this done in Crystal or Scatterers, and use analytical derivatives
2101  if(*par==0) continue;
2102  CrystVector_REAL *pdx =&(vdx[*par]);
2103  CrystVector_REAL *pdy =&(vdy[*par]);
2104  CrystVector_REAL *pdz =&(vdz[*par]);
2105  CrystVector_REAL *pdocc=&(vdocc[*par]);
2106  pdx->resize(nbComp);
2107  pdy->resize(nbComp);
2108  pdz->resize(nbComp);
2109  pdocc->resize(nbComp);
2110 
2111  const REAL p0=(*par)->GetValue();
2112  const REAL step=(*par)->GetDerivStep();
2113  (*par)->Mutate(step);
2114  pScattCompList=&(this->GetCrystal().GetScatteringComponentList());
2115  REAL *ppdx =pdx->data();
2116  REAL *ppdy =pdy->data();
2117  REAL *ppdz =pdz->data();
2118  REAL *ppdocc=pdocc->data();
2119  for(unsigned long i=0;i<nbComp;++i)
2120  {
2121  *ppdx++ =(*pScattCompList)(i).mX;
2122  *ppdy++ =(*pScattCompList)(i).mY;
2123  *ppdz++ =(*pScattCompList)(i).mZ;
2124  *ppdocc++=(*pScattCompList)(i).mOccupancy*(*pScattCompList)(i).mDynPopCorr;
2125  }
2126  (*par)->Mutate(-2*step);
2127  pScattCompList=&(this->GetCrystal().GetScatteringComponentList());
2128  ppdx =pdx->data();
2129  ppdy =pdy->data();
2130  ppdz =pdz->data();
2131  ppdocc=pdocc->data();
2132  for(unsigned long i=0;i<nbComp;++i)
2133  {
2134  *ppdx -=(*pScattCompList)(i).mX;
2135  *ppdx++/=2*step;
2136  *ppdy -=(*pScattCompList)(i).mY;
2137  *ppdy++/=2*step;
2138  *ppdz -=(*pScattCompList)(i).mZ;
2139  *ppdz++/=2*step;
2140  *ppdocc-=(*pScattCompList)(i).mOccupancy*(*pScattCompList)(i).mDynPopCorr;
2141  *ppdocc++/=2*step;
2142  }
2143  (*par)->SetValue(p0);
2144  if( (MaxAbs(vdx[*par])==0)&&(MaxAbs(vdy[*par])==0)&&(MaxAbs(vdz[*par])==0)&&(MaxAbs(vdocc[*par])==0))
2145  {
2146  pdx->resize(0);
2147  pdy->resize(0);
2148  pdz->resize(0);
2149  pdocc->resize(0);
2150  }
2151  }
2152  TAU_PROFILE_STOP(timer1);
2153  TAU_PROFILE_START(timer2);
2154  CrystVector_REAL transMult(mNbReflUsed);
2155  if(!hasinv) transMult=1;
2156  else transMult=2;
2157  if(nbTranslationVectors > 1)
2158  {
2159  if( (pSpg->GetSpaceGroupNumber()>= 143) && (pSpg->GetSpaceGroupNumber()<= 167))
2160  {//Special case for trigonal groups R3,...
2161  REAL * RESTRICT p1=transMult.data();
2162  const REAL * RESTRICT hh=mH2Pi.data();
2163  const REAL * RESTRICT kk=mK2Pi.data();
2164  const REAL * RESTRICT ll=mL2Pi.data();
2165  for(long j=mNbReflUsed;j>0;j--) *p1++ += 2*cos((*hh++ - *kk++ - *ll++)/3.);
2166  }
2167  else
2168  {
2169  for(int j=1;j<nbTranslationVectors;j++)
2170  {
2171  const REAL x=(*pTransVect)[j].tr[0];
2172  const REAL y=(*pTransVect)[j].tr[1];
2173  const REAL z=(*pTransVect)[j].tr[2];
2174  REAL *p1=transMult.data();
2175  const REAL * RESTRICT hh=mH2Pi.data();
2176  const REAL * RESTRICT kk=mK2Pi.data();
2177  const REAL * RESTRICT ll=mL2Pi.data();
2178  for(long j=mNbReflUsed;j>0;j--) *p1++ += cos(*hh++ *x + *kk++ *y + *ll++ *z );
2179  }
2180  }
2181  }
2182 
2183  pScattCompList=&(this->GetCrystal().GetScatteringComponentList());
2184 
2185  mvRealGeomSF_FullDeriv.clear();//:TODO: avoid clearing memory as much as possible
2186  mvImagGeomSF_FullDeriv.clear();
2187  CrystVector_REAL c(mNbReflUsed),s(mNbReflUsed);
2188  CrystMatrix_REAL allCoordsDeriv(nbSymmetrics,3);
2189  for(unsigned long i=0;i<nbComp;i++)
2190  {
2191  const REAL x0=(*pScattCompList)(i).mX;
2192  const REAL y0=(*pScattCompList)(i).mY;
2193  const REAL z0=(*pScattCompList)(i).mZ;
2194  const ScatteringPower *pScattPow=(*pScattCompList)(i).mpScattPow;
2195  const REAL popu= (*pScattCompList)(i).mOccupancy
2196  *(*pScattCompList)(i).mDynPopCorr;
2197  allCoords=pSpg->GetAllSymmetrics(x0,y0,z0,true,true);
2198  for(int j=0;j<nbSymmetrics;j++)
2199  {
2200  const REAL x=allCoords(j,0);
2201  const REAL y=allCoords(j,1);
2202  const REAL z=allCoords(j,2);
2203  {
2204  REAL *pc=c.data();
2205  REAL *ps=s.data();
2206  const REAL *hh=mH2Pi.data();
2207  const REAL *kk=mK2Pi.data();
2208  const REAL *ll=mL2Pi.data();
2209  #ifdef HAVE_SSE_MATHFUN
2210  const v4sf v4x=_mm_load1_ps(&x);
2211  const v4sf v4y=_mm_load1_ps(&y);
2212  const v4sf v4z=_mm_load1_ps(&z);
2213  // Can't multiply directly a vector by a scalar ?
2214  const v4sf v4popu=_mm_load1_ps(&popu); POSSIBLY_UNUSED(v4popu);
2215  int jj=mNbReflUsed;
2216  for(;jj>3;jj-=4)
2217  {
2218  v4sf v4sin,v4cos;
2219 // sincos_ps(_mm_setr_ps(*(hh )*x+ *(kk )*y + *(ll )*z,
2220 // *(hh+1)*x+ *(kk+1)*y + *(ll+1)*z,
2221 // *(hh+2)*x+ *(kk+2)*y + *(ll+2)*z,
2222 // *(hh+3)*x+ *(kk+3)*y + *(ll+3)*z),&v4sin,&v4cos);
2223  sincos_ps(_mm_add_ps(_mm_add_ps(_mm_mul_ps(_mm_load_ps(hh),v4x),
2224  _mm_mul_ps(_mm_load_ps(kk),v4y)
2225  ),
2226  _mm_mul_ps(_mm_load_ps(ll),v4z)
2227  ),&v4sin,&v4cos);
2228  _mm_store_ps(pc,v4cos);
2229  _mm_store_ps(ps,v4sin);
2230 
2231  hh+=4;kk+=4;ll+=4;pc+=4;ps+=4;
2232  }
2233  for(;jj>0;jj--)
2234  {
2235  const REAL tmp = *hh++ * x + *kk++ * y + *ll++ *z;
2236  *pc++ =cos(tmp);
2237  *ps++ =sin(tmp);
2238  }
2239  #else
2240  for(int jj=0;jj<mNbReflUsed;jj++)
2241  {
2242  const REAL tmp = *hh++ * x + *kk++ * y + *ll++ *z;
2243  *pc++ =cos(tmp);
2244  *ps++ =sin(tmp);
2245  }
2246  #endif
2247  }
2248  for(std::set<RefinablePar*>::iterator par=vPar.begin();par!=vPar.end();++par)
2249  {
2250  if((*par)==0) continue;
2251  if(vdx[*par].size()==0) continue;
2252  REAL dx =vdx[*par](i);
2253  REAL dy =vdy[*par](i);
2254  REAL dz =vdz[*par](i);
2255  const REAL dpopu=vdocc[*par](i);
2256 
2257  if((abs(dx)+abs(dy)+abs(dz)+abs(dpopu))==0) continue;
2258  if(mvRealGeomSF_FullDeriv[*par][pScattPow].size()==0)
2259  {
2260  mvRealGeomSF_FullDeriv[*par][pScattPow].resize(mNbRefl);
2261  mvRealGeomSF_FullDeriv[*par][pScattPow]=0;
2262  }
2263  if(mvImagGeomSF_FullDeriv[*par][pScattPow].size()==0)
2264  {
2265  mvImagGeomSF_FullDeriv[*par][pScattPow].resize(mNbRefl);
2266  mvImagGeomSF_FullDeriv[*par][pScattPow]=0;
2267  }
2268  pSpg->GetSymmetric(j,dx,dy,dz,true,true,true);
2269  const REAL *hh=mH2Pi.data();
2270  const REAL *kk=mK2Pi.data();
2271  const REAL *ll=mL2Pi.data();
2272  const REAL *pmult=transMult.data();
2273  REAL *rsf=mvRealGeomSF_FullDeriv[*par][pScattPow].data();
2274  REAL *isf=mvImagGeomSF_FullDeriv[*par][pScattPow].data();
2275  VFN_DEBUG_MESSAGE("ScatteringData::CalcGeomStructFactor_FullDeriv()comp="<<i<<", par="<<(*par)->GetName()<<", rs="<<mvRealGeomSF_FullDeriv[*par][pScattPow].size(),1)
2276  const REAL *pc=c.data();
2277  const REAL *ps=s.data();
2278  //cout<<setw(12)<<(*par)->GetName()<<":"<<setw(12)<<pScattPow->GetName()<<":"<<i<<","<<j
2279  // <<":x="<<setw(12)<<x<<",y="<<setw(12)<<y<<",z="<<setw(12)<<z
2280  // <<":dx="<<setw(12)<<dx<<",dy="<<setw(12)<<dy<<",dz="<<setw(12)<<dz<<",dpopu="<<setw(12)<<dpopu<<",popu="<<setw(12)<<popu<<",c0="<<setw(12)<<*pc<<",s0="<<setw(12)<<*ps<<endl;
2281 
2282  for(int jj=0;jj<mNbReflUsed;jj++)
2283  {// :TODO: directly calculate corrected intensities, instead of 1) geom 2) F and 3) F^2 4) corrected intensity... Faster, less storage !
2284  *rsf += (dpopu * *pc - popu* *ps * (*hh * dx + *kk * dy + *ll * dz))* *pmult;
2285  if(!hasinv) *isf += (dpopu * *ps + popu* *pc * (*hh * dx + *kk * dy + *ll * dz))* *pmult;
2286  //if(jj<6) cout<<" rsf0+="<<setw(12)<<(dpopu * *pc - popu* *ps * (*hh * dx + *kk * dy + *ll * dz))* *pmult<<" ("<<setw(12)<<*rsf
2287  // <<"),isf0+="<<setw(12)<<(dpopu * *ps + popu* *pc * (*hh * dx + *kk * dy + *ll * dz))* *pmult
2288  // <<" ("<<setw(12)<<*isf<<")"<<endl;
2289  ps++;pc++;hh++;kk++;ll++;pmult++;rsf++;isf++;
2290  }
2291  }
2292  }
2293  }
2294  if(true==pSpg->HasInversionCenter())
2295  {
2296  if(false==pSpg->IsInversionCenterAtOrigin())
2297  {
2298  //:TODO: if there is an inversion center not in (0,0,0), apply a constant phase
2299  }
2300  }
2301 
2302  TAU_PROFILE_STOP(timer2);
2303  #if 0
2304  std::vector<const CrystVector_REAL*> v;
2305  v.push_back(&mH);
2306  v.push_back(&mK);
2307  v.push_back(&mL);
2308  std::map< std::pair<const ScatteringPower *,RefinablePar*>,CrystVector_REAL> mr,mi;
2310 
2311  for(std::set<RefinablePar*>::iterator par=vPar.begin();par!=vPar.end();++par)
2312  {
2313  for(std::map<const ScatteringPower*,CrystVector_REAL>::iterator pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos)
2314  {
2315  const ScatteringPower *pScattPow=pos->first;
2316  cout<<(*par)->GetName()<<","<<pScattPow->GetName();
2317  if(mvRealGeomSF_FullDeriv[*par][pScattPow].size()==0)
2318  {
2319  cout<<" => skipped (deriv==0)"<<endl;
2320  continue;
2321  }
2322  else cout <<endl;
2323  const REAL step=(*par)->GetDerivStep();
2324  (*par)->Mutate(step);
2325  this->CalcGeomStructFactor();
2326  mr[make_pair(pScattPow,*par)]=mvRealGeomSF[pScattPow];
2327  mi[make_pair(pScattPow,*par)]=mvImagGeomSF[pScattPow];
2328  (*par)->Mutate(-2*step);
2329  this->CalcGeomStructFactor();
2330  mr[make_pair(pScattPow,*par)]-=mvRealGeomSF[pScattPow];
2331  mr[make_pair(pScattPow,*par)]/=step*2;
2332  mi[make_pair(pScattPow,*par)]-=mvImagGeomSF[pScattPow];
2333  mi[make_pair(pScattPow,*par)]/=step*2;
2334  (*par)->Mutate(step);
2335 
2336  v.push_back(&(mvRealGeomSF_FullDeriv[*par][pScattPow]));
2337  v.push_back(&(mr[make_pair(pScattPow,*par)]));
2338  if(!hasinv)
2339  {
2340  v.push_back(&(mvImagGeomSF_FullDeriv[*par][pScattPow]));
2341  v.push_back(&(mi[make_pair(pScattPow,*par)]));
2342  }
2343  if(v.size()>20)break;
2344  }
2345  if(v.size()>20)break;
2346  }
2347  cout<<"############################ Geom Fhkl Deriv Real, Imag ##############################"
2348  <<endl<<FormatVertVectorHKLFloats<REAL>(v,11,4,20)
2349  <<"############################ END GeomF hkl Deriv Real, Imag ##############################"<<endl;
2350  cout<<"############################ X Y Z Occ ##############################"
2351  <<endl<<FormatVertVector<REAL>(vdx[*(vPar.begin())],vdy[*(vPar.begin())],vdz[*(vPar.begin())],vdocc[*(vPar.begin())],8,4,20)<<endl
2352  <<"############################ END X Y Z Occ ##############################"<<endl;
2353  //exit(0);
2354  #endif
2355 
2356  // We can use geom struct fact calculated at the beginning, since parameters are back to the same values.
2358 }
2359 
2361 {
2362  // Assume this is called by ScatteringData::CalcStructFactor()
2363  // and that we already have computed geometrical structure factors
2364  VFN_DEBUG_ENTRY("ScatteringData::CalcLuzzatiFactor",3)
2365  bool useLuzzati=false;
2366  for(map<const ScatteringPower*,CrystVector_REAL>::const_iterator
2367  pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos)
2368  {
2369  if(pos->first->GetMaximumLikelihoodPositionError()!=0)
2370  {
2371  useLuzzati=true;
2372  break;
2373  }
2374  }
2375  if(!useLuzzati)
2376  {
2377  mvLuzzatiFactor.clear();
2378  VFN_DEBUG_EXIT("ScatteringData::CalcLuzzatiFactor(): not needed, no positionnal errors",3)
2379  return;
2380  }
2381  bool recalc=false;
2382  if( (mClockTheta >mClockLuzzatiFactor)
2383  ||(mClockGeomStructFact>mClockLuzzatiFactor)//checks if occupancies changed
2384  ||(mClockNbReflUsed>mClockLuzzatiFactor))
2385  {
2386  //if(mClockTheta >mClockLuzzatiFactor)cout<<"1"<<endl;
2387  //if(mClockGeomStructFact>mClockLuzzatiFactor)cout<<"2"<<endl;
2388  //if(mClockNbReflUsed>mClockLuzzatiFactor)cout<<"3"<<endl;
2389  recalc=true;
2390  }
2391  else
2392  {
2393  for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--)
2394  {
2395  if(mpCrystal->GetScatteringPowerRegistry().GetObj(i)
2396  .GetMaximumLikelihoodParClock()>mClockLuzzatiFactor)
2397  {
2398  recalc=true;
2399  break;
2400  }
2401  }
2402  }
2403 
2404  if(false==recalc)
2405  {
2406  VFN_DEBUG_EXIT("ScatteringData::CalcLuzzatiFactor(): no recalc needed",3)
2407  return;
2408  }
2409  TAU_PROFILE("ScatteringData::CalcLuzzatiFactor()","void ()",TAU_DEFAULT);
2410 
2411  for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--)
2412  {
2413  const ScatteringPower* pScattPow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i));
2414  if(0 == pScattPow->GetMaximumLikelihoodPositionError())
2415  {
2416  mvLuzzatiFactor[pScattPow].resize(0);
2417  }
2418  else
2419  {
2420  mvLuzzatiFactor[pScattPow].resize(mNbRefl);
2421  const REAL b=-(8*M_PI*M_PI)* pScattPow->GetMaximumLikelihoodPositionError()
2422  * pScattPow->GetMaximumLikelihoodPositionError();
2423  const REAL *stol=this->GetSinThetaOverLambda().data();
2424  REAL *fact=mvLuzzatiFactor[pScattPow].data();
2425  for(long j=0;j<mNbReflUsed;j++) {*fact++ = exp(b * *stol * *stol);stol++;}
2426  VFN_DEBUG_MESSAGE("ScatteringData::CalcLuzzatiFactor():"<<pScattPow->GetName()<<endl<<
2428  mvRealGeomSF[pScattPow],mvImagGeomSF[pScattPow],
2429  mvScatteringFactor[pScattPow],mvLuzzatiFactor[pScattPow],10,4,mNbReflUsed
2430  ),2);
2431  }
2432  }
2433  mClockLuzzatiFactor.Click();
2434  VFN_DEBUG_EXIT("ScatteringData::CalcLuzzatiFactor(): no recalc needed",3)
2435 }
2436 
2438 {
2439  // this is called by CalcStructFactor(), after the calculation of the structure factors,
2440  // and the recomputation of Luzzati factors has already been asked
2441  // So we only recompute if these clocks have changed.
2442  //
2443  // The Crystal::mMasterClockScatteringPower will tell the last time the number of ghost
2444  // atoms has been changed in any of the scattpow.
2445 
2446  if( (mClockFhklCalcVariance>mClockLuzzatiFactor)
2447  &&(mClockFhklCalcVariance>mClockStructFactor)
2448  &&(mClockFhklCalcVariance>mpCrystal->GetMasterClockScatteringPower())) return;
2449 
2450  bool hasGhostAtoms=false;
2451  for(map<const ScatteringPower*,CrystVector_REAL>::const_iterator
2452  pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos)
2453  {
2454  if(pos->first->GetMaximumLikelihoodNbGhostAtom()!=0)
2455  {
2456  hasGhostAtoms=true;
2457  break;
2458  }
2459  }
2460 
2461  if( (0==mvLuzzatiFactor.size())&&(!hasGhostAtoms))
2462  {
2463  mFhklCalcVariance.resize(0);
2464  return;
2465  }
2466  VFN_DEBUG_ENTRY("ScatteringData::CalcStructFactVariance()",3)
2467  TAU_PROFILE("ScatteringData::CalcStructFactVariance()","void ()",TAU_DEFAULT);
2468  bool needVar=false;
2469 
2470  map<const ScatteringPower*,REAL> vComp;
2471  {
2473  const long nbComp=pList->GetNbComponent();
2474  const ScatteringComponent *pComp;
2475  for(long i=0;i<nbComp;i++)
2476  {
2477  pComp=&((*pList)(i));
2478  vComp[pComp->mpScattPow]=0;
2479  }
2480  for(long i=0;i<nbComp;i++)
2481  {
2482  pComp=&((*pList)(i));
2483  vComp[pComp->mpScattPow]+= pComp->mOccupancy * pComp->mDynPopCorr;
2484  }
2485  for(map<const ScatteringPower*,REAL>::iterator
2486  pos=vComp.begin();pos!=vComp.end();++pos)
2487  pos->second *= this->GetCrystal().GetSpaceGroup().GetNbSymmetrics();
2488  }
2489  // Ghost atoms
2490  map<const ScatteringPower*,REAL> vGhost;
2491  {
2492  const long nbScattPow=mpCrystal->GetScatteringPowerRegistry().GetNb();
2493  const long mult=this->GetCrystal().GetSpaceGroup().GetNbSymmetrics();
2494  for(int i=0;i<nbScattPow;i++)
2495  {
2496  const ScatteringPower* pow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i));
2497  const REAL nb=pow->GetMaximumLikelihoodNbGhostAtom();
2498  vGhost[pow]=nb*mult;
2499  }
2500  }
2501 
2502  if(mFhklCalcVariance.numElements() == mNbRefl)
2503  {
2504  REAL *pVar=mFhklCalcVariance.data();
2505  for(long j=0;j<mNbReflUsed;j++) *pVar++ = 0;
2506  }
2507 
2508  for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--)
2509  {
2510  const ScatteringPower* pScattPow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i));
2511  if( (mvLuzzatiFactor[pScattPow].numElements()==0)
2512  &&(vGhost[pScattPow]==0)) continue;
2513  needVar=true;
2514  if(mFhklCalcVariance.numElements() != mNbRefl)
2515  {
2516  mFhklCalcVariance.resize(mNbRefl);
2517  REAL *pVar=mFhklCalcVariance.data();
2518  for(long j=0;j<mNbReflUsed;j++) *pVar++ = 0;
2519  }
2520  // variance on real & imag parts of the structure factor
2521  const REAL *pScatt=mvScatteringFactor[pScattPow].data();
2522  const int *pExp=mExpectedIntensityFactor.data();
2523  REAL *pVar=mFhklCalcVariance.data();
2524  if(mvLuzzatiFactor[pScattPow].numElements()==0)
2525  {
2526  const REAL nbghost=vGhost[pScattPow];
2527  for(long j=0;j<mNbReflUsed;j++)
2528  {
2529  *pVar++ += *pExp++ * *pScatt * *pScatt * nbghost;
2530  pScatt++;
2531  }
2532  }
2533  else
2534  {
2535  const REAL *pLuz=mvLuzzatiFactor[pScattPow].data();
2536  const REAL occ=vComp[pScattPow];
2537  const REAL nbghost=vGhost[pScattPow];
2538  for(long j=0;j<mNbReflUsed;j++)
2539  {
2540  *pVar++ += *pExp++ * *pScatt * *pScatt * ( occ*(1 - *pLuz * *pLuz) + nbghost);
2541  pScatt++; pLuz++;
2542  }
2543  }
2544  }
2545  if(false == needVar) mFhklCalcVariance.resize(0);
2546 
2547  mClockFhklCalcVariance.Click();
2548  VFN_DEBUG_EXIT("ScatteringData::CalcStructFactVariance()",3)
2549 }
2550 
2551 }//namespace ObjCryst
The namespace which includes all objects (crystallographic and algorithmic) in ObjCryst++.
Definition: doc-main.h:25
const RefParType * gpRefParTypeScattDataCorrIntPO_Direction
Parameter type for preferred orientation direction.
const RefParType * gpRefParTypeScattDataScale
Type for scattering data scale factors.
const RefParType * gpRefParTypeScattDataProfileWidth
Type for reflection profile width.
RadiationType
Type of radiation used.
Definition: General.h:96
const RefParType * gpRefParTypeScattDataCorrIntAbsorp
Parameter type for absorption correction.
WavelengthType
Incident beam characteristics : monochromatic, X-Ray tube with Alpha1 and alpha2, MAD (a few waveleng...
Definition: General.h:102
const RefParType * gpRefParTypeScattDataCorrPos
Parameter type for correction to peak positions.
const RefParType * gpRefParTypeScattDataProfile
Type for reflection profile.
const RefParType * gpRefParTypeScattDataCorrIntPO_Fraction
Parameter type for fraction of preferred orientation.
const RefParType * gpRefParTypeScattDataBackground
Parameter type for background intensity.
const RefParType * gpRefParTypeScattDataCorr
Generic type for scattering data correction parameter.
const RefParType * gpRefParTypeScattDataProfileType
Type for reflection profiles type (e.g. gaussian/lorentzian mix)
const RefParType * gpRefParTypeScattDataCorrInt_Ellipsoid
Parameter type for the ellipsoid coefficient.
const RefParType * gpRefParTypeScattDataCorrIntPO_Amplitude
Parameter type for the amplitude of preferred orientation.
const RefParType * gpRefParTypeScattDataCorrInt
Generic type for correction to calculated intensities.
const RefParType * gpRefParTypeScattDataProfileAsym
Type for reflection profile asymmetry.
const RefParType * gpRefParTypeScattData
Generic type for scattering data.
const RefParType * gpRefParTypeScattDataCorrIntPolar
Parameter type for polarization correction.
const RefParType * gpRefParTypeScattDataCorrIntExtinc
Parameter type for extinction correction.
Crystal class: Unit cell, spacegroup, scatterers.
Definition: Crystal.h:98
virtual const ScatteringComponentList & GetScatteringComponentList() const
Get the list of all scattering components.
Definition: Crystal.cpp:298
const RefinableObjClock & GetClockScattererList() const
When was the list of scatterers last changed ?
Definition: Crystal.cpp:1196
ObjRegistry< ScatteringPower > & GetScatteringPowerRegistry()
Get the registry of ScatteringPower included in this Crystal.
Definition: Crystal.cpp:236
const RefinableObjClock & GetClockScattCompList() const
Get the list of all scattering components.
Definition: Crystal.cpp:335
const RefinableObjClock & GetMasterClockScatteringPower() const
Get the clock which reports all changes in ScatteringPowers.
Definition: Crystal.cpp:294
Exception class for ObjCryst++ library.
Definition: General.h:122
Class to define the radiation (type, monochromaticity, wavelength(s)) of an experiment.
REAL mLinearPolarRate
Linear Polarization Rate (default:0, X-Ray tube unmonochromatized)
void Print() const
Print to screen/console the charcteristics of the radiation.
CrystVector_REAL mWavelength
Wavelength of the Experiment, in Angstroems.
string mXRayTubeName
Name of the X-Ray tube used, if relevant.
RefObjOpt mRadiationType
Neutron ? X-Ray ? (Electron: unimplemented)
REAL GetXRayTubeAlpha2Alpha1Ratio() const
Get the Kalpha2/Kalpha1 ratio.
WavelengthType GetWavelengthType() const
Get the Wavelength type (monochromatic, Alpha1+Alpha2, Time Of Flight...)
REAL mXRayTubeDeltaLambda
Absolute difference between alpha1 and alpha2, in angstroems.
const CrystVector_REAL & GetWavelength() const
Get the wavelength(s) in Angstroems.
REAL mXRayTubeAlpha2Alpha1Ratio
Ratio alpha2/alpha1 (should be 0.5)
REAL GetXRayTubeDeltaLambda() const
Get the wavelength difference for Alpha1 and Alpha2.
const RefinableObjClock & GetClockWavelength() const
Last time the wavelength has been changed.
void SetRadiationType(const RadiationType)
Set the radiation type (X-Rays, Neutron)
RefObjOpt mWavelengthType
monochromatic ? Alpha1 & Alpha2 ? Multi-Wavelength ?
const RefinableObjClock & GetClockRadiation() const
Last time the nature (X-Rays/Neutron, number of wavelengths)radiation has been changed.
Radiation()
Default constructor.
void SetWavelength(const REAL)
Set the (monochromatic) wavelength of the beam.
virtual const string & GetClassName() const
Name for this class ("RefinableObj", "Crystal",...).
void SetWavelengthType(const WavelengthType &type)
Set the Wavelength type (monochromatic, Alpha1+Alpha2, Time Of Flight...)
RadiationType GetRadiationType() const
Get the radiation type (X-Rays, Neutron)
Class to compute structure factors for a set of reflections and a Crystal.
long mNbReflUsed
Number of reflections which are below the max.
RefinableObjClock mClockNbReflUsed
Clock recording the last time the number of reflections used has increased.
virtual void SetHKL(const CrystVector_REAL &h, const CrystVector_REAL &k, const CrystVector_REAL &l)
input H,K,L
CrystVector_REAL mSinThetaLambda
for the crystal and the reflections in ReciprSpace
const RefinableObjClock & GetClockNbReflBelowMaxSinThetaOvLambda() const
Clock the last time the number of reflections used was changed.
map< const ScatteringPower *, CrystVector_REAL > mvScatteringFactor
Scattering factors for each ScatteringPower, as vectors with NbRefl elements.
map< const ScatteringPower *, REAL > mvFprime
Anomalous X-Ray scattering term f' and f" are stored here for each ScatteringPower We store here only...
virtual const Radiation & GetRadiation() const =0
Get the radiation object for this data.
const map< const ScatteringPower *, CrystVector_REAL > & GetScatteringFactor() const
Scattering factors for each ScatteringPower, as vectors with NbRefl elements.
REAL mGlobalBiso
Global Biso, affecting the overall structure factor for all reflections (but not the structure factor...
RefinableObjClock mClockStructFactor
Clock for the structure factor.
virtual void PrintFhklCalc(ostream &os=cout) const
Print H, K, L F^2 Re(F) Im(F) theta sin(theta)/lambda for all reflections.
void CalcGeomStructFactor() const
Compute the 'Geometrical Structure Factor' for each ScatteringPower of the Crystal.
RefinableObjClock mClockFhklObsSq
Last time observed squared structure factors were altered.
RefinableObjClock mClockGlobalTemperatureFact
last time the global temperature factor was computed
const CrystVector_REAL & GetH2Pi() const
Return the 1D array of H coordinates for all reflections, multiplied by 2*pi.
RefinableObjClock mClockTheta
Clock the last time theta was computed.
const CrystVector_REAL & GetSinThetaOverLambda() const
Return an array with for all reflections.
const CrystVector_REAL & GetK() const
Return the 1D array of K coordinates for all reflections.
REAL GetMaxSinThetaOvLambda() const
Get the maximum value for sin(theta)/lambda.
bool mIgnoreImagScattFact
Ignore imaginary part of scattering factor.
virtual void GenHKLFullSpace(const REAL maxTheta, const bool unique=false)
Generate a list of h,k,l to describe a full reciprocal space, up to a given maximum theta value.
CrystVector_REAL GetWavelength() const
wavelength of the experiment (in Angstroems)
void CalcLuzzatiFactor() const
Calculate the Luzzati factor associated to each ScatteringPower and each reflection,...
RefinableObjClock mClockThermicFact
Clock the last time temperature factors were computed.
bool IsIgnoringImagScattFact() const
If true, then the imaginary part of the scattering factor is ignored during Structure factor computat...
virtual void PrepareHKLarrays() const
const CrystVector_REAL & GetL2Pi() const
Return the 1D array of L coordinates for all reflections, multiplied by 2*pi.
const CrystVector_REAL & GetTheta() const
Return an array with theta values for all reflections.
const CrystVector_REAL & GetReflZ() const
Return the 1D array of orthonormal z coordinates for all reflections (recipr. space)
virtual void SetMaxSinThetaOvLambda(const REAL max)
Set the maximum value for sin(theta)/lambda.
virtual void SetCrystal(Crystal &crystal)
Set the crystal for this experiment.
virtual void SetApproximationFlag(const bool allow)
Enable or disable numerical approximations.
CrystVector_REAL mFhklCalcSq
F(HKL)^2 calc for each reflection.
void CalcStructFactVariance() const
Calculate the variance associated to the calculated structure factor.
const CrystVector_REAL & GetReflX() const
Return the 1D array of orthonormal x coordinates for all reflections (recipr. space)
virtual void GenHKLFullSpace2(const REAL maxsithsl, const bool unique=false)
Generate a list of h,k,l to describe a full reciprocal space, up to a given maximum theta value.
RefinableObjClock mClockStructFactorSq
Clock for the square modulus of the structure factor.
map< const ScatteringPower *, CrystVector_REAL > mvTemperatureFactor
Thermic factors for each ScatteringPower, as vectors with NbRefl elements.
const CrystVector_REAL & GetH() const
Return the 1D array of H coordinates for all reflections.
CrystVector_REAL mFhklObsSq
Observed squared structure factors (zero-sized if none)
const CrystVector_REAL & GetFhklCalcSq() const
Returns the Array of calculated |F(hkl)|^2 for all reflections.
void CalcGlobalTemperatureFactor() const
Compute the overall temperature factor affecting all reflections.
const CrystVector_REAL & GetFhklObsSq() const
Returns the vector of observed |F(hkl)|^2 for all reflections.
RadiationType GetRadiationType() const
Neutron or x-ray experiment ? Wavelength ?
bool mUseFastLessPreciseFunc
Use faster, but less precise, approximations for functions? (integer approximations to compute sin an...
virtual CrystVector_long SortReflectionBySinThetaOverLambda(const REAL maxSTOL=-1.) const
const RefinableObjClock & GetClockTheta() const
Clock the last time the sin(theta)/lambda and theta arrays were re-computed.
bool HasCrystal() const
Has a Crystal structure associated yet ?
CrystVector_int mExpectedIntensityFactor
Expected intensity factor for all reflections.
CrystVector_REAL mFhklCalcReal
real &imaginary parts of F(HKL)calc
CrystVector_REAL mFhklCalcVariance
The variance on all calculated structure factors, taking into account the positionnal errors and the ...
map< const ScatteringPower *, CrystVector_REAL > mvLuzzatiFactor
The Luzzati 'D' factor for each scattering power and each reflection.
Crystal * mpCrystal
Pointer to the crystal corresponding to this experiment.
RefinableObjClock mClockScattFactor
Clock the last time scattering factors were computed.
virtual void CalcResonantScattFactor() const
CrystVector_REAL mX
reflection coordinates in an orthonormal base
map< const ScatteringPower *, CrystVector_REAL > mvRealGeomSF
Geometrical Structure factor for each ScatteringPower, as vectors with NbRefl elements.
virtual void CalcSinThetaLambda() const
const CrystVector_REAL & GetL() const
Return the 1D array of L coordinates for all reflections.
RefinableObjClock mClockGlobalBiso
last time the global Biso factor was modified
void CalcStructFactor() const
Compute the overall structure factor (real and imaginary part).
long mNbRefl
Number of H,K,L reflections.
const CrystVector_REAL & GetFhklCalcImag() const
Access to imaginary part of F(hkl)calc.
virtual const CrystMatrix_REAL & GetBMatrix() const
Get access to the B matrix used to compute reflection positions.
CrystVector_REAL mH
H,K,L coordinates.
CrystVector_long mIntH
H,K,L integer coordinates.
CrystVector_long EliminateExtinctReflections()
REAL mMaxSinThetaOvLambda
Maximum sin(theta)/lambda for all calculations (10 by default).
void SetFhklObsSq(const CrystVector_REAL &obs)
Set the vector of observed |F(hkl)|^2 for all reflections.
virtual void PrintFhklCalcDetail(ostream &os=cout) const
Print H, K, L sin(theta)/lambda theta F^2 Re(F) Im(F) [Re(F) Im(F)]_i, where [Re(F) Im(F)]_i are the ...
RefinableObjClock mClockGeomStructFact
Clock the last time the geometrical structure factors were computed.
void SetIsIgnoringImagScattFact(const bool b)
If true, then the imaginary part of the scattering factor is ignored during Structure factor computat...
const CrystVector_REAL & GetReflY() const
Return the 1D array of orthonormal y coordinates for all reflections (recipr. space)
CrystVector_REAL mTheta
theta for the crystal and the HKL in ReciprSpace (in radians)
long GetNbRefl() const
Return the number of reflections in this experiment.
virtual long GetNbReflBelowMaxSinThetaOvLambda() const
Recalc, and get the number of reflections which should be actually used, due to the maximuml sin(thet...
CrystVector_REAL mGlobalTemperatureFactor
Global Biso factor.
const Crystal & GetCrystal() const
Const access to the data's crystal.
RefinableObjClock mClockScattFactorResonant
Clock the last time resonant scattering factors were computed.
virtual void EndOptimization()
This should be called by any optimization class at the end of an optimization.
const CrystVector_REAL & GetFhklCalcReal() const
Access to real part of F(hkl)calc.
CrystVector_REAL mH2Pi
H,K,L coordinates, multiplied by 2PI.
const CrystVector_REAL & GetK2Pi() const
Return the 1D array of K coordinates for all reflections, multiplied by 2*pi.
RefinableObjClock mClockHKL
Clock for the list of hkl.
virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false)
This should be called by any optimization class at the begining of an optimization.
CrystVector_int mMultiplicity
Multiplicity for each reflections (mostly for powder diffraction)
Abstract Base Class to describe the scattering power of any Scatterer component in a crystal.
virtual CrystVector_REAL GetTemperatureFactor(const ScatteringData &data, const int spgSymPosIndex=-1) const =0
Get the temperature factor for all reflections of a given ScatteringData object.
virtual CrystMatrix_REAL GetResonantScattFactReal(const ScatteringData &data, const int spgSymPosIndex=-1) const =0
Get the real part of the resonant scattering factor.
REAL GetMaximumLikelihoodNbGhostAtom() const
Maximum Likelihood: get the number of ghost elements per asymmetric unit.
virtual CrystMatrix_REAL GetResonantScattFactImag(const ScatteringData &data, const int spgSymPosIndex=-1) const =0
Get the imaginary part of the resonant scattering factor.
REAL GetMaximumLikelihoodPositionError() const
Maximum Likelihood: get the estimated error (sigma) on the positions for this kind of element.
virtual CrystVector_REAL GetScatteringFactor(const ScatteringData &data, const int spgSymPosIndex=-1) const =0
Get the Scattering factor for all reflections of a given ScatteringData object.
A scattering position in a crystal, associated with the corresponding occupancy and a pointer to the ...
const ScatteringPower * mpScattPow
The ScatteringPower associated with this position.
REAL mDynPopCorr
Dynamical Population Correction.
list of scattering positions in a crystal, associated with the corresponding occupancy and a pointer ...
long GetNbComponent() const
Number of components.
The crystallographic space group, and the cell choice.
Definition: SpaceGroup.h:105
int GetNbSymmetrics(const bool noCenter=false, const bool noTransl=false) const
Return the number of equivalent positions in the spacegroup, ie the multilicity of the general positi...
Definition: SpaceGroup.cpp:418
bool IsInversionCenterAtOrigin() const
Is the center of symmetry at the origin ?
Definition: SpaceGroup.cpp:463
unsigned int GetExpectedIntensityFactor(const REAL h, const REAL k, const REAL l) const
Get the "expected intensity factor" for a given reflection.
Definition: SpaceGroup.cpp:564
int GetSpaceGroupNumber() const
Id number of the spacegroup.
Definition: SpaceGroup.cpp:251
int GetNbTranslationVectors() const
Number of translation vectors (1 for 'P' cells, 2 for 'I', 4 for 'F',etc..)
Definition: SpaceGroup.cpp:261
bool HasInversionCenter() const
Is centrosymmetric ?
Definition: SpaceGroup.cpp:462
CrystMatrix_REAL GetAllSymmetrics(const REAL x, const REAL y, const REAL z, const bool noCenter=false, const bool noTransl=false, const bool noIdentical=false) const
Get all equivalent positions of a (xyz) position.
Definition: SpaceGroup.cpp:276
void GetSymmetric(unsigned int i, REAL &x, REAL &y, REAL &z, const bool noCenter=false, const bool noTransl=false, const bool derivative=false) const
Get all equivalent positions of a (xyz) position.
Definition: SpaceGroup.cpp:368
const RefinableObjClock & GetClockSpaceGroup() const
Get the SpaceGroup Clock (corresponding to the time of the initialization of the SpaceGroup)
Definition: SpaceGroup.cpp:466
const std::vector< SpaceGroup::TRx > & GetTranslationVectors() const
Return all Translation Vectors, as a 3 columns-array.
Definition: SpaceGroup.cpp:266
const cctbx::sgtbx::space_group & GetCCTbxSpg() const
Get the underlying cctbx Spacegroup object.
Definition: SpaceGroup.cpp:464
CrystVector_REAL GetLatticePar() const
Lattice parameters (a,b,c,alpha,beta,gamma) as a 6-element vector in Angstroems and radians.
Definition: UnitCell.cpp:92
const SpaceGroup & GetSpaceGroup() const
Access to the SpaceGroup object.
Definition: UnitCell.cpp:322
const CrystMatrix_REAL & GetBMatrix() const
Get the 'B' matrix (UnitCell::mBMatrix)for the UnitCell (orthogonalization matrix for the given latti...
Definition: UnitCell.cpp:237
const RefinableObjClock & GetClockLatticePar() const
last time the Lattice parameters were changed
Definition: UnitCell.cpp:333
class of refinable parameter types.
Definition: RefinableObj.h:80
We need to record exactly when refinable objects have been modified for the last time (to avoid re-co...
Definition: RefinableObj.h:140
void Reset()
Reset a Clock to 0, to force an update.
void AddChild(const RefinableObjClock &)
Add a 'child' clock.
void Click()
Record an event for this clock (generally, the 'time' an object has been modified,...
Generic class for parameters of refinable objects.
Definition: RefinableObj.h:225
void SetIsUsed(const bool)
Is the parameter used (if not, it is simply irrelevant in the model) ?
virtual void EndOptimization()
This should be called by any optimization class at the end of an optimization.
void AddPar(const RefinablePar &newRefPar)
Add a refinable parameter.
bool IsBeingRefined() const
Is the object being refined ? (Can be refined by one algorithm at a time only.)
virtual void RegisterClient(RefinableObj &) const
Register a new object using this object.
RefinablePar & GetPar(const long i)
Access all parameters in the order they were inputted.
virtual const string & GetName() const
Name of the object.
virtual void SetApproximationFlag(const bool allow)
Enable or disable numerical approximations.
virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false)
This should be called by any optimization class at the begining of an optimization.
void AddOption(RefObjOpt *opt)
int mOptimizationDepth
Is the object being refined or optimized ? if mOptimizationDepth=0, no optimization is taking place.
virtual void DeRegisterClient(RefinableObj &) const
Deregister an object (which not any more) using this object.
virtual void UpdateDisplay() const
If there is an interface, this should be automatically be called each time there is a 'new,...
RefinableObjClock mClockMaster
Master clock, which is changed whenever the object has been altered.
void AddSubRefObj(RefinableObj &)
output a string with a fixed length (adding necessary space or removing excess characters) :
Output vectors as column arrays, with the first 3 columns printed as integers.