FOX/ObjCryst++  2022
SpaceGroup.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 LibCryst++ AsymmetricUnit and SpaceGroup classes
21 *
22 */
23 
24 #include <iomanip>
25 #include <cmath>
26 #include <typeinfo>
27 
28 #include "cctbx/sgtbx/space_group.h"
29 #include "cctbx/sgtbx/brick.h"
30 #include "cctbx/miller/sym_equiv.h"
31 #include <boost/rational.hpp>
32 
33 #include "ObjCryst/ObjCryst/SpaceGroup.h"
34 #include "ObjCryst/Quirks/VFNStreamFormat.h" //simple formatting of integers, REALs..
35 #include "ObjCryst/ObjCryst/GeomStructFactor.h" //Geometrical Struct Factor definitions
36 #include "ObjCryst/Quirks/VFNDebug.h"
37 
38 
39 #include <fstream>
40 
41 #define POSSIBLY_UNUSED(expr) (void)(expr)
42 
43 namespace ObjCryst
44 {
45 
46 #include "ObjCryst/Quirks/VFNDebug.h"
47 
48 // We need to force the C locale when using cctbx (when interpreting xyz strings)
49 tmp_C_Numeric_locale::tmp_C_Numeric_locale()
50 {
51  char *old;
52  old=setlocale(LC_NUMERIC,NULL);
53  mLocale=old;
54  setlocale(LC_NUMERIC,"C");
55 }
56 
57 tmp_C_Numeric_locale::~tmp_C_Numeric_locale()
58 {
59  setlocale(LC_NUMERIC,mLocale.c_str());
60 }
61 
63 //
64 // AsymmetricUnit
65 //
68 {
69  VFN_DEBUG_MESSAGE("AsymmetricUnit::AsymmetricUnit()",5)
70  mXmin=0;
71  mYmin=0;
72  mZmin=0;
73  mXmax=1;
74  mYmax=1;
75  mZmax=1;
76 }
77 
79 {
80  VFN_DEBUG_MESSAGE("AsymmetricUnit::AsymmetricUnit(SpGroup)",5)
81  this->SetSpaceGroup(spg);
82 }
83 
84 AsymmetricUnit::~AsymmetricUnit()
85 {
86  VFN_DEBUG_MESSAGE("AsymmetricUnit::~AsymmetricUnit(SpGroup)",5)
87 }
88 
90 {
91  VFN_DEBUG_MESSAGE("AsymmetricUnit::SetSpaceGroup(SpGroup)",5)
92  tmp_C_Numeric_locale tmploc;
93  # if 0
94  TAU_PROFILE("(AsymmetricUnit::SetSpaceGroup)","void (SpaceGroup)",TAU_DEFAULT);
95  mXmin=0.;
96  mYmin=0.;
97  mZmin=0.;
98  mXmax=1.;
99  mYmax=1.;
100  mZmax=1.;
101  if(1==spg.GetSpaceGroupNumber()) return;//no need to search an asymmetric unit
102  // Test points=reular grid of points inside the unit cell
103  // All points must be or have at least a symmetric in the asymmetric unit
104  const long nbPoints=13;
105  CrystMatrix_REAL testPoints(nbPoints*nbPoints*nbPoints,3);
106  {
107  long l=0;
108  for(long i=0;i<nbPoints;i++)
109  for(long j=0;j<nbPoints;j++)
110  for(long k=0;k<nbPoints;k++)
111  {
112  testPoints(l ,0)=i/(REAL)nbPoints;
113  testPoints(l ,1)=j/(REAL)nbPoints;
114  testPoints(l++,2)=k/(REAL)nbPoints;
115  }
116  }
117  testPoints += 0.01;
118 
119  CrystVector_REAL vert(8);//vertices limits
120  vert(0)=1/8.; vert(1)=1/6.; vert(2)=1/4.; vert(3)=1/3.;
121  vert(4)=1/2.; vert(5)=2/3.; vert(6)=3/4.; vert(7)=1.;
122 
123  const int NbStep=vert.numElements();
124 
125  CrystMatrix_REAL coords;
126 
127  double junk;
128 
129  REAL minVolume=1.;
130 
131  bool allPtsInAsym,tmp;
132  for(long nx=0;nx<NbStep;nx++)
133  for(long ny=0;ny<NbStep;ny++)
134  for(long nz=0;nz<NbStep;nz++)
135  {
136  if(minVolume<(vert(nx)*vert(ny)*vert(nz)-.0001)) break;
137  allPtsInAsym=true;
138  for(int i=0;i<testPoints.rows();i++)
139  {
140  coords=spg.GetAllSymmetrics(testPoints(i,0),testPoints(i,1),testPoints(i,2));
141  for(long j=0;j<coords.numElements();j++) coords(j)=modf(coords(j)+10.,&junk) ;
142  tmp=false;
143  for(long j=0;j<coords.rows();j++)
144  {//Test if at least one of the symmetrics is in the parallelepiped
145  if( (coords(j,0) < vert(nx))
146  &&(coords(j,1) < vert(ny))
147  &&(coords(j,2) < vert(nz)))
148  {
149  //cout << modf(coords(j,0)+10.,junk) << " "
150  // << modf(coords(j,1)+10.,junk) << " "
151  // << modf(coords(j,2)+10.,junk) << endl;
152  tmp=true;
153  break;
154  }
155  }
156  if(false==tmp)
157  {
158  //cout << " Rejected:"<<vert(nx)<<" "<<vert(ny)<<" "<<vert(nz)<<" "<<i<<endl;
159  //cout << coords <<endl;
160  allPtsInAsym=false;
161  break;
162  }
163  }
164  if( (true==allPtsInAsym))
165  {
166  mXmax=vert(nx);
167  mYmax=vert(ny);
168  mZmax=vert(nz);
169  VFN_DEBUG_MESSAGE("->ACCEPTED:" << mXmax <<" "<< mYmax <<" "<< mZmax <<endl,2)
170  //cout << "->ACCEPTED:" << mXmax <<" "<< mYmax <<" "<< mZmax <<endl;
171  minVolume=vert(nx)*vert(ny)*vert(nz);
172  break;//no need to grow any more along z
173  }
174  }
175  cout<<"->Finished Generating (pseudo) Asymmetric Unit, with:"<<endl
176  <<" 0 <= x <= "<< mXmax<<endl
177  <<" 0 <= y <= "<< mYmax<<endl
178  <<" 0 <= z <= "<< mZmax<<endl<<endl;
179  #else
180  const cctbx::sgtbx::brick b(spg.GetCCTbxSpg().type());
181  #ifdef __DEBUG__
182  cout<<"->>Parallelepipedic Asymmetric Unit, from cctbx::sgtbx::brick:"<<endl
183  <<b.as_string()<<endl;
184  #endif
185  mXmin=boost::rational_cast<REAL,int>(b(0,0).value());
186  mYmin=boost::rational_cast<REAL,int>(b(1,0).value());
187  mZmin=boost::rational_cast<REAL,int>(b(2,0).value());
188  mXmax=boost::rational_cast<REAL,int>(b(0,1).value());
189  mYmax=boost::rational_cast<REAL,int>(b(1,1).value());
190  mZmax=boost::rational_cast<REAL,int>(b(2,1).value());
191 
192  #endif
193 }
194 
195 bool AsymmetricUnit::IsInAsymmetricUnit(const REAL x, const REAL y, const REAL z)const
196 {
197  return ( ( x <= mXmin) && ( x >= mXmax)
198  &&( y <= mYmin) && ( y >= mYmax)
199  &&( z <= mZmin) && ( z >= mZmax));
200 }
201 REAL AsymmetricUnit::Xmin() const {return mXmin;}
202 REAL AsymmetricUnit::Xmax() const {return mXmax;}
203 REAL AsymmetricUnit::Ymin() const {return mYmin;}
204 REAL AsymmetricUnit::Ymax() const {return mYmax;}
205 REAL AsymmetricUnit::Zmin() const {return mZmin;}
206 REAL AsymmetricUnit::Zmax() const {return mZmax;}
207 
209 //
210 // SpaceGroup
211 //
213 
214 SpaceGroup::SpaceGroup():mId("P1"),mpCCTbxSpaceGroup(0)
215 {
217 }
218 
219 SpaceGroup::SpaceGroup(const string &spgId):mId(spgId),mpCCTbxSpaceGroup(0)
220 {
221  InitSpaceGroup(spgId);
222 }
223 
225 {
226  if(mpCCTbxSpaceGroup!=0) delete mpCCTbxSpaceGroup;
227 }
228 
229 void SpaceGroup::ChangeSpaceGroup(const string &spgId)
230 {
231  VFN_DEBUG_MESSAGE("SpaceGroup::ChangeSpaceGroup():"<<spgId,5)
232  this->InitSpaceGroup(spgId);
233 }
234 
235 const string& SpaceGroup::GetName()const{return mId;}
236 
237 bool SpaceGroup::IsInAsymmetricUnit(const REAL x, const REAL y, const REAL z) const
238 {
239  return mAsymmetricUnit.IsInAsymmetricUnit(x,y,z);
240 }
241 
242 void SpaceGroup::ChangeToAsymmetricUnit(REAL x, REAL y, REAL z) const
243 {
244  //:TODO:
245 }
246 
248 
249 
252 {
253  return mSpgNumber;
254 }
255 
257 {
258  return mHasInversionCenter;
259 }
260 
262 {
263  return mNbTrans;
264 }
265 
266 const std::vector<SpaceGroup::TRx>& SpaceGroup::GetTranslationVectors()const
267 {
268  return mvTrans;
269 }
270 
271 const std::vector<SpaceGroup::SMx>& SpaceGroup::GetSymmetryOperations()const
272 {
273  return mvSym;
274 }
275 
276 CrystMatrix_REAL SpaceGroup::GetAllSymmetrics(const REAL x, const REAL y, const REAL z,
277  const bool noCenter,const bool noTransl,
278  const bool noIdentical)const
279 {
280  //TAU_PROFILE("SpaceGroup::GetAllSymmetrics()","Matrix (x,y,z)",TAU_DEFAULT);
281  VFN_DEBUG_MESSAGE("SpaceGroup::GetAllSymmetrics()",0)
282  int nbMatrix, nbTrans,coeffInvert,i,j,k;
283  nbMatrix=this->GetCCTbxSpg().n_smx();
284  nbTrans=this->GetNbTranslationVectors();
285  if(this->IsCentrosymmetric()) coeffInvert=2 ; else coeffInvert=1;
286 
287  if(noCenter==true) coeffInvert=1; //skip center of symmetry
288  if(noTransl==true) nbTrans=1; //skip translation operations
289  CrystMatrix_REAL coords(nbMatrix*nbTrans*coeffInvert,3);
290 
291  k=0;
292  for(i=0;i<nbTrans;i++)
293  {
294  const REAL ltr_den=1/(REAL)(this->GetCCTbxSpg().ltr(i).den());
295  const REAL tx=this->GetCCTbxSpg().ltr(i)[0]*ltr_den;
296  const REAL ty=this->GetCCTbxSpg().ltr(i)[1]*ltr_den;
297  const REAL tz=this->GetCCTbxSpg().ltr(i)[2]*ltr_den;
298  //if(noTransl==false) cout << nbTrans <<endl;
299  //if(noTransl==false) cout << tx <<" "<< ty<<" "<< tz<<" "<<endl;
300  for(j=0;j<nbMatrix;j++)
301  {
302  const cctbx::sgtbx::rt_mx *pMatrix=&(this->GetCCTbxSpg().smx(j));
303  const cctbx::sgtbx::rot_mx *pRot=&(pMatrix->r());
304  const cctbx::sgtbx::tr_vec *pTrans=&(pMatrix->t());
305  const REAL r_den=1/(REAL)(pMatrix->r().den());
306  const REAL t_den=1/(REAL)(pMatrix->t().den());
307  coords(k,0)= ((*pRot)[0]*x+(*pRot)[1]*y+(*pRot)[2]*z)*r_den+(*pTrans)[0]*t_den+tx;
308  coords(k,1)= ((*pRot)[3]*x+(*pRot)[4]*y+(*pRot)[5]*z)*r_den+(*pTrans)[1]*t_den+ty;
309  coords(k,2)= ((*pRot)[6]*x+(*pRot)[7]*y+(*pRot)[8]*z)*r_den+(*pTrans)[2]*t_den+tz;
310  k++;
311  }
312  }
313  if(coeffInvert==2) //inversion center not in ListSeitzMx, but to be applied
314  {
315  int shift=nbMatrix*nbTrans;
316  const REAL dx=((REAL)this->GetCCTbxSpg().inv_t()[0])/(REAL)this->GetCCTbxSpg().inv_t().den();//inversion not at the origin
317  const REAL dy=((REAL)this->GetCCTbxSpg().inv_t()[1])/(REAL)this->GetCCTbxSpg().inv_t().den();
318  const REAL dz=((REAL)this->GetCCTbxSpg().inv_t()[2])/(REAL)this->GetCCTbxSpg().inv_t().den();
319  for(i=0;i<shift;i++)
320  {
321  coords(i+shift,0)=dx-coords(i,0);
322  coords(i+shift,1)=dy-coords(i,1);
323  coords(i+shift,2)=dz-coords(i,2);
324  }
325  }
326  //for(i=0;i<nbTrans*nbMatrix*coeffInvert;i++)
327  //cout <<FormatFloat(coords(0,i))<<FormatFloat(coords(1,i))<<FormatFloat(coords(2,i))<<endl;
328  //if(noTransl==false) cout <<coords<<endl;
329 
330  if(true==noIdentical)
331  {
332  VFN_DEBUG_MESSAGE("SpaceGroup::GetAllSymmetrics():Removing identical atoms",5)
333  //Bring back all coordinates to [0;1[
334  REAL *p=coords.data();
335  double junk;
336  for(long i=0;i<coords.numElements();i++)
337  {
338  *p = modf(*p,&junk);
339  if(*p<0) *p += 1.;
340  p++;
341  }
342  CrystMatrix_REAL newCoords;
343  newCoords=coords;
344  const REAL eps=1e-5;
345  long nbKeep=0;
346  for(long i=0;i<coords.rows();i++)
347  {
348  bool keep=true;
349  for(long j=0;j<i;j++)
350  {
351  if( ( fabs(coords(i,0)-coords(j,0)) < eps )
352  &&( fabs(coords(i,1)-coords(j,1)) < eps )
353  &&( fabs(coords(i,2)-coords(j,2)) < eps )) keep=false;
354  }
355  if(true==keep)
356  {
357  newCoords(nbKeep ,0) = coords(i,0);
358  newCoords(nbKeep ,1) = coords(i,1);
359  newCoords(nbKeep++,2) = coords(i,2);
360  }
361  }
362  newCoords.resizeAndPreserve(nbKeep,3);
363  return newCoords;
364  }
365  VFN_DEBUG_MESSAGE("SpaceGroup::GetAllSymmetrics():End",0)
366  return coords;
367 }
368 void SpaceGroup::GetSymmetric(unsigned int idx, REAL &x, REAL &y, REAL &z,
369  const bool noCenter,const bool noTransl,
370  const bool derivative) const
371 {
372  int coeffInvert;
373  const int nbMatrix=this->GetCCTbxSpg().n_smx();
374  int nbTrans=this->GetNbTranslationVectors(); POSSIBLY_UNUSED(nbTrans);
375  if(this->IsCentrosymmetric()) coeffInvert=2 ; else coeffInvert=1;
376 
377  if(noCenter==true) coeffInvert=1; //skip center of symmetry
378  if(noTransl==true) nbTrans=1; //skip translation operations
379 
380  const int i=idx/nbMatrix;//translation index
381  const int j=idx%nbMatrix;
382 
383  const REAL ltr_den=1/(REAL)(this->GetCCTbxSpg().ltr(i).den());
384  const REAL tx=this->GetCCTbxSpg().ltr(i)[0]*ltr_den;
385  const REAL ty=this->GetCCTbxSpg().ltr(i)[1]*ltr_den;
386  const REAL tz=this->GetCCTbxSpg().ltr(i)[2]*ltr_den;
387  const cctbx::sgtbx::rt_mx *pMatrix=&(this->GetCCTbxSpg().smx(j));
388  const cctbx::sgtbx::rot_mx *pRot=&(pMatrix->r());
389  const cctbx::sgtbx::tr_vec *pTrans=&(pMatrix->t());
390  const REAL r_den=1/(REAL)(pMatrix->r().den());
391  const REAL t_den=1/(REAL)(pMatrix->t().den());
392  const REAL x1= ((*pRot)[0]*x+(*pRot)[1]*y+(*pRot)[2]*z)*r_den;
393  const REAL y1= ((*pRot)[3]*x+(*pRot)[4]*y+(*pRot)[5]*z)*r_den;
394  const REAL z1= ((*pRot)[6]*x+(*pRot)[7]*y+(*pRot)[8]*z)*r_den;
395  if(derivative==false)
396  {
397  x=x1+(*pTrans)[0]*t_den+tx;
398  y=y1+(*pTrans)[1]*t_den+ty;
399  z=z1+(*pTrans)[2]*t_den+tz;
400  }
401  else
402  {
403  x=x1;
404  y=y1;
405  z=z1;
406  }
407  if(coeffInvert==2) //inversion center not in ListSeitzMx, but to be applied
408  {
409  const REAL dx=((REAL)this->GetCCTbxSpg().inv_t()[0])/(REAL)this->GetCCTbxSpg().inv_t().den();//inversion not at the origin
410  const REAL dy=((REAL)this->GetCCTbxSpg().inv_t()[1])/(REAL)this->GetCCTbxSpg().inv_t().den();
411  const REAL dz=((REAL)this->GetCCTbxSpg().inv_t()[2])/(REAL)this->GetCCTbxSpg().inv_t().den();
412  x=dx-x;
413  y=dy-y;
414  z=dz-z;
415  }
416 }
417 
418 int SpaceGroup::GetNbSymmetrics(const bool noCenter,const bool noTransl)const
419 {
420  if(noCenter || (!mHasInversionCenter))
421  {
422  if(noTransl) return mNbSym;
423  else return mNbSym*mNbTrans;
424  }
425  else
426  {
427  if(noTransl) return 2*mNbSym;
428  else return 2*mNbSym*mNbTrans;
429  }
430  return 2*mNbSym*mNbTrans;
431 }
432 
433 void SpaceGroup::Print() const
434 {
435  cout << "SpaceGroup:" <<endl;
436  cout << " Schoenflies symbol = " << this->GetCCTbxSpg().match_tabulated_settings().schoenflies() << endl ;
437  cout << " Hermann-Maugin symbol = " << this->GetCCTbxSpg().match_tabulated_settings().hermann_mauguin() << endl ;
438  cout << " Hall symbol = " << this->GetCCTbxSpg().match_tabulated_settings().hall() << endl ;
439  cout << " SgNumber = " << this->GetCCTbxSpg().match_tabulated_settings().number() << endl ;
440  cout << " Number of Seitz Matrix = " << this->GetCCTbxSpg().n_smx() << endl ;
441  cout << " Number of Translation Vectors = " << this->GetCCTbxSpg().n_ltr() << endl ;
442  cout << " List of Seitz Matrices : " << endl ;
443  for(unsigned int i=0;i<this->GetCCTbxSpg().n_smx();i++)
444  cout << " " << this->GetCCTbxSpg().smx(i).as_xyz() <<endl;
445  if(true==mHasInversionCenter)
446  {
447  cout << " There is an inversion center at "
448  << (this->GetCCTbxSpg().inv_t()[0])/(REAL)this->GetCCTbxSpg().inv_t().den()/2. << " "
449  << (this->GetCCTbxSpg().inv_t()[1])/(REAL)this->GetCCTbxSpg().inv_t().den()/2. << " "
450  << (this->GetCCTbxSpg().inv_t()[2])/(REAL)this->GetCCTbxSpg().inv_t().den()/2. << endl;
451  }
452  if(this->GetCCTbxSpg().n_ltr()>0)
453  {
454  cout <<" List of Translation vectors :"<<endl;
455  for(unsigned int i=0;i<this->GetCCTbxSpg().n_ltr();i++)
456  cout << " "<< this->GetCCTbxSpg().ltr(i)[0]/(REAL)this->GetCCTbxSpg().ltr(i).den()<<","
457  << this->GetCCTbxSpg().ltr(i)[1]/(REAL)this->GetCCTbxSpg().ltr(i).den()<<","
458  << this->GetCCTbxSpg().ltr(i)[2]/(REAL)this->GetCCTbxSpg().ltr(i).den()<<endl;
459  }
460  cout<<"Extension (origin choice, rhomboedral/hexagonal):"<<mExtension<<endl;
461 }
464 const cctbx::sgtbx::space_group& SpaceGroup::GetCCTbxSpg()const{return *mpCCTbxSpaceGroup;}
465 
467 
468 unsigned int SpaceGroup::GetUniqueAxis()const{return mUniqueAxisId;}
469 
471 
472 CrystVector_REAL SpaceGroup::GetInversionCenter()const {
473  CrystVector_REAL center(3);
474  center(0) = this->GetCCTbxSpg().inv_t()[0];
475  center(1) = this->GetCCTbxSpg().inv_t()[1];
476  center(2) = this->GetCCTbxSpg().inv_t()[2];
477  // inv_t is the overall translation associated with inversion,
478  // the actual inversion center is therefore at midpoint.
479  center /= 2 * this->GetCCTbxSpg().inv_t().den();
480  return center;
481 }
482 
483 unsigned int SpaceGroup::AreReflEquiv(const REAL h1, const REAL k1, const REAL l1,
484  const REAL h2, const REAL k2, const REAL l2)const
485 {
486  const int ih1=scitbx::math::iround(h1);
487  const int ik1=scitbx::math::iround(k1);
488  const int il1=scitbx::math::iround(l1);
489  cctbx::miller::index<long> h0(scitbx::vec3<long>(ih1,ik1,il1));
490  const int ih2=scitbx::math::iround(h2);
491  const int ik2=scitbx::math::iround(k2);
492  const int il2=scitbx::math::iround(l2);
493  cctbx::miller::index<long> k0(scitbx::vec3<long>(ih2,ik2,il2));
494  cctbx::miller::sym_equiv_indices sei(this->GetCCTbxSpg(),k0);
495  int equiv=0;
496  //cout<<h0.as_string()<<" - "<<k0.as_string()<<","<<sei.f_mates(false)<<","<<sei.f_mates(true)<<endl;
497  for(size_t i_indices=0;i_indices<sei.indices().size();i_indices++)
498  {
499  const size_t sfm = sei.f_mates(false);
500  for(size_t i_mate = 0; i_mate < sfm; i_mate++)
501  {
502  cctbx::miller::index<long> k = sei(i_mate, i_indices).h();
503  //cout<<" ->("<<i_indices<<","<<i_mate<<")"<<k.as_string()<<endl;
504  if(h0==k)
505  {
506  if(i_mate==0) equiv=1;
507  else equiv=2;
508  break;
509  }
510  }
511  }
512  VFN_DEBUG_MESSAGE("SpaceGroup::AreReflEquiv("<<ih1<<","<<ik1<<","<<il1<<"),("<<ih2<<","<<ik2<<","<<il2<<"):"<<equiv,2)
513  return equiv;
514 }
515 
516 CrystMatrix_REAL SpaceGroup::GetAllEquivRefl(const REAL h0, const REAL k0, const REAL l0,
517  const bool excludeFriedelMate,
518  const bool forceFriedelLaw,
519  const REAL sf_re,const REAL sf_im) const
520 {
521  VFN_DEBUG_ENTRY("SpaceGroup::GetAllEquivRefl():",5)
522  const int ih0=scitbx::math::iround(h0);
523  const int ik0=scitbx::math::iround(k0);
524  const int il0=scitbx::math::iround(l0);
525  cctbx::miller::index<long> h(scitbx::vec3<long>(ih0,ik0,il0));
526  cctbx::miller::sym_equiv_indices sei(this->GetCCTbxSpg(),h);
527  int nbEquiv;
528  if(forceFriedelLaw) nbEquiv=sei.multiplicity(false);
529  else nbEquiv=sei.multiplicity(true);
530  if( ((this->IsCentrosymmetric())||forceFriedelLaw) && excludeFriedelMate) nbEquiv/=2;
531  CrystMatrix_REAL equivReflList(nbEquiv,5);
532  complex<double> sf0((double)(sf_re),(double)(sf_im));
533  for(int i=0;i<nbEquiv;i+=1)
534  {
535  cctbx::miller::index<long> k = sei(i).h();
536  equivReflList(i,0)=(REAL)k[0];
537  equivReflList(i,1)=(REAL)k[1];
538  equivReflList(i,2)=(REAL)k[2];
539  equivReflList(i,3)=(REAL)sei(i).complex_eq(sf0).real();
540  equivReflList(i,4)=(REAL)sei(i).complex_eq(sf0).imag();
541  }
542  VFN_DEBUG_EXIT("SpaceGroup::GetAllEquivRefl():",5)
543  return equivReflList;
544 }
545 
546 bool SpaceGroup::IsReflSystematicAbsent(const REAL h0, const REAL k0, const REAL l0)const
547 {
548  const int ih0=scitbx::math::iround(h0);
549  const int ik0=scitbx::math::iround(k0);
550  const int il0=scitbx::math::iround(l0);
551  cctbx::miller::index<long> h(scitbx::vec3<long>(ih0,ik0,il0));
552  return this->GetCCTbxSpg().is_sys_absent(h);
553 }
554 
555 bool SpaceGroup::IsReflCentric(const REAL h0, const REAL k0, const REAL l0)const
556 {
557  const int ih0=scitbx::math::iround(h0);
558  const int ik0=scitbx::math::iround(k0);
559  const int il0=scitbx::math::iround(l0);
560  cctbx::miller::index<long> h(scitbx::vec3<long>(ih0,ik0,il0));
561  return this->GetCCTbxSpg().is_centric(h);
562 }
563 
564 unsigned int SpaceGroup::GetExpectedIntensityFactor(const REAL h0,
565  const REAL k0,
566  const REAL l0)const
567 {
568  const int ih0=scitbx::math::iround(h0);
569  const int ik0=scitbx::math::iround(k0);
570  const int il0=scitbx::math::iround(l0);
571  cctbx::miller::index<long> h(scitbx::vec3<long>(ih0,ik0,il0));
572  return this->GetCCTbxSpg().epsilon(h);
573 }
574 
575 void SpaceGroup::InitSpaceGroup(const string &spgId)
576 {
577  if((mId==spgId)&&(mpCCTbxSpaceGroup!=0)) return;
578  VFN_DEBUG_ENTRY("SpaceGroup::InitSpaceGroup():"<<spgId,8)
579  #ifdef __DEBUG__
580  (*fpObjCrystInformUser)("Initializing spacegroup: "+spgId);
581  #endif
582  try
583  {
584  // replace mpCCTbxSpaceGroup only after we get new space group
585  cctbx::sgtbx::space_group_symbols sgs=cctbx::sgtbx::space_group_symbols(spgId);
586  cctbx::sgtbx::space_group *nsg = new cctbx::sgtbx::space_group(sgs);
587  assert(nsg);
588  delete mpCCTbxSpaceGroup;
589  mpCCTbxSpaceGroup = nsg;
590  }
591  catch(exception ex1)
592  {
593  try
594  {
595  (*fpObjCrystInformUser)("Lookup of '" + spgId + "' symbol failed, trying as Hall symbol.");
596  // replace mpCCTbxSpaceGroup only after we get new space group
597  cctbx::sgtbx::space_group *nsg = new cctbx::sgtbx::space_group(spgId);
598  assert(nsg);
599  delete mpCCTbxSpaceGroup;
600  mpCCTbxSpaceGroup = nsg;
601  }
602  catch(exception ex2)
603  {
604  (*fpObjCrystInformUser)("Could not interpret Spacegroup Symbol:"+spgId);
605  string emsg = "Space group symbol '" + spgId + "' not recognized";
606  throw invalid_argument(emsg);
607  }
608  }
609 
610  try
611  {
612  //Inversion center
613  if(this->GetCCTbxSpg().f_inv() == 2)
614  {
615  mHasInversionCenter=true ;
616  if( (this->GetCCTbxSpg().inv_t()[0] !=0) ||
617  (this->GetCCTbxSpg().inv_t()[1] !=0) ||
618  (this->GetCCTbxSpg().inv_t()[2] !=0) ) mIsInversionCenterAtOrigin=false;
619  else mIsInversionCenterAtOrigin=true;
620  }
621  else
622  {
623  mHasInversionCenter=false ;
625  }
626 
627  //initialize asymmetric unit
629 
630  mUniqueAxisId=0;
631  if( (this->GetCCTbxSpg().type().number() >2)
632  &&(this->GetCCTbxSpg().type().number() <16))
633  {
634  string ch=this->GetCCTbxSpg().match_tabulated_settings().hall();
635  if(ch.find("x")!=std::string::npos) {mUniqueAxisId=0;}
636  else
637  if(ch.find("y")!=std::string::npos) {mUniqueAxisId=1;}
638  else mUniqueAxisId=2;
639  }
640 
641  mNbSym =this->GetCCTbxSpg().n_smx();
642  mNbTrans =this->GetCCTbxSpg().n_ltr();
643  mSpgNumber=this->GetCCTbxSpg().type().number();
644 
645  mExtension='\0'; //this->GetCCTbxSpg().type().extension();
646  }
647  catch(exception ex)
648  {
649  (*fpObjCrystInformUser)("Error initializing spacegroup (Incorrect Hall symbol ?):"+spgId);
650  if (mId != spgId)
651  {
652  (*fpObjCrystInformUser)("Reverting to spacegroup symbol:"+mId);
653  this->InitSpaceGroup(mId);
654  }
655  VFN_DEBUG_EXIT("SpaceGroup::InitSpaceGroup() could not interpret spacegroup:"<<spgId<<":"<<ex.what(),8)
656  string emsg = "Space group symbol '" + spgId + "' not recognized";
657  throw invalid_argument(emsg);
658  }
659 
660  mExtension=this->GetCCTbxSpg().match_tabulated_settings().extension();
661 
662  // Force using the H-M symbol
663  if(mExtension=='\0') mId=this->GetCCTbxSpg().match_tabulated_settings().hermann_mauguin();
664  else mId=this->GetCCTbxSpg().match_tabulated_settings().hermann_mauguin()+":"+mExtension;
665 
666  // Store rotation matrices & translation vectors
667  mvTrans.resize(mNbTrans);
668  for(unsigned int i=0;i<mNbTrans;i++)
669  {
670  for(unsigned int j=0;j<3;j++)
671  mvTrans[i].tr[j] = this->GetCCTbxSpg().ltr(i)[j]/(REAL)(this->GetCCTbxSpg().ltr(i).den());
672  }
673  mvSym.resize(mNbSym);
674  for(unsigned int j=0;j<mNbSym;j++)
675  {
676  const cctbx::sgtbx::rt_mx *pMatrix=&(this->GetCCTbxSpg().smx(j));
677  const cctbx::sgtbx::rot_mx *pRot=&(pMatrix->r());
678  const cctbx::sgtbx::tr_vec *pTrans=&(pMatrix->t());
679  const REAL r_den=1/(REAL)(pMatrix->r().den());
680  const REAL t_den=1/(REAL)(pMatrix->t().den());
681  for(unsigned int i=0;i<9;++i) mvSym[j].mx[i]=(*pRot)[i]*r_den;
682  for(unsigned int i=0;i<3;++i) mvSym[j].tr[i]=(*pTrans)[i]*t_den;
683  }
684  #ifdef __DEBUG__
685  this->Print();
686  #endif
687  mClock.Click();
688  string extension("");
689  if(mExtension=='1') extension=" (Using origin choice #1)";
690  if(mExtension=='2') extension=" (Using origin choice #2)";
691  if(mExtension=='R') extension=" (Using Rhombohedral cell)";
692  if(mExtension=='H') extension=" (Using Hexagonal cell)";
693  #ifdef __DEBUG__
694  (*fpObjCrystInformUser)("Initialized spacegroup, HM: "+spgId+extension+" , Hall:"+this->GetCCTbxSpg().type().hall_symbol());
695  #endif
696  VFN_DEBUG_EXIT("SpaceGroup::InitSpaceGroup():"<<spgId,8)
697 }
698 
699 }//namespace
The namespace which includes all objects (crystallographic and algorithmic) in ObjCryst++.
Definition: doc-main.h:25
This class only serves to temporarilly set the LC_NUMERIC C locale to "C", in order to use '.
Definition: General.h:192
The basic description of spacegroup asymmetric unit.
Definition: SpaceGroup.h:55
void SetSpaceGroup(const SpaceGroup &spg)
Assign a SpaceGroup and generate the corrsponding Xmax, Ymax, ZMax.
Definition: SpaceGroup.cpp:89
AsymmetricUnit()
Default Constructor.
Definition: SpaceGroup.cpp:67
bool IsInAsymmetricUnit(const REAL x, const REAL y, const REAL z) const
Test if (x,y,z) is in the asymmetric unit.
Definition: SpaceGroup.cpp:195
The crystallographic space group, and the cell choice.
Definition: SpaceGroup.h:105
void ChangeToAsymmetricUnit(REAL x, REAL y, REAL z) const
Move (x,y,z) coordinates to their equivalent in the asym unit.
Definition: SpaceGroup.cpp:242
char GetExtension() const
Extension to space group symbol ('1','2':origin choice ; 'R','H'=rhomboedral/hexagonal)
Definition: SpaceGroup.cpp:470
bool mHasInversionCenter
Is spacegroup centrosymmetric ?
Definition: SpaceGroup.h:318
bool IsReflCentric(const REAL h, const REAL k, const REAL l) const
Is the reflection centric ?
Definition: SpaceGroup.cpp:555
unsigned long mSpgNumber
SpaceGroup Number.
Definition: SpaceGroup.h:336
std::vector< SMx > mvSym
Store floating-point matrices for faster use.
Definition: SpaceGroup.h:340
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
void Print() const
Prints a description of the spacegroup (symbol, properties).
Definition: SpaceGroup.cpp:433
const string & GetName() const
Get the name of this spacegroup (its name, as supplied initially by the calling program or user)
Definition: SpaceGroup.cpp:235
void InitSpaceGroup(const string &spgId)
Init the spaceGroup object from its name.
Definition: SpaceGroup.cpp:575
bool IsInversionCenterAtOrigin() const
Is the center of symmetry at the origin ?
Definition: SpaceGroup.cpp:463
string mId
Spacegroup's name ( 'I422', 'D2^8','230') Maybe we should only store the Hermann-Mauguin symbol,...
Definition: SpaceGroup.h:305
SpaceGroup()
Default Constructor (initializes in P1)
Definition: SpaceGroup.cpp:214
unsigned int GetUniqueAxis() const
Which is the unique axis (for monoclinic space groups )
Definition: SpaceGroup.cpp:468
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
unsigned long mNbTrans
Number of lattice translations, including (0,0,0).
Definition: SpaceGroup.h:334
bool mIsInversionCenterAtOrigin
Is center of symmetry at the origin ?
Definition: SpaceGroup.h:322
bool IsReflSystematicAbsent(const REAL h, const REAL k, const REAL l) const
Is the reflection systematically absent ?
Definition: SpaceGroup.cpp:546
cctbx::sgtbx::space_group * mpCCTbxSpaceGroup
SgOps structure for this spacegroup.
Definition: SpaceGroup.h:313
int GetSpaceGroupNumber() const
Id number of the spacegroup.
Definition: SpaceGroup.cpp:251
unsigned int AreReflEquiv(const REAL h1, const REAL k1, const REAL l1, const REAL h2, const REAL k2, const REAL l2) const
Are these reflections equivalent ?
Definition: SpaceGroup.cpp:483
~SpaceGroup()
Destructor.
Definition: SpaceGroup.cpp:224
CrystVector_REAL GetInversionCenter() const
Get the inversion center.
Definition: SpaceGroup.cpp:472
int GetNbTranslationVectors() const
Number of translation vectors (1 for 'P' cells, 2 for 'I', 4 for 'F',etc..)
Definition: SpaceGroup.cpp:261
bool IsCentrosymmetric() const
Is the crystal centrosymmetric ?
Definition: SpaceGroup.cpp:256
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
std::vector< TRx > mvTrans
Store floating-point translation vectors for faster use.
Definition: SpaceGroup.h:342
const RefinableObjClock & GetClockSpaceGroup() const
Get the SpaceGroup Clock (corresponding to the time of the initialization of the SpaceGroup)
Definition: SpaceGroup.cpp:466
bool IsInAsymmetricUnit(const REAL x, const REAL y, const REAL z) const
Test if a given scatterer at (x,y,z) is in the asymmetric unit.
Definition: SpaceGroup.cpp:237
RefinableObjClock mClock
The Spacegroup clock.
Definition: SpaceGroup.h:328
unsigned int mUniqueAxisId
Unique axis number (0=a,1=b,2=c)
Definition: SpaceGroup.h:330
const AsymmetricUnit & GetAsymUnit() const
Get the AsymmetricUnit for this spacegroup.
Definition: SpaceGroup.cpp:247
const std::vector< SpaceGroup::SMx > & GetSymmetryOperations() const
Get all symmetry operations stored in vector of struct SMx.
Definition: SpaceGroup.cpp:271
unsigned long mNbSym
Number of symmetry operations (excluding center, and translations).
Definition: SpaceGroup.h:332
CrystMatrix_REAL GetAllEquivRefl(const REAL h, const REAL k, const REAL l, const bool excludeFriedelMate=false, const bool forceFriedelLaw=false, const REAL sf_re=0, const REAL sf_im=0) const
Get the list of all equivalent reflections.
Definition: SpaceGroup.cpp:516
const std::vector< SpaceGroup::TRx > & GetTranslationVectors() const
Return all Translation Vectors, as a 3 columns-array.
Definition: SpaceGroup.cpp:266
void ChangeSpaceGroup(const string &spgId)
Change the Spacegroup.
Definition: SpaceGroup.cpp:229
const cctbx::sgtbx::space_group & GetCCTbxSpg() const
Get the underlying cctbx Spacegroup object.
Definition: SpaceGroup.cpp:464
AsymmetricUnit mAsymmetricUnit
The spacegroup asymmetric unit.
Definition: SpaceGroup.h:325
char mExtension
Extension to space group symbol (1,2:origin choice ; R,H=rhomboedral/hexagonal)
Definition: SpaceGroup.h:338
We need to record exactly when refinable objects have been modified for the last time (to avoid re-co...
Definition: RefinableObj.h:140
void Click()
Record an event for this clock (generally, the 'time' an object has been modified,...