FOX/ObjCryst++  2022
CIF.cpp
1 #include <ctype.h>
2 #include <cmath>
3 #include <boost/format.hpp>
4 
5 #include "cctbx/sgtbx/space_group.h"
6 #include "cctbx/sgtbx/space_group_type.h"
7 #include "cctbx/miller/sym_equiv.h"
8 #include "cctbx/sgtbx/brick.h"
9 
10 #include "ObjCryst/ObjCryst/CIF.h"
11 #include "ObjCryst/ObjCryst/Crystal.h"
12 #include "ObjCryst/ObjCryst/Atom.h"
13 #include "ObjCryst/ObjCryst/PowderPattern.h"
14 #include "ObjCryst/Quirks/Chronometer.h"
15 
16 #define POSSIBLY_UNUSED(expr) (void)(expr)
17 
18 using namespace std;
19 
20 namespace ObjCryst
21 {
22 CIFData::CIFAtom::CIFAtom():
23 mLabel(""),mSymbol(""),mOccupancy(1.0),mBiso(0.0)
24 {}
25 
26 CIFData::CIFData()
27 {}
28 
29 void CIFData::ExtractAll(const bool verbose)
30 {
31  (*fpObjCrystInformUser)("CIF: Extract Data...");
32  // :TODO: convert cartesian to fractional coordinates and vice-versa, if unit cell is known
33  // :TODO: Take care of values listed as "." and "?" instead of a real value.
34  this->ExtractName(verbose);
35  this->ExtractUnitCell(verbose);
36  this->ExtractSpacegroup(verbose);
37  this->ExtractAtomicPositions(verbose);
38  this->ExtractAnisotropicADPs(verbose);
39  this->ExtractPowderPattern(verbose);
40  this->ExtractSingleCrystalData(verbose);
41  (*fpObjCrystInformUser)("CIF: Finished Extracting Data...");
42 }
43 
44 void CIFData::ExtractUnitCell(const bool verbose)
45 {
46  map<ci_string,string>::const_iterator positem;
47  positem=mvItem.find("_cell_length_a");
48  if(positem!=mvItem.end())
49  {
50  (*fpObjCrystInformUser)("CIF: Extract Unit Cell...");
51  mvLatticePar.resize(6);
52  mvLatticePar[0]=CIFNumeric2REAL(positem->second);
53  positem=mvItem.find("_cell_length_b");
54  if(positem!=mvItem.end())
55  mvLatticePar[1]=CIFNumeric2REAL(positem->second);
56  positem=mvItem.find("_cell_length_c");
57  if(positem!=mvItem.end())
58  mvLatticePar[2]=CIFNumeric2REAL(positem->second);
59  positem=mvItem.find("_cell_angle_alpha");
60  if(positem!=mvItem.end())
61  mvLatticePar[3]=CIFNumeric2REAL(positem->second);
62  positem=mvItem.find("_cell_angle_beta");
63  if(positem!=mvItem.end())
64  mvLatticePar[4]=CIFNumeric2REAL(positem->second);
65  positem=mvItem.find("_cell_angle_gamma");
66  if(positem!=mvItem.end())
67  mvLatticePar[5]=CIFNumeric2REAL(positem->second);
68  if(verbose) cout<<"Found Lattice parameters:" <<mvLatticePar[0]<<" , "<<mvLatticePar[1]<<" , "<<mvLatticePar[2]
69  <<" , "<<mvLatticePar[3]<<" , "<<mvLatticePar[4]<<" , "<<mvLatticePar[5]<<endl;
70  mvLatticePar[3]*=0.017453292519943295;// pi/180
71  mvLatticePar[4]*=0.017453292519943295;
72  mvLatticePar[5]*=0.017453292519943295;
73  this->CalcMatrices();
74  }
75 }
76 
77 void CIFData::ExtractSpacegroup(const bool verbose)
78 {
79  map<ci_string,string>::const_iterator positem;
80  positem=mvItem.find("_space_group_IT_number");
81  if(positem!=mvItem.end())
82  {
83  mSpacegroupNumberIT=positem->second;//CIFNumeric2Int()
84  if(verbose) cout<<"Found spacegroup IT number:"<<mSpacegroupNumberIT<<endl;
85  }
86  else
87  {
88  positem=mvItem.find("_symmetry_Int_Tables_number");
89  if(positem!=mvItem.end())
90  {
91  mSpacegroupNumberIT=positem->second;//CIFNumeric2Int()
92  if(verbose) cout<<"Found spacegroup IT number (with OBSOLETE CIF #1.0 TAG):"<<mSpacegroupNumberIT<<endl;
93  }
94  }
95 
96  positem=mvItem.find("_space_group_name_Hall");
97  if(positem!=mvItem.end())
98  {
99  mSpacegroupSymbolHall=positem->second;
100  if(verbose) cout<<"Found spacegroup Hall symbol:"<<mSpacegroupSymbolHall<<endl;
101  }
102  else
103  {
104  positem=mvItem.find("_symmetry_space_group_name_Hall");
105  if(positem!=mvItem.end())
106  {
107  mSpacegroupSymbolHall=positem->second;
108  if(verbose) cout<<"Found spacegroup Hall symbol (with OBSOLETE CIF #1.0 TAG):"<<mSpacegroupSymbolHall<<endl;
109  }
110  }
111 
112  positem=mvItem.find("_space_group_name_H-M_alt");
113  if(positem!=mvItem.end())
114  {
115  mSpacegroupHermannMauguin=positem->second;
116  if(verbose) cout<<"Found spacegroup Hermann-Mauguin symbol:"<<mSpacegroupHermannMauguin<<endl;
117  }
118  else
119  {
120  positem=mvItem.find("_symmetry_space_group_name_H-M");
121  if(positem!=mvItem.end())
122  {
123  mSpacegroupHermannMauguin=positem->second;
124  if(verbose) cout<<"Found spacegroup Hall Hermann-Mauguin (with OBSOLETE CIF #1.0 TAG):"<<mSpacegroupHermannMauguin<<endl;
125  }
126  }
127  // Try to extract symmetry_as_xyz
128  for(map<set<ci_string>,map<ci_string,vector<string> > >::const_iterator loop=mvLoop.begin();
129  loop!=mvLoop.end();++loop)
130  {
131  if(mvSymmetry_equiv_pos_as_xyz.size()>0) break;// only extract ONE list of symmetry strings
132  map<ci_string,vector<string> >::const_iterator pos;
133  pos=loop->second.find("_symmetry_equiv_pos_as_xyz");
134  if(pos!=loop->second.end())
135  {
136  if(verbose) cout<<"Found list of _symmetry_equiv_pos_as_xyz:"<<endl;
137  for(unsigned int i=0;i<pos->second.size();++i)
138  {
139  if(verbose) cout<<" "<<pos->second[i]<<endl;
140  mvSymmetry_equiv_pos_as_xyz.insert(pos->second[i]);
141  }
142  }
143  }
144 }
145 
146 void CIFData::ExtractName(const bool verbose)
147 {
148  map<ci_string,string>::const_iterator positem;
149  positem=mvItem.find("_chemical_name_systematic");
150  if(positem!=mvItem.end())
151  {
152  mName=positem->second;
153  if(verbose) cout<<"Found chemical name:"<<mName<<endl;
154  }
155  else
156  {
157  positem=mvItem.find("_chemical_name_mineral");
158  if(positem!=mvItem.end())
159  {
160  mName=positem->second;
161  if(verbose) cout<<"Found chemical name:"<<mName<<endl;
162  }
163  else
164  {
165  positem=mvItem.find("_chemical_name_structure_type");
166  if(positem!=mvItem.end())
167  {
168  mName=positem->second;
169  if(verbose) cout<<"Found chemical name:"<<mName<<endl;
170  }
171  else
172  {
173  positem=mvItem.find("_chemical_name_common");
174  if(positem!=mvItem.end())
175  {
176  mName=positem->second;
177  if(verbose) cout<<"Found chemical name:"<<mName<<endl;
178  }
179  else
180  {
181  positem=mvItem.find("_chemical_formula_moiety");
182  if(positem!=mvItem.end())
183  {
184  mName=positem->second;
185  if(verbose) cout<<"Found chemical name:"<<mName<<endl;
186  }
187  else
188  {
189  positem=mvItem.find("_chemical_formula_sum");
190  if(positem!=mvItem.end())
191  {
192  mName=positem->second;
193  if(verbose) cout<<"Found chemical name:"<<mName<<endl;
194  }
195  }
196  }
197  }
198  }
199  }
201  positem=mvItem.find("_chemical_formula_analytical");
202  if(positem!=mvItem.end())
203  {
204  mFormula=positem->second;
205  if(verbose) cout<<"Found chemical formula:"<<mFormula<<endl;
206  }
207  else
208  {
209  positem=mvItem.find("_chemical_formula_structural");
210  if(positem!=mvItem.end())
211  {
212  mFormula=positem->second;
213  if(verbose) cout<<"Found chemical formula:"<<mFormula<<endl;
214  }
215  else
216  {
217  positem=mvItem.find("_chemical_formula_iupac");
218  if(positem!=mvItem.end())
219  {
220  mFormula=positem->second;
221  if(verbose) cout<<"Found chemical formula:"<<mFormula<<endl;
222  }
223  else
224  {
225  positem=mvItem.find("_chemical_formula_moiety");
226  if(positem!=mvItem.end())
227  {
228  mFormula=positem->second;
229  if(verbose) cout<<"Found chemical formula:"<<mFormula<<endl;
230  }
231  }
232  }
233  }
234 }
235 
236 void CIFData::ExtractAtomicPositions(const bool verbose)
237 {
238  map<ci_string,string>::const_iterator positem;
239  for(map<set<ci_string>,map<ci_string,vector<string> > >::const_iterator loop=mvLoop.begin();
240  loop!=mvLoop.end();++loop)
241  {
242  if(mvAtom.size()>0) break;// only extract ONE list of atoms, preferably fractional coordinates
243  map<ci_string,vector<string> >::const_iterator posx,posy,posz,poslabel,possymbol,posoccup,posadp;
244  posx=loop->second.find("_atom_site_fract_x");
245  posy=loop->second.find("_atom_site_fract_y");
246  posz=loop->second.find("_atom_site_fract_z");
247  unsigned int nb = 0;
248  if( (posx!=loop->second.end()) && (posy!=loop->second.end()) && (posz!=loop->second.end()))
249  {
250  nb=posx->second.size();
251  mvAtom.resize(nb);
252  for(unsigned int i=0;i<nb;++i)
253  {
254  mvAtom[i].mCoordFrac.resize(3);
255  mvAtom[i].mCoordFrac[0]=CIFNumeric2REAL(posx->second[i]);
256  mvAtom[i].mCoordFrac[1]=CIFNumeric2REAL(posy->second[i]);
257  mvAtom[i].mCoordFrac[2]=CIFNumeric2REAL(posz->second[i]);
258  }
259  this->Fractional2CartesianCoord();
260  }
261  else
262  {
263  posx=loop->second.find("_atom_site_Cartn_x");
264  posy=loop->second.find("_atom_site_Cartn_y");
265  posz=loop->second.find("_atom_site_Cartn_z");
266  if( (posx!=loop->second.end()) && (posy!=loop->second.end()) && (posz!=loop->second.end()))
267  {
268  nb=posx->second.size();
269  mvAtom.resize(nb);
270  for(unsigned int i=0;i<nb;++i)
271  {
272  mvAtom[i].mCoordCart.resize(3);
273  mvAtom[i].mCoordCart[0]=CIFNumeric2REAL(posx->second[i]);
274  mvAtom[i].mCoordCart[1]=CIFNumeric2REAL(posy->second[i]);
275  mvAtom[i].mCoordCart[2]=CIFNumeric2REAL(posz->second[i]);
276  }
277  this->Cartesian2FractionalCoord();
278  }
279  }
280  if(mvAtom.size()>0)
281  {// Got the atoms, get names, symbols and adps
282  (*fpObjCrystInformUser)("CIF: Extract Atoms...");
283  possymbol=loop->second.find("_atom_site_type_symbol");
284  if(possymbol!=loop->second.end())
285  for(unsigned int i=0;i<nb;++i)
286  mvAtom[i].mSymbol=possymbol->second[i];
287  poslabel=loop->second.find("_atom_site_label");
288  if(poslabel!=loop->second.end())
289  for(unsigned int i=0;i<nb;++i)
290  {
291  mvAtom[i].mLabel=poslabel->second[i];
292  if(possymbol==loop->second.end())
293  {// There was no symbol, use the labels to guess it
294  int nbc=0;
295  if(mvAtom[i].mLabel.size()==1)
296  if(isalpha(mvAtom[i].mLabel[0])) nbc=1;
297  if(mvAtom[i].mLabel.size()>=2)
298  {
299  if(isalpha(mvAtom[i].mLabel[0]) && isalpha(mvAtom[i].mLabel[1])) nbc=2;
300  else if(isalpha(mvAtom[i].mLabel[0])) nbc=1;
301  }
302  if(nbc>0) mvAtom[i].mSymbol=mvAtom[i].mLabel.substr(0,nbc);
303  else mvAtom[i].mSymbol="H";//Something wen wrong, no symbol !
304  }
305  }
306  // Occupancy ?
307  posoccup=loop->second.find("_atom_site_occupancy");
308  if(posoccup!=loop->second.end())
309  for(unsigned int i=0;i<nb;++i)
310  mvAtom[i].mOccupancy=CIFNumeric2REAL(posoccup->second[i]);
311  // ADPs - Record ani, ovl or mpl as iso.
312  REAL mult = 1.0;
313  posadp=loop->second.find("_atom_site_B_iso_or_equiv");
314  if(posadp==loop->second.end())
315  {
316  mult = 8 * M_PI * M_PI;
317  posadp=loop->second.find("_atom_site_U_iso_or_equiv");
318  }
319  if(posadp!=loop->second.end())
320  for(unsigned int i=0;i<nb;++i)
321  mvAtom[i].mBiso = mult*CIFNumeric2REAL(posadp->second[i]);
322  // Now be somewhat verbose
323  if(verbose)
324  {
325  cout << "Found "<<nb<<" atoms. Waouh !"<<endl;
326  for(unsigned int i=0;i<nb;++i)
327  {
328  cout<<mvAtom[i].mLabel<<" "<<mvAtom[i].mSymbol;
329  if(mvAtom[i].mCoordFrac.size()>0)
330  {
331  cout<<" , Fractional: ";
332  for(unsigned int j=0;j<mvAtom[i].mCoordFrac.size();++j)
333  cout<<mvAtom[i].mCoordFrac[j]<<" ";
334  }
335  if(mvAtom[i].mCoordCart.size()>0)
336  {
337  cout<<" , Cartesian: ";
338  for(unsigned int j=0;j<mvAtom[i].mCoordCart.size();++j)
339  cout<<mvAtom[i].mCoordCart[j]<<" ";
340  }
341  cout<<" , Occupancy= "<<mvAtom[i].mOccupancy<<endl;
342  cout<<" , Biso= "<<mvAtom[i].mBiso<<endl;
343  }
344  }
345  }
346  }
347 }
348 
349 void CIFData::ExtractAnisotropicADPs(const bool verbose)
350 {
351 
352  typedef map<set<ci_string>,map<ci_string,vector<string> > >::const_iterator LoopIter;
353  typedef map<ci_string,vector<string> >::const_iterator EntryIter;
354 
355  const REAL utob = 8 * M_PI * M_PI;
356 
357  const char* uijlabels[] = {
358  "_atom_site_aniso_U_11",
359  "_atom_site_aniso_U_22",
360  "_atom_site_aniso_U_33",
361  "_atom_site_aniso_U_12",
362  "_atom_site_aniso_U_13",
363  "_atom_site_aniso_U_23",
364  };
365 
366  const char* bijlabels[] = {
367  "_atom_site_aniso_B_11",
368  "_atom_site_aniso_B_22",
369  "_atom_site_aniso_B_33",
370  "_atom_site_aniso_B_12",
371  "_atom_site_aniso_B_13",
372  "_atom_site_aniso_B_23"
373  };
374 
375  REAL mult[6];
376 
377  EntryIter anisolabels, beta11, beta22, beta33, beta12, beta13, beta23;
378 
379  EntryIter* betaiters[] = {&beta11, &beta22, &beta33, &beta12, &beta13, &beta23};
380 
381  for(LoopIter loop=mvLoop.begin(); loop!=mvLoop.end();++loop)
382  {
383 
384  // Start with anisotropic factors. If we can find the the
385  // "_atom_site_aniso_label" tag, we then want to look for the aniso
386  // information.
387  anisolabels = loop->second.find("_atom_site_aniso_label");
388 
389  // Move to the next loop if we can't find it here.
390  if (anisolabels == loop->second.end()) continue;
391  if(verbose) cout << "Found labels!" << endl;
392 
393  // We have a list of labels. Position the iterators for each of the
394  // adps.
395  for (int idx = 0; idx < 6; ++idx)
396  {
397  EntryIter& betaiter = *betaiters[idx];
398  betaiter = loop->second.find(bijlabels[idx]);
399  mult[idx] = 1.0;
400  if(betaiter == loop->second.end())
401  {
402  betaiter = loop->second.find(uijlabels[idx]);
403  mult[idx] = utob;
404  }
405  if(betaiter == loop->second.end()) mult[idx] = 0.0;
406  }
407 
408  // Check that we have values. If not, then we can get out of here.
409  bool havedata = false;
410  for (int i = 0; i < 6; ++i)
411  {
412  if( mult[i] != 0 ) havedata = true;
413  }
414  if (!havedata) return;
415 
416  // Now loop over the labels, find the corresponding CIFAtom, and fill in
417  // its information.
418  size_t nb = anisolabels->second.size();
419  if(verbose) cout << "Have " << nb << " labels." << endl;
420  for (size_t i = 0; i < nb; ++i)
421  {
422  string label = anisolabels->second[i];
423  if(verbose) cout << label << endl;
424 
425  // See if we have a CIFAtom with this label. If so, initialize the mBeta
426  // vector.
427  vector<CIFAtom>::iterator atom = mvAtom.begin();
428  for (; atom != mvAtom.end(); ++atom)
429  {
430  if (atom->mLabel == label)
431  {
432  atom->mBeta.resize(6, 0.0);
433  break;
434  }
435  }
436  // If we didn't find the mvAtom, then we should move on to the next
437  // label.
438  if (atom == mvAtom.end()) continue;
439 
440  // Fill in what we've got, one entry at a time.
441  for (int idx=0; idx<6; ++idx)
442  {
443  if (mult[idx] == 0)
444  {
445  if(verbose) cout << "skipping index " << idx << endl;
446  continue;
447  }
448 
449  EntryIter& betaiter = *betaiters[idx];
450 
451  if (betaiter->second.size() <= i) continue;
452 
453  double beta = CIFNumeric2REAL(betaiter->second[i]);
454  atom->mBeta[idx] = mult[idx] * beta;
455 
456  if(verbose) cout << "mBeta " << idx << " " << atom->mBeta[idx] << endl;
457  }
458  }
459  }
460  return;
461 }
462 
463 
469 static REAL defaultWavelength=1.0;
470 
471 void CIFData::ExtractPowderPattern(const bool verbose)
472 {
473  map<ci_string,string>::const_iterator positem;
474  positem=mvItem.find("_diffrn_radiation_wavelength");
475  if(positem==mvItem.end()) positem=mvItem.find("_pd_proc_wavelength");
476  if(positem!=mvItem.end())
477  {
478  mWavelength=CIFNumeric2REAL(positem->second);
479  defaultWavelength=mWavelength;
480  if(verbose) cout<<"Found wavelength:"<<defaultWavelength<<endl;
481  }
482  else mWavelength=defaultWavelength;
483 
485  for(map<set<ci_string>,map<ci_string,vector<string> > >::const_iterator loop=mvLoop.begin();
486  loop!=mvLoop.end();++loop)
487  {
488  mDataType=WAVELENGTH_MONOCHROMATIC;
489  map<ci_string,vector<string> >::const_iterator pos_x,pos_iobs,pos_weight,pos_mon,pos_wavelength;
490  pos_wavelength=loop->second.find("_diffrn_radiation_wavelength");
491  if(pos_wavelength!=loop->second.end())
492  {
493  if(verbose) cout<<"Found wavelength (in loop):"<<pos_wavelength->second[0];
494  mWavelength=CIFNumeric2REAL(pos_wavelength->second[0]);
495  defaultWavelength=mWavelength;
496  if(verbose) cout<<" -> "<<defaultWavelength<<endl;
497  }
498 
499  pos_iobs=loop->second.find("_pd_meas_counts_total");
500  if(pos_iobs==loop->second.end()) pos_iobs=loop->second.find("_pd_meas_intensity_total");
501  if(pos_iobs==loop->second.end()) pos_iobs=loop->second.find("_pd_proc_intensity_total");
502  if(pos_iobs==loop->second.end()) pos_iobs=loop->second.find("_pd_proc_intensity_net");
503  if(pos_iobs==loop->second.end()) continue;//no observed powder data found
504  pos_weight=loop->second.find("_pd_proc_ls_weight");
505  pos_x=loop->second.find("_pd_proc_2theta_corrected");
506  if(pos_x==loop->second.end()) pos_x=loop->second.find("_pd_meas_angle_2theta");
507  if(pos_x==loop->second.end()) pos_x=loop->second.find("_pd_meas_2theta_scan");
508  if(pos_x==loop->second.end())
509  {
510  pos_x=loop->second.find("_pd_meas_time_of_flight");
511  if(pos_x!=loop->second.end()) mDataType=WAVELENGTH_TOF;
512  }
513 
514  bool x_fixed_step=false;
515  REAL xmin = 0, xmax = 0, xinc = 0;
516  POSSIBLY_UNUSED(xmax);
517  if(pos_x==loop->second.end())
518  {
519  map<ci_string,string>::const_iterator pos_min,pos_max,pos_inc;
520  pos_min=mvItem.find("_pd_proc_2theta_range_min");
521  if(pos_min==mvItem.end()) pos_min=mvItem.find("_pd_meas_2theta_range_min");
522  pos_max=mvItem.find("_pd_proc_2theta_range_max");
523  if(pos_max==mvItem.end()) pos_max=mvItem.find("_pd_meas_2theta_range_max");
524  pos_inc=mvItem.find("_pd_proc_2theta_range_inc");
525  if(pos_inc==mvItem.end()) pos_inc=mvItem.find("_pd_meas_2theta_range_inc");
526  if((pos_min!=mvItem.end()) && (pos_max!=mvItem.end()) && (pos_inc!=mvItem.end()) )
527  {
528  x_fixed_step=true;
529  xmin=CIFNumeric2REAL(pos_min->second);
530  xmax=CIFNumeric2REAL(pos_max->second);
531  xinc=CIFNumeric2REAL(pos_inc->second);
532  }
533  }
534  pos_mon=loop->second.find("_pd_meas_intensity_monitor");
535  if(pos_mon==loop->second.end()) pos_mon=loop->second.find("_pd_meas_step_count_time");
536 
537  if( (pos_iobs!=loop->second.end()) && ( (pos_x!=loop->second.end()) || (x_fixed_step)) )
538  {// Found powder data !
539  const long nb=pos_iobs->second.size();
540  if(verbose) cout<<"Found powder data, with "<<nb<<" data points"<<endl;
541  mPowderPatternObs.resize(nb);
542  mPowderPatternX.resize(nb);
543  mPowderPatternSigma.resize(nb);
544  REAL mult=1.0;
545  if(mDataType!=WAVELENGTH_TOF) mult=0.017453292519943295;
546  for(long i=0;i<nb;++i)
547  {
548  mPowderPatternObs[i]=CIFNumeric2REAL(pos_iobs->second[i]);
549  if(x_fixed_step) mPowderPatternX[i]=(xmin+i*xinc)*mult;
550  else mPowderPatternX[i]=CIFNumeric2REAL(pos_x->second[i])*mult;
551  // :TODO: use esd on observed intensity, if available.
552  if(pos_weight!=loop->second.end())
553  {
554  mPowderPatternSigma[i]=CIFNumeric2REAL(pos_weight->second[i]);
555  if(mPowderPatternSigma[i]>0) mPowderPatternSigma[i]=1/sqrt(fabs(mPowderPatternSigma[i]));
556  else mPowderPatternSigma[i]=sqrt(fabs(mPowderPatternObs[i])); // :KLUDGE: ?
557  }
558  else mPowderPatternSigma[i]=sqrt(fabs(mPowderPatternObs[i]));
559  if(pos_mon!=loop->second.end())
560  {//VCT or monitor
561  const REAL mon=CIFNumeric2REAL(pos_mon->second[i]);
562  if(mon>0)
563  {
564  mPowderPatternObs[i]/=mon;
565  mPowderPatternSigma[i]/=sqrt(mon);
566  }
567  }
568  //if((i<10) && verbose) cout<<i<<" "<<mPowderPatternX[i]/mult<<" "<<mPowderPatternObs[i]<<" "<<mPowderPatternSigma[i]<<endl;
569  }
570  }
571  }
572 }
573 
574 void CIFData::ExtractSingleCrystalData(const bool verbose)
575 {
576  map<ci_string,string>::const_iterator positem;
577  positem=mvItem.find("_diffrn_radiation_wavelength");
578  if(positem==mvItem.end()) positem=mvItem.find("_pd_proc_wavelength");
579  if(positem!=mvItem.end())
580  {
581  mWavelength=CIFNumeric2REAL(positem->second);
582  defaultWavelength=mWavelength;
583  if(verbose) cout<<"Found wavelength:"<<defaultWavelength<<endl;
584  }
585  else mWavelength=defaultWavelength;
586 
588  for(map<set<ci_string>,map<ci_string,vector<string> > >::const_iterator loop=mvLoop.begin();
589  loop!=mvLoop.end();++loop)
590  {
591  mDataType=WAVELENGTH_MONOCHROMATIC;
592  map<ci_string,vector<string> >::const_iterator pos_h,pos_k,pos_l,pos_iobs,pos_sigma,pos_wavelength;
593  pos_wavelength=loop->second.find("_diffrn_radiation_wavelength");
594  if(pos_wavelength!=loop->second.end())
595  {
596  if(verbose) cout<<"Found wavelength (in loop):"<<pos_wavelength->second[0];
597  mWavelength=CIFNumeric2REAL(pos_wavelength->second[0]);
598  defaultWavelength=mWavelength;
599  if(verbose) cout<<" -> "<<defaultWavelength<<endl;
600  }
601 
602  pos_iobs=loop->second.find("_refln_F_squared_meas");
603  if(pos_iobs==loop->second.end()) continue;//no observed powder data found
604  pos_sigma=loop->second.find("_refln_F_squared_sigma");
605  pos_h=loop->second.find("_refln_index_h");
606  pos_k=loop->second.find("_refln_index_k");
607  pos_l=loop->second.find("_refln_index_l");
608 
609  if( (pos_iobs!=loop->second.end()) && (pos_h!=loop->second.end()) && (pos_k!=loop->second.end()) && (pos_l!=loop->second.end()))
610  {// Found single crystal data !
611  const long nb=pos_iobs->second.size();
612  if(verbose) cout<<"Found single crystal data, with "<<nb<<" data points"<<endl;
613  mIobs.resize(nb);
614  mH.resize(nb);
615  mK.resize(nb);
616  mL.resize(nb);
617  mSigma.resize(nb);
618  for(long i=0;i<nb;++i)
619  {
620  mIobs(i)=CIFNumeric2REAL(pos_iobs->second[i]);
621  mH(i)=CIFNumeric2Int(pos_h->second[i]);
622  mK(i)=CIFNumeric2Int(pos_k->second[i]);
623  mL(i)=CIFNumeric2Int(pos_l->second[i]);
624  if(pos_sigma!=loop->second.end()) mSigma(i)=CIFNumeric2REAL(pos_sigma->second[i]);
625  else mSigma(i)=sqrt(fabs(abs(mIobs(i))));
626  }
627  }
628  }
629 }
630 
631 void CIFData::CalcMatrices(const bool verbose)
632 {
633  if(mvLatticePar.size()==0) return;//:TODO: throw error
634  REAL a,b,c,alpha,beta,gamma;//direct space parameters
635  REAL aa,bb,cc,alphaa,betaa,gammaa;//reciprocal space parameters
636  POSSIBLY_UNUSED(aa);
637  POSSIBLY_UNUSED(bb);
638  POSSIBLY_UNUSED(betaa);
639  POSSIBLY_UNUSED(gammaa);
640  REAL v;//volume of the unit cell
641  a=mvLatticePar[0];
642  b=mvLatticePar[1];
643  c=mvLatticePar[2];
644  alpha=mvLatticePar[3];
645  beta=mvLatticePar[4];
646  gamma=mvLatticePar[5];
647 
648  v=sqrt(fabs(1-cos(alpha)*cos(alpha)-cos(beta)*cos(beta)-cos(gamma)*cos(gamma)
649  +2*cos(alpha)*cos(beta)*cos(gamma)));
650 
651  aa=sin(alpha)/a/v;
652  bb=sin(beta )/b/v;
653  cc=sin(gamma)/c/v;
654 
655  alphaa=acos( (cos(beta )*cos(gamma)-cos(alpha))/sin(beta )/sin(gamma) );
656  betaa =acos( (cos(alpha)*cos(gamma)-cos(beta ))/sin(alpha)/sin(gamma) );
657  gammaa=acos( (cos(alpha)*cos(beta )-cos(gamma))/sin(alpha)/sin(beta ) );
658 
659  mOrthMatrix[0][0]=a;
660  mOrthMatrix[0][1]=b*cos(gamma);
661  mOrthMatrix[0][2]=c*cos(beta);
662 
663  mOrthMatrix[1][0]=0;
664  mOrthMatrix[1][1]=b*sin(gamma);
665  mOrthMatrix[1][2]=-c*sin(beta)*cos(alphaa);
666 
667  mOrthMatrix[2][0]=0;
668  mOrthMatrix[2][1]=0;
669  mOrthMatrix[2][2]=1/cc;
670 
671  // Invert upper triangular matrix
672  REAL cm[3][3];
673  cm[0][0]=mOrthMatrix[0][0];
674  cm[0][1]=mOrthMatrix[0][1];
675  cm[0][2]=mOrthMatrix[0][2];
676 
677  cm[1][0]=mOrthMatrix[1][0];
678  cm[1][1]=mOrthMatrix[1][1];
679  cm[1][2]=mOrthMatrix[1][2];
680 
681  cm[2][0]=mOrthMatrix[2][0];
682  cm[2][1]=mOrthMatrix[2][1];
683  cm[2][2]=mOrthMatrix[2][2];
684  for(long i=0;i<3;i++)
685  for(long j=0;j<3;j++)
686  if(i==j) mOrthMatrixInvert[i][j]=1;
687  else mOrthMatrixInvert[i][j]=0;
688  for(long i=0;i<3;i++)
689  {
690  REAL a;
691  for(long j=i-1;j>=0;j--)
692  {
693  a=cm[j][i]/cm[i][i];
694  for(long k=0;k<3;k++) mOrthMatrixInvert[j][k] -= mOrthMatrixInvert[i][k]*a;
695  for(long k=0;k<3;k++) cm[j][k] -= cm[i][k]*a;
696  }
697  a=cm[i][i];
698  for(long k=0;k<3;k++) mOrthMatrixInvert[i][k] /= a;
699  for(long k=0;k<3;k++) cm[i][k] /= a;
700  }
701  if(verbose)
702  {
703  cout <<"Fractional2Cartesian matrix:"<<endl
704  <<mOrthMatrix[0][0]<<" "<<mOrthMatrix[0][1]<<" "<<mOrthMatrix[0][2]<<endl
705  <<mOrthMatrix[1][0]<<" "<<mOrthMatrix[1][1]<<" "<<mOrthMatrix[1][2]<<endl
706  <<mOrthMatrix[2][0]<<" "<<mOrthMatrix[2][1]<<" "<<mOrthMatrix[2][2]<<endl<<endl;
707  /*
708  cout <<cm[0][0]<<" "<<cm[0][1]<<" "<<cm[0][2]<<endl
709  <<cm[1][0]<<" "<<cm[1][1]<<" "<<cm[1][2]<<endl
710  <<cm[2][0]<<" "<<cm[2][1]<<" "<<cm[2][2]<<endl<<endl;
711  */
712  cout <<"Cartesian2Fractional matrix:"<<endl
713  <<mOrthMatrixInvert[0][0]<<" "<<mOrthMatrixInvert[0][1]<<" "<<mOrthMatrixInvert[0][2]<<endl
714  <<mOrthMatrixInvert[1][0]<<" "<<mOrthMatrixInvert[1][1]<<" "<<mOrthMatrixInvert[1][2]<<endl
715  <<mOrthMatrixInvert[2][0]<<" "<<mOrthMatrixInvert[2][1]<<" "<<mOrthMatrixInvert[2][2]<<endl<<endl;
716  }
717 }
718 
719 void CIFData::f2c(REAL &x,REAL &y, REAL &z)
720 {
721  const REAL x0=x,y0=y,z0=z;
722  x=mOrthMatrix[0][0]*x0+mOrthMatrix[0][1]*y0+mOrthMatrix[0][2]*z0;
723  y=mOrthMatrix[1][0]*x0+mOrthMatrix[1][1]*y0+mOrthMatrix[1][2]*z0;
724  z=mOrthMatrix[2][0]*x0+mOrthMatrix[2][1]*y0+mOrthMatrix[2][2]*z0;
725 }
726 
727 void CIFData::c2f(REAL &x,REAL &y, REAL &z)
728 {
729  const REAL x0=x,y0=y,z0=z;
730  x=mOrthMatrixInvert[0][0]*x0+mOrthMatrixInvert[0][1]*y0+mOrthMatrixInvert[0][2]*z0;
731  y=mOrthMatrixInvert[1][0]*x0+mOrthMatrixInvert[1][1]*y0+mOrthMatrixInvert[1][2]*z0;
732  z=mOrthMatrixInvert[2][0]*x0+mOrthMatrixInvert[2][1]*y0+mOrthMatrixInvert[2][2]*z0;
733 }
734 
735 void CIFData::Cartesian2FractionalCoord()
736 {
737  for(vector<CIFAtom>::iterator pos=mvAtom.begin();pos!=mvAtom.end();++pos)
738  {
739  pos->mCoordFrac.resize(3);
740  pos->mCoordFrac[0]=pos->mCoordCart.at(0);
741  pos->mCoordFrac[1]=pos->mCoordCart.at(1);
742  pos->mCoordFrac[2]=pos->mCoordCart.at(2);
743  c2f(pos->mCoordFrac[0],pos->mCoordFrac[1],pos->mCoordFrac[2]);
744  }
745 }
746 
747 void CIFData::Fractional2CartesianCoord()
748 {
749  for(vector<CIFAtom>::iterator pos=mvAtom.begin();pos!=mvAtom.end();++pos)
750  {
751  pos->mCoordCart.resize(3);
752  pos->mCoordCart[0]=pos->mCoordFrac.at(0);
753  pos->mCoordCart[1]=pos->mCoordFrac.at(1);
754  pos->mCoordCart[2]=pos->mCoordFrac.at(2);
755  f2c(pos->mCoordCart[0],pos->mCoordCart[1],pos->mCoordCart[2]);
756  }
757 }
758 
760 
761 
762 CIF::CIF(istream &is, const bool interpret,const bool verbose)
763 {
764  string s;
765  (*fpObjCrystInformUser)("CIF: Opening CIF");
766  Chronometer chrono;
767  chrono.start();
768  //Copy to an iostream so that we can put back characters if necessary
769  stringstream in;
770  char c;
771  while(is.get(c))in.put(c);
772  const float t0read=chrono.seconds();
773  s=(boost::format("CIF: Parsing CIF (reading dt=%5.3fs)")%t0read).str();
774  (*fpObjCrystInformUser)(s);
775  this->Parse(in);
776  const float t1parse=chrono.seconds();
777  s=(boost::format("CIF: Finished Parsing, Extracting...(parsing dt=%5.3fs)") % (t1parse-t0read)).str();
778  (*fpObjCrystInformUser)(s);
779  // Extract structure from blocks
780  if(interpret)
781  for(map<string,CIFData>::iterator posd=mvData.begin();posd!=mvData.end();++posd)
782  posd->second.ExtractAll(verbose);
783  const float t2interpret=chrono.seconds();
784  s=(boost::format("CIF: Finished Import...(interpret dt=%5.3fs, total CIF import=%5.3fs)")%(t2interpret-t1parse)%t2interpret).str();
785  (*fpObjCrystInformUser)(s);
786 }
787 
788 bool iseol(const char c) { return ((c=='\n')||(c=='\r'));}
789 
790 std::string trimString(const std::string &s)
791 {
792  const size_t i0 = s.find_first_not_of(" \t\r\n");
793  if (i0 == std::string::npos) return "";
794  const size_t i1 = s.find_last_not_of(" \t\r\n");
795  return s.substr(i0, i1-i0+1);
796 }
797 
799 string CIFReadValue(stringstream &in,char &lastc)
800 {
801  bool vv=false;//very verbose ?
802  string value;
803  while(!isgraph(in.peek())) in.get(lastc);
804  while(in.peek()=='#')
805  {//discard these comments for now
806  string tmp;
807  getline(in,tmp);
808  lastc='\r';
809  while(!isgraph(in.peek())) in.get(lastc);
810  }
811  if(in.peek()==';')
812  {//SemiColonTextField
813  bool warning=!iseol(lastc);
814  if(warning)
815  cout<<"WARNING: Trying to read a SemiColonTextField but last char is not an end-of-line char !"<<endl;
816  value="";
817  in.get(lastc);
818  while(in.peek()!=';')
819  {
820  string tmp;
821  getline(in,tmp);
822  value+=tmp+" ";
823  }
824  in.get(lastc);
825  if(vv) cout<<"SemiColonTextField:"<<value<<endl;
826  if(warning && !vv) cout<<"SemiColonTextField:"<<value<<endl;
827  return trimString(value);
828  }
829  if((in.peek()=='\'') || (in.peek()=='\"'))
830  {//QuotedString
831  char delim;
832  in.get(delim);
833  value="";
834  while(!((lastc==delim)&&(!isgraph(in.peek()))) )
835  {
836  in.get(lastc);
837  value+=lastc;
838  }
839  if(vv) cout<<"QuotedString:"<<value<<endl;
840  return trimString(value.substr(0,value.size()-1));
841  }
842  // If we got here, we have an ordinary value, numeric or unquoted string
843  in>>value;
844  if(vv) cout<<"NormalValue:"<<value<<endl;
845  return value;
846 }
847 
848 void CIF::Parse(stringstream &in)
849 {
850  bool vv=false;//very verbose ?
851  char lastc=' ';
852  string block="";// Current block data
853  while(!in.eof())
854  {
855  //stringstream mess;
856  //mess<<"CIF: Parsing:"<<in.tellg();
857  //(*fpObjCrystInformUser)(mess.str());
858  while(!isgraph(in.peek()) && !in.eof()) in.get(lastc);
859  if(in.eof()) break;
860  if(vv) cout<<endl;
861  if(in.peek()=='#')
862  {//Comment
863  string tmp;
864  getline(in,tmp);
865  if(block=="") mvComment.push_back(tmp);
866  else mvData[block].mvComment.push_back(tmp);
867  lastc='\r';
868  if(vv)cout<<"Comment:"<<tmp<<endl;
869  continue;
870  }
871  if(in.peek()=='_')
872  {//Tag
873  string tag,value;
874  in>>tag;
875  // Convert all dots to underscores to cover much of DDL2 with this DDL1 parser.
876  for (string::size_type pos = tag.find('.'); pos != string::npos; pos = tag.find('.', ++ pos))
877  tag.replace(pos, 1, 1, '_');
878  value=CIFReadValue(in,lastc);
879  if(value==string("?")) continue;//useless
880  mvData[block].mvItem[ci_string(tag.c_str())]=value;
881  if(vv)cout<<"New Tag:"<<tag<<" ("<<value.size()<<"):"<<value<<endl;
882  continue;
883  }
884  if((in.peek()=='d') || (in.peek()=='D'))
885  {// Data
886  string tmp;
887  in>>tmp;
888  block=tmp.substr(5);
889  if(vv) cout<<endl<<endl<<"NEW BLOCK DATA: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ->"<<block<<endl<<endl<<endl;
890  mvData[block]=CIFData();
891  continue;
892  }
893  if((in.peek()=='l') || (in.peek()=='L'))
894  {// loop_
895  vector<ci_string> tit;
896  string tmp;
897  in>>tmp; //should be loop_
898  if(vv) cout<<"LOOP : "<<tmp;
899  while(!in.eof())
900  {//read titles
901  while(!isgraph(in.peek()) && !in.eof()) in.get(lastc);
902  if(in.peek()=='#')
903  {
904  getline(in,tmp);
905  if(block=="") mvComment.push_back(tmp);
906  else mvData[block].mvComment.push_back(tmp);
907  continue;
908  }
909  if(in.peek()!='_')
910  {
911  if(vv) cout<<endl<<"End of loop titles:"<<(char)in.peek()<<endl;
912  break;
913  }
914  in>>tmp;
915  // Convert all dots to underscores to cover much of DDL2 with this DDL1 parser.
916  for (string::size_type pos = tmp.find('.'); pos != string::npos; pos = tmp.find('.', ++ pos))
917  tmp.replace(pos, 1, 1, '_');
918  tit.push_back(ci_string(tmp.c_str()));
919  if(vv) cout<<" , "<<tmp;
920  }
921  if(vv) cout<<endl;
922  map<ci_string,vector<string> > lp;
923  while(true)
924  {
925  while(!isgraph(in.peek()) && !in.eof()) in.get(lastc);
926  if(in.eof()) break;
927  if(vv) cout<<"LOOP VALUES...: "<<(char)in.peek()<<" "<<endl;
928  if(in.peek()=='_') break;
929  if(in.peek()=='#')
930  {// Comment (in a loop ??)
931  string tmp;
932  getline(in,tmp);
933  if(block=="") mvComment.push_back(tmp);
934  else mvData[block].mvComment.push_back(tmp);
935  lastc='\r';
936  if(vv) cout<<"Comment in a loop (?):"<<tmp<<endl;
937  continue;
938  };
939  const std::ios::pos_type pos=in.tellg();
940  in>>tmp;
941  if(vv) cout<<"WHATNEXT? "<<tmp;
942  if(ci_string(tmp.c_str())=="loop_")
943  {//go back and continue
944  if(vv) cout<<endl<<"END OF LOOP :"<<tmp<<endl;
945  in.seekg(pos);
946  break;
947  }
948  if(tmp.size()>=5)
949  if(ci_string(tmp.substr(0,5).c_str())=="data_")
950  {//go back and continue
951  if(vv) cout<<endl<<"END OF LOOP :"<<tmp<<endl;
952  in.seekg(pos);
953  break;
954  }
955  // go back
956  in.seekg(pos);
957  for(unsigned int i=0;i<tit.size();++i)
958  {//Read all values
959  const string value=CIFReadValue(in,lastc);
960  lp[tit[i]].push_back(value);
961  if(vv) cout<<" #"<<i<<" : "<<value<<endl;
962  }
963  }
964  // The key to the mvLoop map is the set of column titles
965  set<ci_string> stit;
966  for(unsigned int i=0;i<tit.size();++i) stit.insert(tit[i]);
967  mvData[block].mvLoop[stit]=lp;
968  continue;
969  }
970  // If we get here, something went wrong ! Discard till end of line...
971  string junk;
972  getline(in,junk);
973  cout<<"WARNING: did not understand : "<<junk<<endl;
974  }
975 }
976 
977 REAL CIFNumeric2REAL(const string &s)
978 {
979  if((s==".") || (s=="?")) return 0.0;
980  // Use stream rather than sscanf to rely on C++ locale to read C-locale values
981  REAL v=0;
982  stringstream ss(s);
983  ss.imbue(std::locale::classic());
984  ss>>v;
985  return v;
986 }
987 
988 int CIFNumeric2Int(const string &s)
989 {
990  if((s==".") || (s=="?")) return 0;
991  // Use stream rather than sscanf to rely on C++ locale to read C-locale values
992  int v=0;
993  stringstream ss(s);
994  ss.imbue(std::locale::classic());
995  ss>>v;
996  return v;
997 }
998 
999 Crystal* CreateCrystalFromCIF(CIF &cif,bool verbose,bool checkSymAsXYZ)
1000 {
1001  return CreateCrystalFromCIF(cif,verbose,checkSymAsXYZ,false,false);
1002 }
1003 
1004 Crystal* CreateCrystalFromCIF(CIF &cif,const bool verbose,const bool checkSymAsXYZ,
1005  const bool oneScatteringPowerPerElement, const bool connectAtoms,
1006  Crystal *pCryst)
1007 {
1008  (*fpObjCrystInformUser)("CIF: Opening CIF");
1009  Chronometer chrono;
1010  chrono.start();
1011 
1012  // If oneScatteringPowerPerElement==true, we hold this to compute the average Biso per element
1013  std::map<ScatteringPower*,std::pair<REAL,unsigned int> > vElementBiso;
1014 
1015  bool import_multiple = true;
1016  if(pCryst!=NULL) import_multiple = false;
1017  bool crystal_found = false;
1018 
1019  for(map<string,CIFData>::iterator pos=cif.mvData.begin();pos!=cif.mvData.end();++pos)
1020  if(pos->second.mvLatticePar.size()==6)
1021  {
1022  // If no atoms are listed and we already have a crystal structure defined,
1023  //asssume we don't want this one - e.g. like some IuCr journals single crystal
1024  //data cif files including cell parameters
1025  if((pos->second.mvAtom.size()==0) && (gCrystalRegistry.GetNb()>0)) continue;
1026  // Use unambigous Hall symbol if present, otherwise try HM symbol or spg number
1027  string spg;
1028  if(pos->second.mSpacegroupSymbolHall!="") try
1029  {
1030  tmp_C_Numeric_locale tmploc;
1031  cctbx::sgtbx::space_group cctbxspg(pos->second.mSpacegroupSymbolHall);
1032  cctbxspg.t_den();
1033  cctbxspg.n_smx();
1034  cctbxspg.n_ltr();
1035  cctbxspg.type();
1036  cctbxspg.type().number();
1037  cctbxspg.type().hall_symbol();
1038  cctbxspg.type().lookup_symbol();
1039  cctbxspg.match_tabulated_settings().extension();
1040  cctbxspg.match_tabulated_settings().hermann_mauguin();
1041  cctbxspg.type().universal_hermann_mauguin_symbol();
1042  cctbx::sgtbx::brick b(cctbxspg.type());
1043  spg=pos->second.mSpacegroupSymbolHall;
1044  }
1045  catch(exception)
1046  {
1047  VFN_DEBUG_MESSAGE("CreateCrystalFromCIF(): could not interpret Hall symbol:"<<pos->second.mSpacegroupSymbolHall, 10)
1048  }
1049  if((spg=="") && (pos->second.mSpacegroupHermannMauguin!="")) try
1050  {
1051  tmp_C_Numeric_locale tmploc;
1052  cctbx::sgtbx::space_group cctbxspg(cctbx::sgtbx::space_group_symbols(pos->second.mSpacegroupHermannMauguin));
1053  cctbxspg.t_den();
1054  cctbxspg.n_smx();
1055  cctbxspg.n_ltr();
1056  cctbxspg.type();
1057  cctbxspg.type().number();
1058  cctbxspg.type().hall_symbol();
1059  cctbxspg.type().lookup_symbol();
1060  cctbxspg.type().universal_hermann_mauguin_symbol();
1061  cctbxspg.match_tabulated_settings().extension();
1062  cctbxspg.match_tabulated_settings().hermann_mauguin();
1063  cctbx::sgtbx::brick b(cctbxspg.type());
1064  spg=pos->second.mSpacegroupHermannMauguin;
1065  }
1066  catch(exception)
1067  {
1068  VFN_DEBUG_MESSAGE("CreateCrystalFromCIF(): could not interpret Hermann-Mauguin symbol:"<<pos->second.mSpacegroupHermannMauguin, 10)
1069  }
1070  if((spg=="") && (pos->second.mSpacegroupNumberIT!=""))
1071  try
1072  {
1073  tmp_C_Numeric_locale tmploc;
1074  cctbx::sgtbx::space_group cctbxspg(cctbx::sgtbx::space_group_symbols(pos->second.mSpacegroupNumberIT));
1075  cctbxspg.t_den();
1076  cctbxspg.n_smx();
1077  cctbxspg.n_ltr();
1078  cctbxspg.type();
1079  cctbxspg.type().number();
1080  cctbxspg.type().hall_symbol();
1081  cctbxspg.type().lookup_symbol();
1082  cctbxspg.type().universal_hermann_mauguin_symbol();
1083  cctbxspg.match_tabulated_settings().extension();
1084  cctbxspg.match_tabulated_settings().hermann_mauguin();
1085  cctbx::sgtbx::brick b(cctbxspg.type());
1086  spg=pos->second.mSpacegroupNumberIT;
1087  }
1088  catch(exception)
1089  {
1090  VFN_DEBUG_MESSAGE("CreateCrystalFromCIF(): could not interpret spacegroup number (!) :"<<pos->second.mSpacegroupNumberIT, 10)
1091  }
1092  if(spg=="") spg="P1";
1093  if(verbose) cout<<"Create crystal with spacegroup: "<<spg
1094  <<" / "<<pos->second.mSpacegroupHermannMauguin
1095  <<" / "<<pos->second.mSpacegroupSymbolHall
1096  <<" / "<<pos->second.mSpacegroupNumberIT
1097  <<"-> "<<spg
1098  <<endl;
1099  (*fpObjCrystInformUser)("CIF: Create Crystal=");
1100  if(pCryst==NULL)
1101  pCryst=new Crystal(pos->second.mvLatticePar[0],pos->second.mvLatticePar[1],pos->second.mvLatticePar[2],
1102  pos->second.mvLatticePar[3],pos->second.mvLatticePar[4],pos->second.mvLatticePar[5],spg);
1103  else
1104  pCryst->Init(pos->second.mvLatticePar[0],pos->second.mvLatticePar[1],pos->second.mvLatticePar[2],
1105  pos->second.mvLatticePar[3],pos->second.mvLatticePar[4],pos->second.mvLatticePar[5],spg, "");
1106  crystal_found = true;
1107  if( (pos->second.mSpacegroupSymbolHall=="")
1108  &&(pos->second.mvSymmetry_equiv_pos_as_xyz.size()>0)
1109  &&(pos->second.mSpacegroupHermannMauguin!="")
1110  &&checkSymAsXYZ)
1111  {// Could not use a Hall symbol, but we have a list of symmetry_equiv_pos_as_xyz,
1112  // so check we have used the best possible origin
1113  tmp_C_Numeric_locale tmploc;
1114  static vector<string> origin_list;
1115  if(origin_list.size()==0)
1116  {//ugly ?
1117  origin_list.resize(5);
1118  origin_list[0]="";
1119  origin_list[1]=":1";
1120  origin_list[2]=":2";
1121  origin_list[3]=":R";
1122  origin_list[4]=":H";
1123  }
1124  // If we do not have an HM symbol, then use the one generated by cctbx (normally from spg number)
1125  string hmorig=pos->second.mSpacegroupHermannMauguin;
1126  if(hmorig=="") hmorig=pCryst->GetSpaceGroup().GetCCTbxSpg().match_tabulated_settings().hermann_mauguin();
1127 
1128  if(verbose) cout<<" Symmetry checking using symmetry_equiv_pos_as_xyz:"<<endl;
1129  string bestsymbol=hmorig;
1130  unsigned int bestscore=0;
1131  for(vector<string>::const_iterator posOrig=origin_list.begin();posOrig!=origin_list.end();++posOrig)
1132  {
1133  // The origin extension may not make sense, so we need to watch for exception
1134  try
1135  {
1136  pCryst->ChangeSpaceGroup(hmorig+*posOrig);
1137  }
1138  catch(invalid_argument)
1139  {
1140  continue;
1141  }
1142 
1143  // If the symbol is the same as before, the origin probably was not understood - no need to test
1144  if((posOrig!=origin_list.begin())&&(pCryst->GetSpaceGroup().GetName()==bestsymbol)) continue;
1145 
1146  unsigned int nbSymSpg=pCryst->GetSpaceGroup().GetCCTbxSpg().all_ops().size();
1147  unsigned int nbSymCommon=0;
1148  try
1149  {
1150  for(unsigned int i=0;i<nbSymSpg;i++)
1151  {
1152  for(set<string>::const_iterator posSymCIF=pos->second.mvSymmetry_equiv_pos_as_xyz.begin();
1153  posSymCIF!=pos->second.mvSymmetry_equiv_pos_as_xyz.end();++posSymCIF)
1154  {
1155  cctbx::sgtbx::rt_mx mx1(*posSymCIF);
1156  cctbx::sgtbx::rt_mx mx2(pCryst->GetSpaceGroup().GetCCTbxSpg().all_ops()[i]);
1157  mx1.mod_positive_in_place();
1158  mx2.mod_positive_in_place();
1159  if(mx1==mx2)
1160  {
1161  nbSymCommon++;
1162  break;
1163  }
1164  }
1165  }
1166  if(verbose) cout<<" Trying: "<<pCryst->GetSpaceGroup().GetName()
1167  <<" nbsym:"<<nbSymSpg<<"(cctbx), "
1168  <<pos->second.mvSymmetry_equiv_pos_as_xyz.size()<<"(CIF)"
1169  <<",common:"<<nbSymCommon<<endl;
1170  if(bestscore<((nbSymSpg==pos->second.mvSymmetry_equiv_pos_as_xyz.size())*nbSymCommon))
1171  {
1172  bestscore=(nbSymSpg==pos->second.mvSymmetry_equiv_pos_as_xyz.size())*nbSymCommon;
1173  bestsymbol=pCryst->GetSpaceGroup().GetName();
1174  }
1175  }
1176  catch(cctbx::error)
1177  {
1178  cout<<"WOOPS: cctbx error ! Wrong symmetry_equiv_pos_as_xyz strings ?"<<endl;
1179  }
1180  }
1181  if(verbose) cout<<endl<<"Finally using spacegroup name:"<<bestsymbol<<endl;
1182  pCryst->ChangeSpaceGroup(bestsymbol);
1183  }
1184  // Try to set name from CIF. If that fails, the computed formula will be used at the end
1185  if(pos->second.mName!="") pCryst->SetName(pos->second.mName);
1186  else if(pos->second.mFormula!="") pCryst->SetName(pos->second.mFormula);
1187 
1188  const float t1=chrono.seconds();
1189  (*fpObjCrystInformUser)((boost::format("CIF: Create Crystal:%s(%s)(dt=%6.3fs)")%pCryst->GetName() % pCryst->GetSpaceGroup().GetName() % t1).str());
1190 
1191  bool doInformUserAllAtoms=true;
1192  if(pos->second.mvAtom.size()>30) doInformUserAllAtoms = false;
1193  unsigned int ctatom=0;
1194  for(vector<CIFData::CIFAtom>::const_iterator posat=pos->second.mvAtom.begin();posat!=pos->second.mvAtom.end();++posat)
1195  {
1196  if( (posat->mLabel==".") || (posat->mSymbol==".") || (posat->mLabel.find("dummy")!=std::string::npos) || (posat->mSymbol.find("dummy")!=std::string::npos) )
1197  {
1198  if(doInformUserAllAtoms) (*fpObjCrystInformUser)("CIF: Ignoring DUMMY Atom:"+posat->mLabel+"(symbol="+posat->mSymbol+")");
1199  continue;
1200  }
1201  ctatom++;
1202 
1203  //const float t20=chrono.seconds();
1204  // Try to find an existing scattering power with the same properties, or create a new one
1205  ScatteringPower* sp=NULL;
1206  if(oneScatteringPowerPerElement)
1207  {
1208  for(unsigned int i=0;i<pCryst->GetScatteringPowerRegistry().GetNb();++i)
1209  {
1210  if(pCryst->GetScatteringPowerRegistry().GetObj(i).GetSymbol()!=posat->mSymbol) continue;
1211  vElementBiso[&(pCryst->GetScatteringPowerRegistry().GetObj(i))].first+=posat->mBiso;
1212  vElementBiso[&(pCryst->GetScatteringPowerRegistry().GetObj(i))].second+=1;
1213  sp=&(pCryst->GetScatteringPowerRegistry().GetObj(i));
1214  break;
1215  }
1216  if(sp==NULL)
1217  {
1218  if(verbose) cout<<"Scattering power "<<posat->mSymbol<<" not found, creating it..."<<endl;
1219  sp = new ScatteringPowerAtom(posat->mSymbol,posat->mSymbol);
1220  // Always extract isotropic DP, even with ADPs present
1221  // :TODO: if only ADP are listed, calculate isotropic DP
1222  vElementBiso[sp].first+=posat->mBiso;
1223  vElementBiso[sp].second=1;
1224  pCryst->AddScatteringPower(sp);
1225  //const float t21=chrono.seconds();
1226  //(*fpObjCrystInformUser)((boost::format("CIF: Add scattering power: %s (dt=%6.3fsCrystal creation=%6.3fs total)")% posat->mSymbol % (t21-t20) % t21).str());
1227  }
1228  }
1229  else
1230  {
1231  #if 0
1232  for(unsigned int i=0;i<pCryst->GetScatteringPowerRegistry().GetNb();++i)
1233  {
1234  if(pCryst->GetScatteringPowerRegistry().GetObj(i).GetSymbol()!=posat->mSymbol) continue;
1235  if(posat->mBeta.size() == 6)
1236  {
1237  if( (pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(0)!=posat->mBeta[0])
1238  ||(pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(1)!=posat->mBeta[1])
1239  ||(pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(2)!=posat->mBeta[2])
1240  ||(pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(3)!=posat->mBeta[3])
1241  ||(pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(4)!=posat->mBeta[4])
1242  ||(pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(5)!=posat->mBeta[5])) continue;
1243  }
1244  else if(posat->mBiso!=pCryst->GetScatteringPowerRegistry().GetObj(i).GetBiso()) continue;
1245  sp=&(pCryst->GetScatteringPowerRegistry().GetObj(i));
1246  break;
1247  }
1248  if(sp==NULL)
1249  #endif
1250  {
1251  if(verbose) cout<<"Creating new scattering power for:"<<posat->mLabel<<endl;
1252  sp = new ScatteringPowerAtom(posat->mLabel,posat->mSymbol);
1253  // Always extract isotropic DP, even with ADPs present
1254  // :TODO: if only ADP are listed, calculate isotropic DP
1255  sp->SetBiso(posat->mBiso);
1256  // ADPs ?
1257  if(posat->mBeta.size() == 6)
1258  {
1259  for (int idx=0; idx<6; ++idx) sp->SetBij(idx, posat->mBeta[idx]);
1260  }
1261  pCryst->AddScatteringPower(sp);
1262  //const float t21=chrono.seconds();
1263  //(*fpObjCrystInformUser)((boost::format("CIF: Add scattering power: %s (dt=%6.3fsCrystal creation=%6.3fs total)") % posat->mLabel % (t21-t20) % t21).str());
1264  }
1265  }
1266  // (*fpObjCrystInformUser)("CIF: Add Atom:"+posat->mLabel+"("+sp->GetName()+")");
1267  pCryst->AddScatterer(new Atom(posat->mCoordFrac[0],posat->mCoordFrac[1],posat->mCoordFrac[2],
1268  posat->mLabel,sp,posat->mOccupancy));
1269  const float t22=chrono.seconds();
1270  if(doInformUserAllAtoms) (*fpObjCrystInformUser)((boost::format("CIF: new Atom: %s (%s) (Crystal creation=%6.3fs total)") % posat->mLabel % sp->GetName() % t22).str());
1271  else if (ctatom%20 == 0)(*fpObjCrystInformUser)((boost::format("CIF: imported %u atoms (Crystal creation=%6.3fs total)") % ctatom % t22).str());
1272  }
1273  if(oneScatteringPowerPerElement)
1274  {
1275  for(std::map<ScatteringPower*,std::pair<REAL,unsigned int> >::iterator pos=vElementBiso.begin();pos!=vElementBiso.end();++pos)
1276  pos->first->SetBiso(pos->second.first/pos->second.second);
1277  }
1278  (*fpObjCrystInformUser)((boost::format("CIF: Finished importing %u atoms (Crystal creation=%6.3fs total)") % ctatom % chrono.seconds()).str());
1279  if(connectAtoms)
1280  {
1281  (*fpObjCrystInformUser)("CIF: connecting atoms");
1282  pCryst->ConnectAtoms();
1283  unsigned int ctat=0;
1284  unsigned int ctmol=0;
1285  for(int i=0;i<pCryst->GetNbScatterer();i++)
1286  {
1287  if(pCryst->GetScatt(i).GetClassName()=="Atom") ctat +=1;
1288  else if(pCryst->GetScatt(i).GetClassName()=="Molecule") ctmol +=1;
1289  }
1290  (*fpObjCrystInformUser)((boost::format("CIF: finished connecting atoms (%u isolated atoms, %u molecules) (Crystal creation=%6.3fs total)") % ctat % ctmol % chrono.seconds()).str());
1291  }
1292  if(pCryst->GetName()=="") pCryst->SetName(pCryst->GetFormula());
1293  if(!import_multiple) return pCryst;
1294  }
1295  if(!crystal_found) throw ObjCrystException("CreateCrystalFromCIF: no structure found");
1296  return pCryst;
1297 }
1298 
1300 {
1301  PowderPattern* pPow=NULL;
1302  for(map<string,CIFData>::iterator pos=cif.mvData.begin();pos!=cif.mvData.end();++pos)
1303  {
1304  if(pos->second.mPowderPatternObs.size()>10)
1305  {
1306  pPow=new PowderPattern();
1307  pPow->ImportPowderPatternCIF(cif);
1308  (*fpObjCrystInformUser)((boost::format("CIF: Imported POWDER PATTERN, with %d points") % pPow->GetNbPoint()).str());
1309  }
1310  }
1311  return pPow;
1312 }
1313 
1315 {
1316  DiffractionDataSingleCrystal* pData=NULL;
1317  std::string name("");
1318  for(map<string,CIFData>::iterator pos=cif.mvData.begin();pos!=cif.mvData.end();++pos)
1319  {
1320  if(pos->second.mH.numElements()>0)
1321  {
1322  (*fpObjCrystInformUser)((boost::format("CIF: Importing SINGLE CRYSTAL DIFFRACTION data")).str());
1323  if(pcryst==0)
1324  {
1325  if(gCrystalRegistry.GetNb()>0)
1326  { // Use last Crystal created
1327  pcryst=&(gCrystalRegistry.GetObj(gCrystalRegistry.GetNb()-1));
1328  (*fpObjCrystInformUser)((boost::format("CIF: Importing SINGLE CRYSTAL DIFFRACTION data: using last Crystal structure as corresponding crystal [%s]") % pcryst->GetName().c_str()).str());
1329  name = pcryst->GetName();
1330  }
1331  else
1332  {
1333  pcryst=new Crystal;
1334  pcryst->SetName("Crystal data for Single Crystal Diffraction data imported from CIF");
1335  (*fpObjCrystInformUser)((boost::format("CIF: Importing SINGLE CRYSTAL DIFFRACTION data: creating new empty Crystal structure")).str());
1336  }
1337  }
1338  pData=new DiffractionDataSingleCrystal(*pcryst);
1339  pData->SetHklIobs(pos->second.mH,pos->second.mK,pos->second.mL,pos->second.mIobs,pos->second.mSigma);
1340  if(pData->GetName()=="") pData->SetName(name);
1341  (*fpObjCrystInformUser)((boost::format("CIF: Imported SINGLE CRYSTAL DIFFRACTION data, with %d reflections") % pData->GetNbRefl()).str());
1342  }
1343  }
1344  return pData;
1345 }
1346 
1347 }//namespace
The namespace which includes all objects (crystallographic and algorithmic) in ObjCryst++.
Definition: doc-main.h:25
DiffractionDataSingleCrystal * CreateSingleCrystalDataFromCIF(CIF &cif, Crystal *pcryst)
Create DiffractionDataSingleCrystal object(s) from a CIF, if possible.
Definition: CIF.cpp:1314
Crystal * CreateCrystalFromCIF(CIF &cif, bool verbose, bool checkSymAsXYZ)
Extract Crystal object(s) from a CIF, if possible.
Definition: CIF.cpp:999
static REAL defaultWavelength
This is the default wavelength - whenever a "_diffrn_radiation_wavelength" or "_pd_proc_wavelength"en...
Definition: CIF.cpp:469
string CIFReadValue(stringstream &in, char &lastc)
Read one value, whether it is numeric, string or text.
Definition: CIF.cpp:799
ObjRegistry< Crystal > gCrystalRegistry("List of all Crystals")
Global registry for all Crystal objects.
Definition: Crystal.h:669
PowderPattern * CreatePowderPatternFromCIF(CIF &cif)
Create PowderPattern object(s) from a CIF, if possible.
Definition: CIF.cpp:1299
The basic atom scatterer, in a crystal.
Definition: Atom.h:58
The CIFData class holds all the information from a single data_ block from a cif file.
Definition: CIF.h:63
Main CIF class - parses the stream and separates data blocks, comments, items, loops.
Definition: CIF.h:170
std::map< std::string, CIFData > mvData
The data blocks, after parsing. The key is the name of the data block.
Definition: CIF.h:181
Crystal class: Unit cell, spacegroup, scatterers.
Definition: Crystal.h:98
void ConnectAtoms(const REAL min_relat_dist=0.4, const REAL max_relat_dist=1.3, const bool warnuser_fail=false)
Convert as much as possible the crystal's atoms to molecule(s).
Definition: Crystal.cpp:1626
void AddScatteringPower(ScatteringPower *scattPow)
Add a ScatteringPower for this Crystal.
Definition: Crystal.cpp:241
ObjRegistry< ScatteringPower > & GetScatteringPowerRegistry()
Get the registry of ScatteringPower included in this Crystal.
Definition: Crystal.cpp:236
Scatterer & GetScatt(const string &scattName)
Provides an access to the scatterers.
Definition: Crystal.cpp:212
std::string GetFormula() const
Formula with atoms in alphabetic order.
Definition: Crystal.cpp:405
long GetNbScatterer() const
Number of scatterers in the crystal.
Definition: Crystal.cpp:210
void AddScatterer(Scatterer *scatt)
Add a scatterer to the crystal.
Definition: Crystal.cpp:188
void Init(const REAL a, const REAL b, const REAL c, const REAL alpha, const REAL beta, const REAL gamma, const string &SpaceGroupId, const string &name)
Init all Crystal parameters.
Definition: Crystal.cpp:1603
DiffractionData object for Single Crystal analysis.
void SetHklIobs(const CrystVector_long &h, const CrystVector_long &k, const CrystVector_long &l, const CrystVector_REAL &iObs, const CrystVector_REAL &sigma)
input H,K,L, Iobs and Sigma
Exception class for ObjCryst++ library.
Definition: General.h:122
This class only serves to temporarilly set the LC_NUMERIC C locale to "C", in order to use '.
Definition: General.h:192
Powder pattern class, with an observed pattern and several calculated components to modelize the patt...
void ImportPowderPatternCIF(const CIF &cif)
Import CIF powder pattern data.
unsigned long GetNbPoint() const
Number of points ?
virtual const string & GetClassName() const
Name for this class ("RefinableObj", "Crystal",...).
Definition: Scatterer.cpp:97
long GetNbRefl() const
Return the number of reflections in this experiment.
Abstract Base Class to describe the scattering power of any Scatterer component in a crystal.
virtual void SetBiso(const REAL newB)
Sets the isotropic temperature B factor.
REAL mBiso
Temperature isotropic B factor.
virtual void SetBij(const size_t &i, const size_t &j, const REAL newB)
Sets the anisotropic temperature B factor for (i, j) pair.
The Scattering Power for an Atom.
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
const cctbx::sgtbx::space_group & GetCCTbxSpg() const
Get the underlying cctbx Spacegroup object.
Definition: SpaceGroup.cpp:464
void ChangeSpaceGroup(const string &spgId)
Change the spacegroup.
Definition: UnitCell.cpp:325
const SpaceGroup & GetSpaceGroup() const
Access to the SpaceGroup object.
Definition: UnitCell.cpp:322
virtual void SetName(const string &name)
Name of the object.
virtual const string & GetName() const
Name of the object.
Simple chronometer class, with microsecond precision.
Definition: Chronometer.h:35