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