FOX/ObjCryst++  2022
Crystal.cpp
1 /* ObjCryst++ Object-Oriented Crystallographic Library
2  (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net
3  2000-2001 University of Geneva (Switzerland)
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 /*
20 * source file LibCryst++ Crystal class
21 *
22 */
23 
24 #include <cmath>
25 #include <set>
26 #include <vector>
27 #include <typeinfo>
28 #include <boost/format.hpp>
29 
30 #include "cctbx/sgtbx/space_group.h"
31 
32 #include "ObjCryst/ObjCryst/Crystal.h"
33 #include "ObjCryst/ObjCryst/Molecule.h"
34 #include "ObjCryst/ObjCryst/Atom.h"
35 
36 #include "ObjCryst/Quirks/VFNStreamFormat.h" //simple formatting of integers, REALs..
37 #include "ObjCryst/Quirks/VFNDebug.h"
38 
39 #ifdef __WX__CRYST__
40  #include "ObjCryst/wxCryst/wxCrystal.h"
41 #endif
42 
43 #include <fstream>
44 #include <iomanip>
45 
46 namespace ObjCryst
47 {
48 const RefParType *gpRefParTypeCrystal=0;
49 long NiftyStaticGlobalObjectsInitializer_Crystal::mCount=0;
51 //
52 // CRYSTAL : the crystal (Unit cell, spaceGroup, scatterers)
53 //
55 ObjRegistry<Crystal> gCrystalRegistry("List of all Crystals");
56 
58 mScattererRegistry("List of Crystal Scatterers"),
59 mBumpMergeCost(0.0),mBumpMergeScale(1.0),
60 mDistTableMaxDistance(1.0),
61 mDistTableForInterMolMaxDistance(1.0),
62 mDistMaxMultiplier(2),
63 mScatteringPowerRegistry("List of Crystal ScatteringPowers"),
64 mBondValenceCost(0.0),mBondValenceCostScale(1.0),mDeleteSubObjInDestructor(1),
65 mInterMolDistCostScale(1.0),mInterMolDistCost(0.0),mCostCalcMethod(0),mInterMolDistListNeedsInit(true)
66 {
67  VFN_DEBUG_MESSAGE("Crystal::Crystal()",10)
68  this->InitOptions();
69  this->Init(10,11,12,M_PI/2+.1,M_PI/2+.2,M_PI/2+.3,"P 1","");
70  gCrystalRegistry.Register(*this);
71  gTopRefinableObjRegistry.Register(*this);
73  mClockMaster.AddChild(this->mScattererRegistry.GetRegistryClock());
74  mClockMaster.AddChild(this->mScatteringPowerRegistry.GetRegistryClock());
75 }
76 
77 Crystal::Crystal(const REAL a, const REAL b, const REAL c, const string &SpaceGroupId):
78 mScattererRegistry("List of Crystal Scatterers"),
79 mBumpMergeCost(0.0),mBumpMergeScale(1.0),
80 mDistTableMaxDistance(1.0),
81 mDistTableForInterMolMaxDistance(1.0),
82 mDistMaxMultiplier(2),
83 mScatteringPowerRegistry("List of Crystal ScatteringPowers"),
84 mBondValenceCost(0.0),mBondValenceCostScale(1.0),mDeleteSubObjInDestructor(1),
85 mInterMolDistCostScale(1.0),mInterMolDistCost(0.0),mCostCalcMethod(0),mInterMolDistListNeedsInit(true)
86 {
87  VFN_DEBUG_MESSAGE("Crystal::Crystal(a,b,c,Sg)",10)
88  this->Init(a,b,c,M_PI/2,M_PI/2,M_PI/2,SpaceGroupId,"");
89  this->InitOptions();
90  gCrystalRegistry.Register(*this);
91  gTopRefinableObjRegistry.Register(*this);
93  mClockMaster.AddChild(this->mScattererRegistry.GetRegistryClock());
94  mClockMaster.AddChild(this->mScatteringPowerRegistry.GetRegistryClock());
95 }
96 
97 Crystal::Crystal(const REAL a, const REAL b, const REAL c, const REAL alpha,
98  const REAL beta, const REAL gamma,const string &SpaceGroupId):
99 mScattererRegistry("List of Crystal Scatterers"),
100 mBumpMergeCost(0.0),mBumpMergeScale(1.0),
101 mDistTableMaxDistance(1.0),
102 mDistTableForInterMolMaxDistance(1.0),
103 mDistMaxMultiplier(2),
104 mScatteringPowerRegistry("List of Crystal ScatteringPowers"),
105 mBondValenceCost(0.0),mBondValenceCostScale(1.0),mDeleteSubObjInDestructor(1),
106 mInterMolDistCostScale(1.0),mInterMolDistCost(0.0),mCostCalcMethod(0),mInterMolDistListNeedsInit(true)
107 {
108  VFN_DEBUG_MESSAGE("Crystal::Crystal(a,b,c,alpha,beta,gamma,Sg)",10)
109  this->Init(a,b,c,alpha,beta,gamma,SpaceGroupId,"");
110  this->InitOptions();
111  gCrystalRegistry.Register(*this);
112  gTopRefinableObjRegistry.Register(*this);
114  mClockMaster.AddChild(this->mScattererRegistry.GetRegistryClock());
115  mClockMaster.AddChild(this->mScatteringPowerRegistry.GetRegistryClock());
116 }
117 
119 mScattererRegistry("List of Crystal Scatterers"),
120 mBumpMergeCost(0.0),mBumpMergeScale(1.0),
121 mDistTableMaxDistance(1.0),
122 mDistTableForInterMolMaxDistance(1.0),
123 mDistMaxMultiplier(2),
124 mScatteringPowerRegistry("List of Crystal ScatteringPowers"),
125 mBondValenceCost(0.0),mBondValenceCostScale(1.0),mDeleteSubObjInDestructor(1),
126 mInterMolDistCostScale(1.0),mInterMolDistCost(0.0),mCostCalcMethod(0),mInterMolDistListNeedsInit(true)
127 {
128  VFN_DEBUG_MESSAGE("Crystal::Crystal()",10)
129  // Only create a default crystal, then copy old using XML
130  this->InitOptions();
131  this->Init(10,11,12,M_PI/2+.1,M_PI/2+.2,M_PI/2+.3,"P 1","");
132  gCrystalRegistry.Register(*this);
133  gTopRefinableObjRegistry.Register(*this);
135  mClockMaster.AddChild(mClockScattererList); // Is that a duplicate with the next line ?
136  mClockMaster.AddChild(this->mScattererRegistry.GetRegistryClock());
137  mClockMaster.AddChild(this->mScatteringPowerRegistry.GetRegistryClock());
138 
139  stringstream sst;
140  old.XMLOutput(sst);
141  XMLCrystTag tag(sst);
142  this->XMLInput(sst,tag);
143 }
144 
146 {
147  VFN_DEBUG_ENTRY("Crystal::~Crystal()",5)
148  for(long i=0;i<mScattererRegistry.GetNb();i++)
149  {
150  VFN_DEBUG_MESSAGE("Crystal::~Crystal(&scatt):1:"<<i,5)
151  this->RemoveSubRefObj(mScattererRegistry.GetObj(i));
152  mScattererRegistry.GetObj(i).DeRegisterClient(*this);
153  }
154  if( mDeleteSubObjInDestructor )
155  {
156  mScattererRegistry.DeleteAll();
157  }
158  else
159  {
160  mScattererRegistry.DeRegisterAll();
161  }
162  for(long i=0;i<mScatteringPowerRegistry.GetNb();i++)
163  {
164  VFN_DEBUG_MESSAGE("Crystal::~Crystal(&scatt):2:"<<i,5)
165  this->RemoveSubRefObj(mScatteringPowerRegistry.GetObj(i));
166  mScatteringPowerRegistry.GetObj(i).DeRegisterClient(*this);
167  // :TODO: check if it is not used by another Crystal (forbidden!)
168  }
169  if( mDeleteSubObjInDestructor )
170  {
171  mScatteringPowerRegistry.DeleteAll();
172  }
173  else
174  {
175  mScatteringPowerRegistry.DeRegisterAll();
176  }
177  gCrystalRegistry.DeRegister(*this);
178  gTopRefinableObjRegistry.DeRegister(*this);
179  VFN_DEBUG_EXIT("Crystal::~Crystal()",5)
180 }
181 
182 const string& Crystal::GetClassName() const
183 {
184  const static string className="Crystal";
185  return className;
186 }
187 
189 {
190  VFN_DEBUG_ENTRY("Crystal::AddScatterer(&scatt)",5)
191  mScattererRegistry.Register(*scatt);
192  scatt->RegisterClient(*this);
193  this->AddSubRefObj(*scatt);
194  scatt->SetCrystal(*this);
196  VFN_DEBUG_EXIT("Crystal::AddScatterer(&scatt):Finished",5)
197 }
198 
199 void Crystal::RemoveScatterer(Scatterer *scatt, const bool del)
200 {
201  VFN_DEBUG_MESSAGE("Crystal::RemoveScatterer(&scatt)",5)
202  mScattererRegistry.DeRegister(*scatt);
203  scatt->DeRegisterClient(*this);
204  this->RemoveSubRefObj(*scatt);
205  if(del) delete scatt;
207  VFN_DEBUG_MESSAGE("Crystal::RemoveScatterer(&scatt):Finished",5)
208 }
209 
210 long Crystal::GetNbScatterer()const {return mScattererRegistry.GetNb();}
211 
212 Scatterer& Crystal::GetScatt(const string &scattName)
213 {
214  return mScattererRegistry.GetObj(scattName);
215 }
216 
217 const Scatterer& Crystal::GetScatt(const string &scattName) const
218 {
219  return mScattererRegistry.GetObj(scattName);
220 }
221 
222 Scatterer& Crystal::GetScatt(const long scattIndex)
223 {
224  return mScattererRegistry.GetObj(scattIndex);
225 }
226 
227 const Scatterer& Crystal::GetScatt(const long scattIndex) const
228 {
229  return mScattererRegistry.GetObj(scattIndex);
230 }
231 
233 
235 
237 {return mScatteringPowerRegistry;}
239 {return mScatteringPowerRegistry;}
240 
242 {
243  mScatteringPowerRegistry.Register(*scattPow);
244  scattPow->RegisterClient(*this);//:TODO: Should register as (unique) 'owner'.
245  this->AddSubRefObj(*scattPow);
246  mClockMaster.AddChild(scattPow->GetClockMaster());
249 }
250 
251 void Crystal::RemoveScatteringPower(ScatteringPower *scattPow, const bool del)
252 {
253  VFN_DEBUG_ENTRY("Crystal::RemoveScatteringPower()",2)
254  mScatteringPowerRegistry.DeRegister(*scattPow);
255  this->RemoveSubRefObj(*scattPow);
259  if(del) delete scattPow;
260 
261  for(Crystal::VBumpMergePar::iterator pos=mvBumpMergePar.begin();pos!=mvBumpMergePar.end();)
262  {
263  if((pos->first.first==scattPow)||(pos->first.second==scattPow))
264  {
265  mvBumpMergePar.erase(pos++);
267  }
268  else ++pos;// See Josuttis Std C++ Lib p.205 for safe method
269  }
270 
271  for(map<pair<const ScatteringPower*,const ScatteringPower*>, REAL>::iterator
272  pos=mvBondValenceRo.begin();pos!=mvBondValenceRo.end();)
273  {
274  if((pos->first.first==scattPow)||(pos->first.second==scattPow))
275  {
276  mvBondValenceRo.erase(pos++);
278  }
279  else ++pos;// See Josuttis Std C++ Lib p.205 for safe method
280  }
281  VFN_DEBUG_EXIT("Crystal::RemoveScatteringPower()",2)
282 }
283 
285 {
286  return mScatteringPowerRegistry.GetObj(name);
287 }
288 
289 const ScatteringPower& Crystal::GetScatteringPower(const string &name)const
290 {
291  return mScatteringPowerRegistry.GetObj(name);
292 }
293 
296 
297 
299 {
301  bool update=false;
302  if(mClockScattCompList<this->GetClockLatticePar()) update=true;
303  if(mClockScattCompList<this->GetClockScattererList()) update=true;
304  if(update==false)
305  for(long i=0;i<mScattererRegistry.GetNb();i++)
306  {
307  //mClockScattCompList.Print();
308  //this->GetScatt(i).GetClockScatterer().Print();
309  if(mClockScattCompList<this->GetScatt(i).GetClockScatterer()) {update=true;break;}
310  }
311  if(true==update)
312  {
313  VFN_DEBUG_MESSAGE("Crystal::GetScatteringComponentList()",2)
314  TAU_PROFILE("Crystal::GetScatteringComponentList()","ScattCompList& ()",TAU_DEFAULT);
316  for(long i=0;i<mScattererRegistry.GetNb();i++)
317  {
318  //this->GetScatt(i).GetScatteringComponentList().Print();
320  }
321 
322  //:KLUDGE: this must be *before* calling CalcDynPopCorr() to avoid an infinite loop..
324 
325  if(1==mUseDynPopCorr.GetChoice())
326  this->CalcDynPopCorr(1.,.5); else this->ResetDynPopCorr();
327  VFN_DEBUG_MESSAGE("Crystal::GetScatteringComponentList():End",2)
328  }
329  #ifdef __DEBUG__
330  if(gVFNDebugMessageLevel<2) mScattCompList.Print();
331  #endif
332  return mScattCompList;
333 }
334 
336 {
337  return mClockScattCompList;
338 }
339 
340 void Crystal::Print(ostream &os)const
341 {
342  VFN_DEBUG_MESSAGE("Crystal::Print()",5)
343  this->UnitCell::Print(os);
344 
346  this->CalcBondValenceSum();
347 
348  os << "List of scattering components (atoms): " << mScattCompList.GetNbComponent() << endl ;
349 
350  long k=0;
351  std::map<long, REAL>::const_iterator posBV;
352  for(int i=0;i<mScattererRegistry.GetNb();i++)
353  {
354  //mpScatterrer[i]->Print();
356  for(int j=0;j<list.GetNbComponent();j++)
357  {
358  os << FormatString(this->GetScatt(i).GetComponentName(j),16) << " at : "
359  << FormatFloat(list(j).mX,7,4)
360  << FormatFloat(list(j).mY,7,4)
361  << FormatFloat(list(j).mZ,7,4)
362  << ", Occup=" << FormatFloat(list(j).mOccupancy,6,4)
363  << " * " << FormatFloat(mScattCompList(k).mDynPopCorr,6,4);
364  // Check for dummy atoms
365  if( NULL != list(j).mpScattPow )
366  {
367  os << ", ScattPow:" << FormatString(list(j).mpScattPow->GetName(),16)
368  << ", Biso=" << FormatFloat(list(j).mpScattPow->GetBiso());
369  }
370  else
371  {
372  os << ", ScattPow: dummy";
373  }
374  // Check for dummy atoms
375  if( NULL != this->mScattCompList(k).mpScattPow )
376  {
377  posBV=this->mvBondValenceCalc.find(k);
378  if(posBV!=this->mvBondValenceCalc.end())
379  os <<": Valence="<<posBV->second<<" (expected="
380  <<this->mScattCompList(k).mpScattPow->GetFormalCharge()<<")";
381  }
382  os << endl;
383  k++;
384  }
385  }
386  os <<endl
387  << "Occupancy = occ * dyn, where:"<<endl
388  << " - occ is the 'real' occupancy"<< endl
389  << " - dyn is the dynamical occupancy correction, indicating either"<< endl
390  << " an atom on a special position, or several identical atoms "<< endl
391  << " overlapping (dyn=0.5 -> atom on a symetry plane / 2fold axis.."<< endl
392  << " -> OR 2 atoms strictly overlapping)"<< endl
393  <<endl;
394  REAL nbAtoms=0;
395  const long genMult=this->GetSpaceGroup().GetNbSymmetrics();
396  for(int i=0;i<mScattCompList.GetNbComponent();i++)
397  nbAtoms += genMult * mScattCompList(i).mOccupancy * mScattCompList(i).mDynPopCorr;
398  os << " Total number of components (atoms) in one unit cell : " << nbAtoms<<endl
399  << " Chemical formula: "<< this->GetFormula() << endl
400  << " Weight: "<< this->GetWeight()<< " g/mol" << endl;
401 
402  VFN_DEBUG_MESSAGE("Crystal::Print():End",5)
403 }
404 
405 std::string Crystal::GetFormula() const
406 {
408  if(mScattCompList.GetNbComponent() == 0) return "";
409  std::map<std::string,float> velts;
410  for(unsigned int i=0; i<mScattCompList.GetNbComponent(); ++i)
411  {
412  const ScatteringComponent* psi = &mScattCompList(i);
413  if(psi->mpScattPow == 0) continue;
414  if(psi->mpScattPow->GetClassName().compare("ScatteringPowerAtom")!=0) continue;
415  const ScatteringPowerAtom *pat=dynamic_cast<const ScatteringPowerAtom*>(psi->mpScattPow);
416  string p=pat->GetSymbol();
417  if(velts.count(p)==0)
418  velts[p] = psi->mOccupancy * psi->mDynPopCorr ;
419  else velts[p] += psi->mOccupancy * psi->mDynPopCorr;
420  }
421  stringstream s;
422  s<<std::setprecision(2);
423  for(std::map<std::string,float>::const_iterator pos=velts.begin();pos!=velts.end();++pos)
424  {
425  if(pos!=velts.begin()) s<<" ";
426  float nb=pos->second;
427  if(abs(round(nb)-nb)<0.005)
428  {
429  if(int(round(nb))==1) s<<pos->first;
430  else s<<pos->first<<int(round(nb));
431  }
432  else s<<pos->first<<nb;
433  }
434  return s.str();
435 }
436 
437 
438 REAL Crystal::GetWeight() const
439 {
441  if(mScattCompList.GetNbComponent() == 0) return 0;
442  REAL w=0;
443  for(unsigned int i=0; i<mScattCompList.GetNbComponent(); ++i)
444  {
445  const ScatteringComponent* psi = &mScattCompList(i);
446  if(psi->mpScattPow == 0) continue;
447  if(psi->mpScattPow->GetClassName().compare("ScatteringPowerAtom")!=0) continue;
448  const ScatteringPowerAtom *pat=dynamic_cast<const ScatteringPowerAtom*>(psi->mpScattPow);
449  w += pat->GetAtomicWeight() * psi->mOccupancy * psi->mDynPopCorr ;
450  }
451  return w;
452 }
453 
454 
455 CrystMatrix_REAL Crystal::GetMinDistanceTable(const REAL minDistance) const
456 {
457  VFN_DEBUG_MESSAGE("Crystal::MinDistanceTable()",5)
458  this->CalcDistTable(true);
459  const long nbComponent=mScattCompList.GetNbComponent();
460 
461  CrystMatrix_REAL minDistTable(nbComponent,nbComponent);
462  REAL dist;
463  REAL tmp;
464  REAL min=minDistance*minDistance;
465  if(minDistance<0) min = -1.;// no min distance
466  minDistTable=10000.;
467  for(int i=0;i<nbComponent;i++)
468  {
469  //VFN_DEBUG_MESSAGE("Crystal::MinDistanceTable():comp="<<i,10)
470  std::vector<Crystal::Neighbour>::const_iterator pos;
471  for(pos=mvDistTableSq[i].mvNeighbour.begin();
472  pos<mvDistTableSq[i].mvNeighbour.end();pos++)
473  {
474  tmp=pos->mDist2;
475  dist=minDistTable(i,pos->mNeighbourIndex);
476  if( (tmp<dist)
477  && ((tmp>min) || ( (mvDistTableSq[i].mIndex !=pos->mNeighbourIndex)
478  &&(mvDistTableSq[i].mUniquePosSymmetryIndex
479  !=pos->mNeighbourSymmetryIndex))))
480  minDistTable(i,pos->mNeighbourIndex)=tmp;
481  }
482  }
483  for(int i=0;i<nbComponent;i++)
484  {
485  for(int j=0;j<=i;j++)
486  {
487  if(9999.>minDistTable(i,j)) minDistTable(i,j)=sqrt(minDistTable(i,j));
488  else minDistTable(i,j)=-1;
489  minDistTable(j,i)=minDistTable(i,j);
490  }
491  }
492  VFN_DEBUG_MESSAGE("Crystal::MinDistanceTable():End",3)
493  return minDistTable;
494 }
495 
496 void Crystal::PrintMinDistanceTable(const REAL minDistance,ostream &os) const
497 {
498  VFN_DEBUG_MESSAGE("Crystal::PrintMinDistanceTable()",5)
499  CrystMatrix_REAL minDistTable;
500  minDistTable=this->GetMinDistanceTable(minDistance);
501  VFN_DEBUG_MESSAGE("Crystal::PrintMinDistanceTable():0",5)
502  os << "Table of minimal distances between all components (atoms)"<<endl;
503  os << " ";
504  for(long i=0;i<mScattererRegistry.GetNb();i++)
505  {
506  VFN_DEBUG_MESSAGE("Crystal::PrintMinDistanceTable()1:Scatt:"<<i,3)
507  for(long j=0;j<this->GetScatt(i).GetNbComponent();j++)
508  os << FormatString(this->GetScatt(i).GetComponentName(j),7);
509  }
510  os << endl;
511  long l=0;
512  const long nbComponent=mScattCompList.GetNbComponent();
513  for(long i=0;i<mScattererRegistry.GetNb();i++)
514  for(long j=0;j<this->GetScatt(i).GetNbComponent();j++)
515  {
516  VFN_DEBUG_MESSAGE("Crystal::PrintMinDistanceTable()2:Scatt,comp:"<<i<<","<<j,3)
517  os << FormatString(this->GetScatt(i).GetComponentName(j),14);
518  for(long k=0;k<nbComponent;k++)
519  {
520  if(minDistTable(l,k)>0) os << FormatFloat(minDistTable(l,k),6,3) ;
521  else os<<" >10 ";
522  }
523  os << endl;
524  l++;
525  }
526  VFN_DEBUG_MESSAGE("Crystal::PrintMinDistanceTable():End",3)
527 }
528 
529 ostream& Crystal::POVRayDescription(ostream &os,const CrystalPOVRayOptions &options)const
530 {
531  VFN_DEBUG_MESSAGE("Crystal::POVRayDescription(os,bool)",5)
532  os <<"/////////////////////// MACROS////////////////////"<<endl;
533 
534  os << "#macro ObjCrystAtom(atomx,atomy,atomz,atomr,atomc,occ,atten)"
535  << " sphere"<<endl
536  << " { <atomx,atomy,atomz>,atomr"<<endl
537  << " finish {ambient 0.5*occ*atten diffuse 0.4*occ*atten phong occ*atten specular 0.2*occ*atten "
538  << "roughness 0.02 metallic reflection 0.0}"<<endl
539  << " pigment { colour atomc transmit (1-occ*atten)}"<<endl
540  << " no_shadow"<<endl
541  << " }"<<endl
542  << "#end"<<endl<<endl;
543 
544  os << "#macro ObjCrystBond(x1,y1,z1,x2,y2,z2,bondradius,bondColour,occ,atten)"<<endl
545  << " cylinder"<<endl
546  << " { <x1,y1,z1>,"<<endl
547  << " <x2,y2,z2>,"<<endl
548  << " bondradius"<<endl
549  << " finish {ambient 0.5*occ*atten diffuse 0.4*occ*atten phong occ*atten specular 0.2*occ*atten "
550  << "roughness 0.02 metallic reflection 0.0}"<<endl
551  << " pigment { colour bondColour transmit (1-occ*atten)}"<<endl
552  << " no_shadow"<<endl
553  << " }"<<endl
554  << "#end"<<endl<<endl;
555 
556  os <<"//////////// Crystal Unit Cell /////////////////" <<endl;
557  REAL x=1,y=1,z=1;
558  this->FractionalToOrthonormalCoords(x,y,z);
559  os << " //box{ <0,0,0>, <"<< x << "," << y << "," << z << ">" <<endl;
560  os << " // pigment {colour rgbf<1,1,1,0.9>}" << endl;
561  os << " // hollow" << endl;
562  os << " //}" <<endl<<endl;
563 
564  #define UNITCELL_EDGE(X0,Y0,Z0,X1,Y1,Z1)\
565  {\
566  REAL x0=X0,y0=Y0,z0=Z0,x1=X1,y1=Y1,z1=Z1;\
567  this->FractionalToOrthonormalCoords(x0,y0,z0);\
568  this->FractionalToOrthonormalCoords(x1,y1,z1);\
569  os << " ObjCrystBond("\
570  <<x0<<","<<y0<<","<<z0<< ","\
571  <<x1<<","<<y1<<","<<z1<< ","\
572  << "0.02,rgb<1.0,1.0,1.0>,1.0,1.0)"<<endl;\
573  }
574 
575  UNITCELL_EDGE(0,0,0,1,0,0)
576  UNITCELL_EDGE(0,0,0,0,1,0)
577  UNITCELL_EDGE(0,0,0,0,0,1)
578 
579  UNITCELL_EDGE(1,1,1,0,1,1)
580  UNITCELL_EDGE(1,1,1,1,0,1)
581  UNITCELL_EDGE(1,1,1,1,1,0)
582 
583  UNITCELL_EDGE(1,0,0,1,1,0)
584  UNITCELL_EDGE(1,0,0,1,0,1)
585 
586  UNITCELL_EDGE(0,1,0,1,1,0)
587  UNITCELL_EDGE(0,1,0,0,1,1)
588 
589  UNITCELL_EDGE(0,0,1,1,0,1)
590  UNITCELL_EDGE(0,0,1,0,1,1)
591 
592  os <<endl<<"/////////////// GLOBAL DECLARATIONS FOR ATOMS & BONDS ///////"<<endl;
593  os << "// Atom colours"<<endl;
594  for(int i=0;i<mScatteringPowerRegistry.GetNb();i++)
595  {
596  const float r=mScatteringPowerRegistry.GetObj(i).GetColourRGB()[0];
597  const float g=mScatteringPowerRegistry.GetObj(i).GetColourRGB()[1];
598  const float b=mScatteringPowerRegistry.GetObj(i).GetColourRGB()[2];
599  os << " #declare colour_"<< mScatteringPowerRegistry.GetObj(i).GetName()
600  <<"= rgb <"<< r<<","<<g<<","<<b<<">;"<< endl;
601  }
602  os << "// Bond colours"<<endl
603  << " #declare colour_freebond = rgb <0.7,0.7,0.7>;"<< endl
604  << " #declare colour_nonfreebond= rgb <0.3,0.3,0.3>;"<< endl;
605 
606  os<<endl;
607  os << "/////////////// SCATTERERS ///////"<<endl;
608  for(int i=0;i<mScattererRegistry.GetNb();i++)
609  this->GetScatt(i).POVRayDescription(os,options) ;
610  return os;
611 }
612 
613 #ifdef OBJCRYST_GL
614 void Crystal::GLInitDisplayList(const bool onlyIndependentAtoms,
615  const REAL xMin,const REAL xMax,
616  const REAL yMin,const REAL yMax,
617  const REAL zMin,const REAL zMax,
618  const bool displayNames,
619  const bool hideHydrogens,
620  const REAL fadeDistance,
621  const bool fullMoleculeInLimits)const
622 {
623  VFN_DEBUG_ENTRY("Crystal::GLInitDisplayList()",5)
624  REAL en=1;// if -1, display enantiomeric structure
625  if(mDisplayEnantiomer.GetChoice()==1) en=-1;
626 
627  //Center of displayed unit
628  REAL xc=(xMin+xMax)/2.;
629  REAL yc=(yMin+yMax)/2.;
630  REAL zc=(zMin+zMax)/2.;
631  if(false==displayNames)
632  {
633  //Describe Unit Cell
634  REAL x111= 1.;
635  REAL y111= 1.;
636  REAL z111= 1.;
637  this->FractionalToOrthonormalCoords(x111,y111,z111);
638  REAL x110= 1.;
639  REAL y110= 1.;
640  REAL z110= 0.;
641  this->FractionalToOrthonormalCoords(x110,y110,z110);
642  REAL x101= 1.;
643  REAL y101= 0.;
644  REAL z101= 1.;
645  this->FractionalToOrthonormalCoords(x101,y101,z101);
646  REAL x100= 1.;
647  REAL y100= 0.;
648  REAL z100= 0.;
649  this->FractionalToOrthonormalCoords(x100,y100,z100);
650  REAL x011= 0.;
651  REAL y011= 1.;
652  REAL z011= 1.;
653  this->FractionalToOrthonormalCoords(x011,y011,z011);
654  REAL x010= 0.;
655  REAL y010= 1.;
656  REAL z010= 0.;
657  this->FractionalToOrthonormalCoords(x010,y010,z010);
658  REAL x001= 0.;
659  REAL y001= 0.;
660  REAL z001= 1.;
661  this->FractionalToOrthonormalCoords(x001,y001,z001);
662  REAL x000= 0.;
663  REAL y000= 0.;
664  REAL z000= 0.;
665  this->FractionalToOrthonormalCoords(x000,y000,z000);
666  REAL xM= 0.5;
667  REAL yM= 0.5;
668  REAL zM= 0.5;
669  this->FractionalToOrthonormalCoords(xM,yM,zM);
670  xM*=2;yM*=2;zM*=2;
671  glPushMatrix();
672  //Add Axis & axis names
673  const GLfloat colour0 [] = {0.00, 0.00, 0.00, 0.00};
674  const GLfloat colour1 [] = {0.50, 0.50, 0.50, 1.00};
675  const GLfloat colour2 [] = {1.00, 1.00, 1.00, 1.00};
676  glMaterialfv(GL_FRONT, GL_AMBIENT, colour1);
677  glMaterialfv(GL_FRONT, GL_DIFFUSE, colour0);
678  glMaterialfv(GL_FRONT, GL_SPECULAR, colour0);
679  glMaterialfv(GL_FRONT, GL_EMISSION, colour1);
680  glMaterialfv(GL_FRONT, GL_SHININESS, colour0);
681  REAL x,y,z;
682  x=1.2-xc;y=-yc;z=-zc;
683  this->FractionalToOrthonormalCoords(x,y,z);
684  glRasterPos3f(en*x,y,z);
685  crystGLPrint("a");
686 
687  x=-xc;y=1.2-yc;z=-zc;
688  this->FractionalToOrthonormalCoords(x,y,z);
689  glRasterPos3f(en*x,y,z);
690  crystGLPrint("b");
691 
692  x=-xc;y=-yc;z=1.2-zc;
693  this->FractionalToOrthonormalCoords(x,y,z);
694  glRasterPos3f(en*x,y,z);
695  crystGLPrint("c");
696  // Cell
697  glMaterialfv(GL_FRONT, GL_AMBIENT, colour1);
698  glMaterialfv(GL_FRONT, GL_DIFFUSE, colour1);
699  glMaterialfv(GL_FRONT, GL_SPECULAR, colour1);
700  glMaterialfv(GL_FRONT, GL_EMISSION, colour0);
701  glMaterialfv(GL_FRONT, GL_SHININESS, colour0);
702  this->FractionalToOrthonormalCoords(xc,yc,zc);
703  glTranslatef(-xc*en, -yc, -zc);
704  glBegin(GL_LINES);
705  //top
706  glNormal3f((x110+x010-xM)*en,y110+y010-yM,z110+z010-zM);
707  glVertex3f( x110*en, y110, z110);
708  glVertex3f( x010*en, y010, z010);
709 
710  glNormal3f((x011+x010-xM)*en,y011+y010-yM,z011+z010-zM);
711  glVertex3f( x010*en, y010, z010);
712  glVertex3f( x011*en, y011, z011);
713 
714  glNormal3f((x011+x111-xM)*en,y011+y111-yM,z011+z111-zM);
715  glVertex3f( x011*en, y011, z011);
716  glVertex3f( x111*en, y111, z111);
717 
718  glNormal3f((x110+x111-xM)*en,y110+y111-yM,z110+z111-zM);
719  glVertex3f( x111*en, y111, z111);
720  glVertex3f( x110*en, y110, z110);
721  //bottom
722  glNormal3f((x101+x001-xM)*en,y101+y001-yM,z101+z001-zM);
723  glVertex3f( x101*en, y101, z101);
724  glVertex3f( x001*en, y001, z001);
725 
726  glNormal3f((x000+x001-xM)*en,y000+y001-yM,z000+z001-zM);
727  glVertex3f( x001*en, y001, z001);
728  glVertex3f( x000*en, y000, z000);
729 
730  glNormal3f((x000+x100-xM)*en,y000+y100-yM,z000+z100-zM);
731  glVertex3f( x000*en, y000, z000);
732  glVertex3f( x100*en, y100, z100);
733 
734  glNormal3f((x101+x100-xM)*en,y101+y100-yM,z101+z100-zM);
735  glVertex3f( x100*en, y100, z100);
736  glVertex3f( x101*en, y101, z101);
737  //sides
738  glNormal3f((x101+x111-xM)*en,y101+y111-yM,z101+z111-zM);
739  glVertex3f( x101*en, y101, z101);
740  glVertex3f( x111*en, y111, z111);
741 
742  glNormal3f((x001+x011-xM)*en,y001+y011-yM,z001+z011-zM);
743  glVertex3f( x001*en, y001, z001);
744  glVertex3f( x011*en, y011, z011);
745 
746  glNormal3f((x000+x010-xM)*en,y000+y010-yM,z000+z010-zM);
747  glVertex3f( x000*en, y000, z000);
748  glVertex3f( x010*en, y010, z010);
749 
750  glNormal3f((x100+x110-xM)*en,y100+y110-yM,z100+z110-zM);
751  glVertex3f( x100*en, y100, z100);
752  glVertex3f( x110*en, y110, z110);
753  glEnd();
754  glPopMatrix();
755  }
756 
757  //Describe all Scatterers
758  VFN_DEBUG_MESSAGE("Crystal::GLView(bool):Scatterers...",5)
759  glPushMatrix();
760  if(displayNames) this->FractionalToOrthonormalCoords(xc,yc,zc);
761  glTranslatef(-xc*en, -yc, -zc);
762  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
763  {
764  bool displayEnantiomer=false;
765  if(mDisplayEnantiomer.GetChoice()==1) displayEnantiomer=true;
766  for(int i=0;i<mScattererRegistry.GetNb();i++)
767  this->GetScatt(i).GLInitDisplayList(onlyIndependentAtoms,
768  xMin,xMax,yMin,yMax,zMin,zMax,
769  displayEnantiomer,displayNames,hideHydrogens,fadeDistance,fullMoleculeInLimits);
770  }
771  glPopMatrix();
772  VFN_DEBUG_EXIT("Crystal::GLInitDisplayList(bool)",5)
773 }
774 #endif // OBJCRYST_GL
775 
776 void Crystal::CalcDynPopCorr(const REAL overlapDist, const REAL mergeDist) const
777 {
778  VFN_DEBUG_ENTRY("Crystal::CalcDynPopCorr(REAL)",4)
779  TAU_PROFILE("Crystal::CalcDynPopCorr()","void (REAL)",TAU_DEFAULT);
780 
781  this->CalcDistTable(true);
783 
784  const long nbComponent=mScattCompList.GetNbComponent();
785  const int nbSymmetrics=this->GetSpaceGroup().GetNbSymmetrics();
786  CrystVector_REAL neighborsDist(nbComponent*nbSymmetrics);
787  long nbNeighbors=0;
788  REAL corr;
789 
790  int atomicNumber;
791  const REAL overlapDistSq=overlapDist*overlapDist;
792  REAL dist;
793  for(long i=0;i<nbComponent;i++)
794  {
795  VFN_DEBUG_MESSAGE("Crystal::CalcDynPopCorr(): Component:"<<i,0)
796  if(0==mScattCompList(i).mpScattPow)
797  {
798  mScattCompList(i).mDynPopCorr=1.;
799  continue;
800  }
801  atomicNumber=mScattCompList(i).mpScattPow->GetDynPopCorrIndex();
802  nbNeighbors=0;
803  std::vector<Crystal::Neighbour>::const_iterator pos;
804  for(pos=mvDistTableSq[i].mvNeighbour.begin();
805  pos<mvDistTableSq[i].mvNeighbour.end();pos++)
806  {
807  VFN_DEBUG_MESSAGE("Crystal::CalcDynPopCorr(): Component:"<<i<<"Neighbour:"<<pos->mNeighbourIndex,0)
808  if(0==mScattCompList(pos->mNeighbourIndex).mpScattPow)continue;
809  if(atomicNumber==mScattCompList(pos->mNeighbourIndex).mpScattPow->GetDynPopCorrIndex())
810  {
811  if(overlapDistSq > pos->mDist2)
812  {
813  //resizing can be necessary if the unit cell is small, so that an atom two unit cells away is
814  //still considered a neighbor...
815  if(nbNeighbors==neighborsDist.numElements()) neighborsDist.resizeAndPreserve(nbNeighbors+20);
816  neighborsDist(nbNeighbors++)=sqrt(pos->mDist2);
817  }
818  }
819  }
820  corr=0.;
821  for(long j=0;j<nbNeighbors;j++)
822  {
823  dist=neighborsDist(j)-mergeDist;
824  if(dist<0.) dist=0.;
825  corr += fabs((overlapDist-dist-mergeDist)/(overlapDist-mergeDist));
826  }
827  mScattCompList(i).mDynPopCorr=1./(1+corr);
828  }
830  VFN_DEBUG_EXIT("Crystal::CalcDynPopCorr(REAL):End.",4)
831 }
832 
834 {
835  //:NOTE: This is useless !!
837  const long nbComponent=mScattCompList.GetNbComponent();
838  for(long i=0;i<nbComponent;i++) mScattCompList(i).mDynPopCorr=1.;
839 }
840 
841 REAL Crystal::GetDynPopCorr(const Scatterer* pscatt, unsigned int component)const
842 {
843  if(this->GetUseDynPopCorr()==0) return 1.0;
845  unsigned int j=0;
846  for(long i=0;i<mScattererRegistry.GetNb();i++)
847  {
848  if(pscatt==&(this->GetScatt(i)))
849  {
850  return mScattCompList(j+component).mDynPopCorr;
851  }
853  }
854  // Something is wrong if we got here !
855  throw ObjCrystException("Crystal::GetDynPopCorr(): did not find this scatterer !");
856  return 1.0;
857 }
858 
859 void Crystal::SetUseDynPopCorr(const int b)
860 {
861  VFN_DEBUG_MESSAGE("Crystal::SetUseDynPopCorr()",1)
862  mUseDynPopCorr.SetChoice(b);
864 }
865 
867 {
868  return mUseDynPopCorr.GetChoice();
869 }
870 
871 int Crystal::FindScatterer(const string &scattName)const
872 {
873  VFN_DEBUG_MESSAGE("Crystal::FindScatterer(name)",0)
874  for(int i=0;i<this->GetNbScatterer();i++)
875  {
876  if( mScattererRegistry.GetObj(i).GetName() == scattName) return i;
877  }
878  throw ObjCrystException("Crystal::FindScatterer(string)\
879  Cannot find this scatterer:"+scattName);
880 }
881 vector<int> Crystal::FindScatterersInComponentList(const string &scattName)const
882 {
883  vector<int> res;
884  for(int i=0;i<mNamedScattCompList.size();i++) {
885  if(mNamedScattCompList[i].mName.compare(scattName)==0) {
886  res.push_back(i);
887  }
888  }
889  return res;
890 }
891 bool Crystal::isScattererInInterMolDistList(string &scattName) const
892 {
893  for(long i=0;i<mInterMolDistList.size();i++) {
894  for(long j=0;j<mInterMolDistList[i].mAt1.size();j++) {
895  if(mInterMolDistList[i].mAt1[j].compare(scattName)==0) {
896  return true;
897  }
898  }
899  for(long j=0;j<mInterMolDistList[i].mAt2.size();j++) {
900  if(mInterMolDistList[i].mAt2[j].compare(scattName)==0) {
901  return true;
902  }
903  }
904  }
905  return false;
906 }
907 bool Crystal::isScattererInInterMolDistListAt1(string &scattName) const
908 {
909  for(long i=0;i<mInterMolDistList.size();i++) {
910  for(long j=0;j<mInterMolDistList[i].mAt1.size();j++) {
911  if(mInterMolDistList[i].mAt1[j].compare(scattName)==0) {
912  return true;
913  }
914  }
915  }
916  return false;
917 }
918 bool Crystal::isScattererInInterMolDistListAt2(string &scattName) const
919 {
920  for(long i=0;i<mInterMolDistList.size();i++) {
921  for(long j=0;j<mInterMolDistList[i].mAt2.size();j++) {
922  if(mInterMolDistList[i].mAt2[j].compare(scattName)==0) {
923  return true;
924  }
925  }
926  }
927  return false;
928 }
929 
930 Crystal::BumpMergePar::BumpMergePar():
931  mDist2(1.),mCanOverlap(false){}
932 
933 Crystal::BumpMergePar::BumpMergePar(const REAL dist, const bool canOverlap):
934  mDist2(dist*dist),mCanOverlap(canOverlap){}
935 
936 
937 
939 {
940  if(mvBumpMergePar.size()==0) return 0;
941  if(mBumpMergeScale<1e-5) return 0;
942  this->CalcDistTable(true);
943  VFN_DEBUG_ENTRY("Crystal::GetBumpMergeCost()",4)
946  TAU_PROFILE("Crystal::GetBumpMergeCost()","REAL (REAL)",TAU_DEFAULT);
947 
948  mBumpMergeCost=0;
949 
950  std::vector<NeighbourHood>::const_iterator pos;
951  std::vector<Crystal::Neighbour>::const_iterator neigh;
952  REAL tmp;
953  const ScatteringPower *i1,*i2;
954  VBumpMergePar::const_iterator par;
955  for(pos=mvDistTableSq.begin();pos<mvDistTableSq.end();pos++)
956  {
957  i1=mScattCompList(pos->mIndex).mpScattPow;
958  for(neigh=pos->mvNeighbour.begin();neigh<pos->mvNeighbour.end();neigh++)
959  {
960  i2=mScattCompList(neigh->mNeighbourIndex).mpScattPow;
961  if(i1<i2) par=mvBumpMergePar.find(std::make_pair(i1,i2));
962  else par=mvBumpMergePar.find(std::make_pair(i2,i1));
963  if(par==mvBumpMergePar.end()) continue;
964  if(neigh->mDist2 > par->second.mDist2) continue;
965  if(true==par->second.mCanOverlap)
966  tmp = 0.5*sin(M_PI*(1.-sqrt(neigh->mDist2/par->second.mDist2)))/0.1;
967  else
968  tmp = tan(M_PI*0.49999*(1.-sqrt(neigh->mDist2/par->second.mDist2)))/0.1;
969  mBumpMergeCost += tmp*tmp;
970  }
971  }
974  VFN_DEBUG_EXIT("Crystal::GetBumpMergeCost():"<<mBumpMergeCost,4)
976 }
977 
979  const ScatteringPower &scatt2,const REAL dist)
980 {
981  VFN_DEBUG_MESSAGE("Crystal::SetBumpMergeDistance()",5)
982  if(&scatt1 == &scatt2) this->SetBumpMergeDistance(scatt1,scatt2,dist,true) ;
983  else this->SetBumpMergeDistance(scatt1,scatt2,dist,false);
984 }
985 
987  const ScatteringPower &scatt2,const REAL dist,
988  const bool allowMerge)
989 {
990  VFN_DEBUG_MESSAGE("Crystal::SetBumpMergeDistance("<<scatt1.GetName()<<","<<scatt2.GetName()<<")="<<dist<<","<<allowMerge,3)
991  if(&scatt1 < &scatt2)
992  mvBumpMergePar[std::make_pair(&scatt1,&scatt2)]=BumpMergePar(dist,allowMerge);
993  else
994  mvBumpMergePar[std::make_pair(&scatt2,&scatt1)]=BumpMergePar(dist,allowMerge);
996 }
998  const ScatteringPower &scatt2)
999 {
1000  Crystal::VBumpMergePar::iterator pos;
1001  if(&scatt1 < &scatt2) pos=mvBumpMergePar.find(make_pair(&scatt1 , &scatt2));
1002  else pos=mvBumpMergePar.find(make_pair(&scatt2 , &scatt1));
1003  if(pos!=mvBumpMergePar.end()) mvBumpMergePar.erase(pos);
1005 }
1006 
1007 const Crystal::VBumpMergePar& Crystal::GetBumpMergeParList()const{return mvBumpMergePar;}
1008 Crystal::VBumpMergePar& Crystal::GetBumpMergeParList(){return mvBumpMergePar;}
1009 
1010 Crystal::InterMolDistPar::InterMolDistPar():
1011  mActDist(-1),mDist2(-1),mSig(0.01),mDelta(0.01)
1012 {}
1013 Crystal::InterMolDistPar::InterMolDistPar(const vector<string> At1, const vector<string> At2, const REAL actualDist, const REAL dist, const REAL sigma, const REAL delta):
1014  mAt1(At1),mAt2(At2),mActDist(actualDist),mDist2(dist*dist),mSig(sigma),mDelta(delta)
1015 {}
1016 string Crystal::InterMolDistPar::get_list_At1()
1017 {
1018  string tmpAt1;
1019  for(int j=0;j<mAt1.size();j++) {
1020  tmpAt1 +=mAt1[j];
1021  if(j<(mAt1.size()-1)) {
1022  tmpAt1 += " ";
1023  }
1024  }
1025  return tmpAt1;
1026 }
1027 string Crystal::InterMolDistPar::get_list_At2()
1028 {
1029  string tmpAt2;
1030  for(int j=0;j<mAt2.size();j++) {
1031  tmpAt2 +=mAt2[j];
1032  if(j<(mAt2.size()-1)) {
1033  tmpAt2 += " ";
1034  }
1035  }
1036  return tmpAt2;
1037 }
1038 void Crystal::InterMolDistPar::set_At2(string atom_names)
1039 {
1040  stringstream ss(atom_names);
1041  string word;
1042  while (ss >> word) {
1043  mAt2.push_back(word);
1044  }
1045 }
1046 void Crystal::SetNewInterMolDist(const vector<string> At1, const vector<string> At2, const REAL dist, const REAL sigma, const REAL delta) const
1047 {
1048  mInterMolDistList.push_back(InterMolDistPar(At1, At2, 0, dist, sigma, delta));
1049  mInterMolDistListNeedsInit=true;
1050 }
1051 int Crystal::GetIntermolDistNb() const
1052 {
1053  return mInterMolDistList.size();
1054 }
1055 void Crystal::RemoveIntermolDistPar(int Index) const
1056 {
1057  if((Index>=mInterMolDistList.size()) || (Index<0)) return;
1058 
1059  mInterMolDistList.erase(mInterMolDistList.begin() + Index);
1060  mInterMolDistListNeedsInit=true;
1061 
1062  return;
1063 }
1064 Crystal::InterMolDistPar Crystal::GetIntermolDistPar(int Index) const
1065 {
1066  if((Index>=mInterMolDistList.size()) || (Index<0)) {
1067  return InterMolDistPar();
1068  }
1069  return mInterMolDistList[Index];
1070 }
1071 Crystal::InterMolDistPar *Crystal::GetIntermolDistPar_ptr(int Index) const
1072 {
1073  if((Index>=mInterMolDistList.size()) || (Index<0)) {
1074  return 0;
1075  }
1076  return &mInterMolDistList[Index];
1077 }
1078 REAL Crystal::GetInterMolDistCost() const
1079 {
1080  if(mInterMolDistList.size()==0) return 0;
1081  if(mInterMolDistCostScale==0.0) return 0;
1082 
1083  this->CalcDistTableForInterMolDistCost();
1084 
1085  VFN_DEBUG_ENTRY("Crystal::GetInterMolDistCost()",4)
1086  if(mInterMolDistCostClock>mDistTableForInterMolDistClock) return mInterMolDistCost*mInterMolDistCostScale;
1087  TAU_PROFILE("Crystal::GetInterMolDistCost()","REAL (REAL)",TAU_DEFAULT);
1088 
1089  mInterMolDistCost=0;
1090 
1091  std::vector<NeighbourHood>::const_iterator pos;
1092  std::vector<Crystal::Neighbour>::const_iterator neigh;
1093 
1094  std::vector<InterMolDistPar>::const_iterator imd;
1095  std::vector<string>::const_iterator itAt2;
1096  //std::vector<NeighbourHood>::const_iterator pos;
1097 
1098  float actdiff=0;
1099  float mindiff=10000000;
1100  float bestDist=0;
1101 
1102  //std::cout<<"GetInterMolDistCost():"<<endl;
1103  //searching all defined mInterMolDistList
1104  for(imd = mInterMolDistList.begin();imd<mInterMolDistList.end();imd++) {
1105  actdiff = 0;
1106  mindiff = 10000000;
1107  bestDist = mDistTableForInterMolMaxDistance;
1108 
1109  for(pos=imd->mNbh.begin();pos<imd->mNbh.end();pos++)
1110  {
1111  for(neigh=pos->mvNeighbour.begin();neigh<pos->mvNeighbour.end();neigh++)
1112  {
1113  if(imd->mDist2 > neigh->mDist2) actdiff = imd->mDist2 - neigh->mDist2;
1114  else actdiff = neigh->mDist2 - imd->mDist2;
1115 
1116  // std::cout<<"actualdiff = "<<actdiff<<"\n";
1117  if(actdiff<mindiff) {
1118  mindiff = actdiff;
1119  bestDist = neigh->mDist2;
1120 
1121  //std::cout<<"saving, bestDist="<<bestDist<<"\n";
1122  }
1123  //std::cout<<"found imd->mAt2 ("<<imd->mAt2<<")\n";
1124  }
1125  }
1126  //std::cout<<"["<<(imd - mInterMolDistList.begin())<<"]: "<<endl;
1127 
1128 
1129  if(bestDist<=0) bestDist = 0.00001;
1130  else bestDist = sqrt(bestDist);
1131  //std::cout<<"bestDist: "<<bestDist<<endl;
1132 
1133 
1134  float d = imd->mDist2;
1135  if(d<=0) d = 0.0000001;
1136  else d = sqrt(d);
1137  //std::cout<<"d: "<<d<<endl;
1138  //std::cout<<"abs(d - bestDist) = "<<abs(d - bestDist)<<"\n";
1139 
1140  if(mCostCalcMethod==0) {
1141  //parabolic
1142  if((bestDist < (d + imd->mDelta)) && (bestDist > (d - imd->mDelta))) {
1143  mInterMolDistCost += 0;
1144  //std::cout<<"add: "<<0<<endl;
1145  } else if(bestDist<=(d-imd->mDelta)) {
1146  mInterMolDistCost += pow((bestDist-(d-imd->mDelta))/imd->mSig, 2);
1147  //std::cout<<"add: "<<pow((bestDist-(d-imd->mDelta))/imd->mSig, 2)<<endl;
1148  } else {
1149  mInterMolDistCost += pow((bestDist-(d+imd->mDelta))/imd->mSig, 2);
1150  //std::cout<<"add: "<<pow((bestDist-(d+imd->mDelta))/imd->mSig, 2)<<endl;
1151  }
1152  } else if(mCostCalcMethod==1) {
1153  //Lorentzian, the inverse
1154  if((bestDist < (d + imd->mDelta)) && (bestDist > (d - imd->mDelta))) {
1155  mInterMolDistCost += 0;
1156  } else if(bestDist<=(d-imd->mDelta)) {
1157  mInterMolDistCost += 1 - ( 1 / ( 1 + pow( ((bestDist-(d-imd->mDelta)) / imd->mSig), 2)));
1158  } else {
1159  mInterMolDistCost += 1 - ( 1 / ( 1 + pow( ((bestDist-(d+imd->mDelta)) / imd->mSig), 2)));
1160  }
1161  } else if(mCostCalcMethod==2) {
1162  //energy Lennard-Jones
1163  //cost = 4*eps*[(sig/ri)^12 - (sig/ri)^6] + 1
1164  //where
1165  //eps = 1
1166  //sig = r(obs)/(2^(1/6))
1167  float sig = d/1.122462;
1168  if((bestDist < (d + imd->mDelta)) && (bestDist > (d - imd->mDelta))) {
1169  mInterMolDistCost += 0;
1170  } else if(bestDist<=(d-imd->mDelta)) {
1171  float ri = bestDist+imd->mDelta;
1172  if(ri<(sig)) {
1173  mInterMolDistCost += 1;
1174  } else {
1175  mInterMolDistCost += 4*1*((pow(sig/ri, 12)-pow(sig/ri, 6)))+1;
1176  }
1177  } else {
1178  float ri = bestDist-imd->mDelta;
1179  mInterMolDistCost += 4*1*((pow(sig/ri, 12)-pow(sig/ri, 6)))+1;
1180  }
1181 
1182  }
1183  //std::cout<<"mInterMolDistCost: "<<mInterMolDistCost<<endl;
1184 
1185  }
1186 
1187  mInterMolDistCost *= this->GetSpaceGroup().GetNbSymmetrics();
1188  //std::cout<<"mInterMolDistCost: "<<mInterMolDistCost<<endl;
1189 
1190  mInterMolDistCostClock.Click();
1191 
1192  return mInterMolDistCost*mInterMolDistCostScale;
1193 }
1194 
1195 
1197 
1198 void Crystal::GlobalOptRandomMove(const REAL mutationAmplitude,
1199  const RefParType *type)
1200 {
1201  if(mRandomMoveIsDone) return;
1202  VFN_DEBUG_ENTRY("Crystal::GlobalOptRandomMove()",2)
1203  //Either a random move or a permutation of two scatterers
1204  const unsigned long nb=(unsigned long)this->GetNbScatterer();
1205  if( ((rand()/(REAL)RAND_MAX)<.02) && (nb>1))
1206  {
1207  // This is safe even if one scatterer is partially fixed,
1208  // since we the SetX/SetY/SetZ actually use the MutateTo() function.
1209  const unsigned long n1=rand()%nb;
1210  const unsigned long n2=( (rand()%(nb-1)) +n1+1) %nb;
1211  const float x1=this->GetScatt(n1).GetX();
1212  const float y1=this->GetScatt(n1).GetY();
1213  const float z1=this->GetScatt(n1).GetZ();
1214  this->GetScatt(n1).SetX(this->GetScatt(n2).GetX());
1215  this->GetScatt(n1).SetY(this->GetScatt(n2).GetY());
1216  this->GetScatt(n1).SetZ(this->GetScatt(n2).GetZ());
1217  this->GetScatt(n2).SetX(x1);
1218  this->GetScatt(n2).SetY(y1);
1219  this->GetScatt(n2).SetZ(z1);
1220  }
1221  else
1222  {
1223  this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,type);
1224  }
1225  mRandomMoveIsDone=true;
1226  VFN_DEBUG_EXIT("Crystal::GlobalOptRandomMove()",2)
1227 }
1228 
1230 {
1231  return this->GetBumpMergeCost()+this->GetBondValenceCost()+this->GetInterMolDistCost();
1232 }
1233 
1234 void Crystal::CIFOutput(ostream &os, double mindist)const
1235 {
1236  VFN_DEBUG_ENTRY("Crystal::OutputCIF()",5)
1237 
1238  //Data block name (must have no spaces)
1239  string tempname = mName;
1240  int where, size;
1241  size = tempname.size();
1242  if (size > 32)
1243  {
1244  tempname = tempname.substr(0,32);
1245  size = tempname.size();
1246  }
1247  if (size == 0)
1248  {
1249  tempname = "3D";
1250  size = 2;
1251  }
1252  where = tempname.find(" ",0);
1253  while (where != (int)string::npos)
1254  {
1255  tempname.replace(where,1,"_");
1256  where = tempname.find(" ",0);
1257  //cout << tempname << endl;
1258  }
1259  os << "data_" << tempname <<endl<<endl;
1260 
1261  //Program
1262  os <<"_computing_structure_solution 'FOX http://objcryst.sourceforge.net'"<<endl<<endl;
1263 
1264  //Scattering powers
1265  /* This is making troubles when the cif file is imported to the JANA2006
1266  os << "loop_"<<endl
1267  << " _atom_type_symbol" <<endl
1268  << " _atom_type_description"<<endl
1269  << " _atom_type_scat_source" <<endl;
1270  for(int i=0;i<this->GetScatteringPowerRegistry().GetNb();i++)
1271  os << " "
1272  << this->GetScatteringPowerRegistry().GetObj(i).GetName()<<" "
1273  <<this->GetScatteringPowerRegistry().GetObj(i).GetSymbol()<<" "
1274  <<"'International Tables for Crystallography (Vol. IV)'"
1275  <<endl;
1276  os <<endl;
1277  */
1278 
1279  //Symmetry
1280  os <<"_symmetry_space_group_name_H-M '"
1281  << this->GetSpaceGroup().GetCCTbxSpg().match_tabulated_settings().hermann_mauguin();
1282  const char ext = this->GetSpaceGroup().GetExtension();
1283  if(isalnum(ext))
1284  os <<":"<<ext;
1285  os <<"'"<<endl;
1286  os <<"_symmetry_space_group_name_Hall '"
1287  << this->GetSpaceGroup().GetCCTbxSpg().match_tabulated_settings().hall()<<"'"<<endl;
1288  os <<endl;
1289 
1290  os << "_cell_length_a " << FormatFloat(this->GetLatticePar(0),8,5) << endl
1291  << "_cell_length_b " << FormatFloat(this->GetLatticePar(1),8,5) << endl
1292  << "_cell_length_c " << FormatFloat(this->GetLatticePar(2),8,5) << endl
1293  << "_cell_angle_alpha " << FormatFloat(this->GetLatticePar(3)*RAD2DEG,7,3) << endl
1294  << "_cell_angle_beta " << FormatFloat(this->GetLatticePar(4)*RAD2DEG,7,3) << endl
1295  << "_cell_angle_gamma " << FormatFloat(this->GetLatticePar(5)*RAD2DEG,7,3) << endl
1296  << "_cell_volume " << FormatFloat(this->GetVolume(),7,2);
1297  os <<endl;
1299 
1300  /*
1301  TODO:
1302  loop_
1303  _symmetry_equiv_pos_site_id
1304  _symmetry_equiv_pos_as_xyz
1305 
1306  */
1307 
1308  os << "loop_" << endl
1309  << " _atom_site_label" <<endl
1310  << " _atom_site_type_symbol" <<endl
1311  << " _atom_site_fract_x"<<endl
1312  << " _atom_site_fract_y" <<endl
1313  << " _atom_site_fract_z" <<endl
1314  << " _atom_site_U_iso_or_equiv" <<endl
1315  << " _atom_site_occupancy" <<endl
1316  << " _atom_site_adp_type" <<endl;
1317 
1318  const double BtoU = 1.0 / (8 * M_PI * M_PI);
1319  std::vector<const ScatteringPower*> anisovec;
1320  std::vector<std::string> namevec;
1321  CrystMatrix_REAL minDistTable;
1322  minDistTable=this->GetMinDistanceTable(-1.);
1323  unsigned long k=0;
1324  for(int i=0;i<mScattererRegistry.GetNb();i++)
1325  {
1326  //mpScatterrer[i]->Print();
1328  for(int j=0;j<list.GetNbComponent();j++)
1329  {
1330  if(0==list(j).mpScattPow) continue;
1331  bool redundant=false;
1332  for(unsigned long l=0;l<k;++l) if(abs(minDistTable(l,k))<mindist) redundant=true;//-1 means dist > 10A
1333  if(!redundant)
1334  {
1335  // We can't have spaces in atom labels
1336  string s=this->GetScatt(i).GetComponentName(j);
1337  size_t posc=s.find(' ');
1338  while(posc!=string::npos){s[posc]='~';posc=s.find(' ');}
1339 
1340  bool isiso = list(j).mpScattPow->IsIsotropic();
1341  if(!isiso)
1342  {
1343  anisovec.push_back(list(j).mpScattPow);
1344  namevec.push_back(s);
1345  }
1346 
1347  os << " "
1348  << FormatString(s,10) << " "
1349  << FormatString(list(j).mpScattPow->GetSymbol(),8) << " "
1350  << FormatFloat(list(j).mX,9,6) << " "
1351  << FormatFloat(list(j).mY,9,6) << " "
1352  << FormatFloat(list(j).mZ,9,6) << " "
1353  << FormatFloat(list(j).mpScattPow->GetBiso()*BtoU,9,6) << " "
1354  << FormatFloat(list(j).mOccupancy,6,4)
1355  << (isiso ? " Uiso" : " Uani")
1356  << endl;
1357  }
1358  k++;
1359  }
1360  }
1361 
1362 
1363  // Handle anisotropic atoms
1364  if( anisovec.size() > 0 )
1365  {
1366 
1367  os << endl
1368  << "loop_" << endl
1369  << " _atom_site_aniso_label" << endl
1370  << " _atom_site_aniso_U_11" << endl
1371  << " _atom_site_aniso_U_22" << endl
1372  << " _atom_site_aniso_U_33" << endl
1373  << " _atom_site_aniso_U_12" << endl
1374  << " _atom_site_aniso_U_13" << endl
1375  << " _atom_site_aniso_U_23" << endl;
1376 
1377 
1378  for(size_t i = 0; i < anisovec.size(); ++i)
1379  {
1380  os << " " << FormatString(namevec[i],8) << " ";
1381  for(int j=0; j<6; ++j)
1382  os << FormatFloat(anisovec[i]->GetBij(j)*BtoU,9,6) << " ";
1383  os << endl;
1384  }
1385  }
1386 
1387 
1388  bool first=true;
1389  k=0;
1390  for(int i=0;i<mScattererRegistry.GetNb();i++)
1391  {
1393  for(int j=0;j<list.GetNbComponent();j++)
1394  {
1395  if(0==list(j).mpScattPow) continue;
1396  bool redundant=false;
1397  for(unsigned long l=0;l<k;++l) if(abs(minDistTable(l,k))<mindist) redundant=true;//-1 means dist > 10A
1398  if(redundant)
1399  {
1400  if(first)
1401  {
1402  first=false;
1403  os <<endl
1404  << "# The following atoms have been excluded by Fox because they are"<<endl
1405  << "# almost fully overlapping with another atom (d<" << mindist << "A)"<< endl;
1406  }
1407  os << "# "
1408  << FormatString(list(j).mpScattPow->GetName(),8) << " "
1409  << FormatString(this->GetScatt(i).GetComponentName(j),10) << " "
1410  << FormatFloat(list(j).mX,9,6) << " "
1411  << FormatFloat(list(j).mY,9,6) << " "
1412  << FormatFloat(list(j).mZ,9,6) << " "
1413  << FormatFloat(list(j).mpScattPow->GetBiso()*BtoU,9,6) << " "
1414  << FormatFloat(list(j).mOccupancy,6,4)
1415  << " Uiso"
1416  << endl;
1417  }
1418  k++;
1419  }
1420  }
1421 
1422  os <<endl;
1423  k=0;
1424  if(1==mUseDynPopCorr.GetChoice())
1425  {
1426  os << "# Dynamical occupancy corrections found by ObjCryst++:"<<endl
1427  << "# values below 1. (100%) indicate a correction,"<<endl
1428  << "# which means either that the atom is on a special position,"<<endl
1429  << "# or that it is overlapping with another identical atom."<<endl;
1430  for(int i=0;i<mScattererRegistry.GetNb();i++)
1431  {
1432  //mpScatterrer[i]->Print();
1434  for(int j=0;j<list.GetNbComponent();j++)
1435  {
1436  os << "# "
1437  << FormatString(this->GetScatt(i).GetComponentName(j),16)
1438  << " : " << FormatFloat(mScattCompList(k).mDynPopCorr,6,4)
1439  << endl;
1440  k++;
1441  }
1442  }
1443  os << "#"<<endl;
1444  }
1445 
1446  VFN_DEBUG_EXIT("Crystal::OutputCIF()",5)
1447 }
1448 
1450  CrystVector_uint & groupIndex,
1451  unsigned int &first) const
1452 {
1453  // One group for all lattice parameters
1454  unsigned int latticeIndex=0;
1455  VFN_DEBUG_MESSAGE("Crystal::GetGeneGroup()",4)
1456  for(long i=0;i<obj.GetNbPar();i++)
1457  for(long j=0;j<this->GetNbPar();j++)
1458  if(&(obj.GetPar(i)) == &(this->GetPar(j)))
1459  {
1460  //if(this->GetPar(j).GetType()->IsDescendantFromOrSameAs(gpRefParTypeUnitCell))
1461  //{
1462  if(latticeIndex==0) latticeIndex=first++;
1463  groupIndex(i)=latticeIndex;
1464  //}
1465  //else //no parameters other than unit cell
1466  }
1467 }
1468 void Crystal::BeginOptimization(const bool allowApproximations,const bool enableRestraints)
1469 {
1470  if(this->IsBeingRefined())
1471  {
1472  // RefinableObj::BeginOptimization() will increase the optimization depth
1473  this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints);
1474  return;
1475  }
1476  for(int i=0;i<this->GetScattererRegistry().GetNb();i++)
1477  {
1478  this->GetScattererRegistry().GetObj(i).
1479  SetGlobalOptimStep(gpRefParTypeScattTranslX,0.1/this->GetLatticePar(0));
1480  this->GetScattererRegistry().GetObj(i).
1481  SetGlobalOptimStep(gpRefParTypeScattTranslY,0.1/this->GetLatticePar(1));
1482  this->GetScattererRegistry().GetObj(i).
1483  SetGlobalOptimStep(gpRefParTypeScattTranslZ,0.1/this->GetLatticePar(2));
1484  }
1485  this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints);
1486  // Calculate mDistTableMaxDistance: Default 1 Angstroem, for dynamical occupancy correction
1487  mDistTableMaxDistance=10.0;
1488  // Up to 4 Angstroem if bond-valence is used
1489  if((mvBondValenceRo.size()>0) && (mBondValenceCostScale>1e-5)) mDistTableMaxDistance=4;
1490  // Up to whatever antibump distance the user requires (hopefully not too large !)
1491  for(Crystal::VBumpMergePar::iterator pos=mvBumpMergePar.begin();pos!=mvBumpMergePar.end();++pos)
1492  if(sqrt(pos->second.mDist2)>mDistTableMaxDistance) mDistTableMaxDistance=sqrt(pos->second.mDist2);
1493 
1494  //finding the maximal distance in the user-defined list
1495  mDistTableForInterMolMaxDistance = 1.0;
1496  for(int i=0;i<mInterMolDistList.size();i++) {
1497  if(mInterMolDistList[i].mDist2>0) {
1498  float d = sqrt(mInterMolDistList[i].mDist2);
1499  if(d>mDistTableForInterMolMaxDistance) {
1500  mDistTableForInterMolMaxDistance = d;
1501  }
1502  }
1503  }
1504 
1505  mInterMolDistListNeedsInit = true;
1506 
1507  if(mInterMolDistList.size()!=0) {
1508  mDistTableForInterMolMaxDistance*=mDistMaxMultiplier;
1509  }
1510 
1511  VFN_DEBUG_MESSAGE("Crystal::BeginOptimization():mDistTableMaxDistance="<<mDistTableMaxDistance,10)
1512 }
1513 
1514 void Crystal::AddBondValenceRo(const ScatteringPower &pow1,const ScatteringPower &pow2,const REAL ro)
1515 {
1516  if(&pow1 < &pow2) mvBondValenceRo[make_pair(&pow1,&pow2)]=ro;
1517  else mvBondValenceRo[make_pair(&pow2,&pow1)]=ro;
1519  this->UpdateDisplay();
1520 }
1521 
1522 void Crystal::RemoveBondValenceRo(const ScatteringPower &pow1,const ScatteringPower &pow2)
1523 {
1524  map<pair<const ScatteringPower*,const ScatteringPower*>, REAL>::iterator pos;
1525  if(&pow1 < &pow2) pos=mvBondValenceRo.find(make_pair(&pow1 , &pow2));
1526  else pos=mvBondValenceRo.find(make_pair(&pow2 , &pow1));
1527  if(pos!=mvBondValenceRo.end()) mvBondValenceRo.erase(pos);
1529 }
1530 
1532 {
1533  VFN_DEBUG_MESSAGE("Crystal::GetBondValenceCost()?",4)
1534  if(mBondValenceCostScale<1e-5) return 0.0;
1535  if(mvBondValenceRo.size()==0)
1536  {
1537  mBondValenceCost=0.0;
1539  }
1540  this->CalcBondValenceSum();
1543  VFN_DEBUG_MESSAGE("Crystal::GetBondValenceCost():"<<mvBondValenceCalc.size()<<" valences",4)
1544  TAU_PROFILE("Crystal::GetBondValenceCost()","REAL ()",TAU_DEFAULT);
1545  mBondValenceCost=0.0;
1546  std::map<long, REAL>::const_iterator pos;
1547  for(pos=mvBondValenceCalc.begin();pos!=mvBondValenceCalc.end();++pos)
1548  {
1549  const REAL a=pos->second-mScattCompList(pos->first).mpScattPow->GetFormalCharge();
1550  mBondValenceCost += a*a;
1551  VFN_DEBUG_MESSAGE("Crystal::GetBondValenceCost():"
1552  <<mScattCompList(pos->first).mpScattPow->GetName()
1553  <<"="<<pos->second,4)
1554  }
1557 }
1558 
1559 std::map<pair<const ScatteringPower*,const ScatteringPower*>, REAL>& Crystal::GetBondValenceRoList()
1560 { return mvBondValenceRo;}
1561 
1562 const std::map<pair<const ScatteringPower*,const ScatteringPower*>, REAL>& Crystal::GetBondValenceRoList()const
1563 { return mvBondValenceRo;}
1564 
1566 {
1567  if(mvBondValenceRo.size()==0) return;
1568  this->CalcDistTable(true);
1569  VFN_DEBUG_MESSAGE("Crystal::CalcBondValenceSum()?",4)
1572  VFN_DEBUG_MESSAGE("Crystal::CalcBondValenceSum()",4)
1573  TAU_PROFILE("Crystal::CalcBondValenceSum()","void ()",TAU_DEFAULT);
1574  mvBondValenceCalc.clear();
1575  for(long i=0;i<mScattCompList.GetNbComponent();i++)
1576  {
1577  const ScatteringPower *pow1=mScattCompList(i).mpScattPow;
1578  int nb=0;
1579  REAL val=0.0;
1580  std::vector<Crystal::Neighbour>::const_iterator pos;
1581  for(pos=mvDistTableSq[i].mvNeighbour.begin();
1582  pos<mvDistTableSq[i].mvNeighbour.end();pos++)
1583  {
1584  const REAL dist=sqrt(pos->mDist2);
1585  const REAL occup= mScattCompList(pos->mNeighbourIndex).mOccupancy
1586  *mScattCompList(pos->mNeighbourIndex).mDynPopCorr;
1587  const ScatteringPower *pow2=mScattCompList(pos->mNeighbourIndex).mpScattPow;
1588  map<pair<const ScatteringPower*,const ScatteringPower*>,REAL>::const_iterator pos;
1589  if(pow1<pow2) pos=mvBondValenceRo.find(make_pair(pow1,pow2));
1590  else pos=mvBondValenceRo.find(make_pair(pow2,pow1));
1591  if(pos!=mvBondValenceRo.end())
1592  {
1593  const REAL v=exp((pos->second-dist)/0.37);
1594  val += occup * v;
1595  nb++;
1596  }
1597  }
1598  if(nb!=0) mvBondValenceCalc[i]=val;
1599  }
1601 }
1602 
1603 void Crystal::Init(const REAL a, const REAL b, const REAL c, const REAL alpha,
1604  const REAL beta, const REAL gamma,const string &SpaceGroupId,
1605  const string& name)
1606 {
1607  VFN_DEBUG_MESSAGE("Crystal::Init(a,b,c,alpha,beta,gamma,Sg,name)",10)
1608  this->UnitCell::Init(a,b,c,alpha,beta,gamma,SpaceGroupId,name);
1612 
1613  VFN_DEBUG_MESSAGE("Crystal::Init(a,b,c,alpha,beta,gamma,Sg,name):End",10)
1614 }
1615 
1616 bool CompareBondDist(MolBond* b1, MolBond* b2)
1617 {
1618  return b1->GetLength()<b2->GetLength();
1619 }
1620 
1621 bool ComparePairSecond(const std::pair<int,float> &b1, const std::pair<int,float> &b2)
1622 {
1623  return b1.second < b2.second;
1624 }
1625 
1626 void Crystal::ConnectAtoms(const REAL min_relat_dist, const REAL max_relat_dist, const bool warnuser_fail)
1627 {
1628  VFN_DEBUG_ENTRY("Crystal::ConnectAtoms(...)",10)
1629  // Make sure there are only atoms
1630  for(unsigned int i=0;i<mScattererRegistry.GetNb();i++)
1631  {
1632  if(mScattererRegistry.GetObj(i).GetClassName()!="Atom")
1633  {
1634  if(warnuser_fail) (*fpObjCrystInformUser)("Crystal::ConnectAtoms(): cannot connect atoms unless there are only Atoms in a Crystal");
1635  return;
1636  }
1637  }
1638  this->CalcDistTable(true);
1640 
1641  // Create first Molecule
1642  // start from start_carbon
1643  Molecule *pmol=NULL;
1644  std::set<int> vAssignedAtoms;//atoms already assigned to a Molecule
1645  std::set<int> vTriedAtom0;//atoms already tried as starting point for a Molecule
1646  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...)",10)
1647  while(long(vAssignedAtoms.size()) != mScattererRegistry.GetNb())
1648  {
1649  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): new Molecule ?",7)
1650  // We need at least one carbon atom to start
1651  int atom0=-1;
1652  int maxAtomicNumber = 0;
1653  for(unsigned int i=0;i<mScattCompList.GetNbComponent();i++)
1654  {
1655  if((vAssignedAtoms.count(i)>0) || (vTriedAtom0.find(i)!=vTriedAtom0.end()) ) continue;
1656  if(mScattCompList(i).mpScattPow->GetClassName()=="ScatteringPowerAtom")
1657  {
1658  const ScatteringPowerAtom *p=dynamic_cast<const ScatteringPowerAtom*>(mScattCompList(i).mpScattPow);
1659  if((p->GetAtomicNumber()==6)&&(maxAtomicNumber!=6))
1660  {// Start from the first Carbon found
1661  atom0=i;
1662  maxAtomicNumber=6;
1663  }
1664  else if((p->GetAtomicNumber()>maxAtomicNumber) && (maxAtomicNumber!=6))
1665  {// Else we'll try from the heaviest atom
1666  maxAtomicNumber=p->GetAtomicNumber();
1667  atom0=i;
1668  }
1669  }
1670  else
1671  {
1672  if(warnuser_fail)
1673  (*fpObjCrystInformUser)("Crystal::ConnectAtoms(): cannot connect atoms unless there are only Atoms in a Crystal");
1674  VFN_DEBUG_EXIT("Crystal::ConnectAtoms(...):cannot connect atoms unless there are only Atoms in the structure:"<<i<<":"<<mScattCompList(i).mpScattPow->GetClassName(),10)
1675  return;
1676  }
1677  }
1678  if(atom0<0)
1679  {
1680  if((pmol==NULL) && warnuser_fail) // We did not create any Molecule :-(
1681  {
1682  (*fpObjCrystInformUser)("Crystal::ConnectAtoms(): cannot connect atoms unless there is at least one carbon atom");
1683  VFN_DEBUG_EXIT("Crystal::ConnectAtoms(...):cannot connect atoms unless there is at least one carbon atom",10)
1684  return;
1685  }
1686  break;
1687  }
1688  vTriedAtom0.insert(atom0);
1689  // Atoms in Molecule but for which neighbors have not yet been searched
1690  // first: index in the Crystal's scatt comp list, second: index in the Molecule
1691  std::map<int,int>newAtoms;
1692  // List of all atoms in the Molecule. First is the MolAtom* in the molecule, second is the index in the Crystal
1693  std::map<MolAtom*,int> molAtoms;
1694 
1695  pmol=new Molecule(*this);
1696 
1697  // Add atom0 to Molecule.
1698  newAtoms[atom0]=0;
1699  vAssignedAtoms.insert(atom0);
1700  const ScatteringPowerAtom *p0=dynamic_cast<const ScatteringPowerAtom*>(mScattCompList(atom0).mpScattPow);
1701  {
1702  REAL x=mScattCompList(atom0).mX;
1703  REAL y=mScattCompList(atom0).mY;
1704  REAL z=mScattCompList(atom0).mZ;
1705  const REAL occ=mScattCompList(atom0).mOccupancy;
1706  this->FractionalToOrthonormalCoords(x,y,z);
1707  pmol->AddAtom(x,y,z,p0,mScattererRegistry.GetObj(atom0).GetName(),false);
1708  pmol->GetAtomList().back()->SetOccupancy(occ);
1709  }
1710  molAtoms[pmol->GetAtomList().back()]=atom0;
1711  // Count atoms in the Molecule per element type
1712  vector<unsigned int> vElementCount(140);// Should be safe pending a trans-uranian breakthrough
1713  for(vector<unsigned int>::iterator pos=vElementCount.begin();pos!=vElementCount.end();++pos) *pos=0;
1714  vElementCount[p0->GetAtomicNumber()]+=1;
1715  while(newAtoms.size()>0)
1716  {
1717  atom0=newAtoms.begin()->first;
1718  p0=dynamic_cast<const ScatteringPowerAtom*>(mScattCompList(atom0).mpScattPow);
1719  VFN_DEBUG_ENTRY("Crystal::ConnectAtoms(...):atom0="<<atom0<<","<<mScattererRegistry.GetObj(atom0).GetName()<<"["<<p0->GetSymbol()<<"],"<<newAtoms.size()<<" new atoms",7)
1720  std::vector<std::pair<int,float> > vatomsneighbours;
1721  // Find neigbours between min and max * sum of covalent bonds
1722  for(std::vector<Crystal::Neighbour>::const_iterator pos=mvDistTableSq[atom0].mvNeighbour.begin();
1723  pos!=mvDistTableSq[atom0].mvNeighbour.end();pos++)
1724  {
1725  const ScatteringPowerAtom *p1=dynamic_cast<const ScatteringPowerAtom*>(mScattCompList(pos->mNeighbourIndex).mpScattPow);
1726  const REAL dcov= p0->GetCovalentRadius()+p1->GetCovalentRadius();
1727  //if( (vAssignedAtoms.count(pos->mNeighbourIndex)!=0) || (p1->GetMaxCovBonds()==0))
1728  if(p1->GetMaxCovBonds()==0)
1729  continue;
1730  if( ((min_relat_dist*dcov)<sqrt(pos->mDist2))
1731  &&((max_relat_dist*dcov)>sqrt(pos->mDist2)))
1732  {
1733  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...):atom0="<<mScattererRegistry.GetObj(atom0).GetName()<<"-"<<p1->GetName()<<"("<<p1->GetMaxCovBonds()<<"):dcov="<<dcov<<",d="<<sqrt(pos->mDist2),7)
1734  vatomsneighbours.push_back(std::make_pair(pos->mNeighbourIndex,sqrt(pos->mDist2)));
1735  }
1736  else
1737  {
1738  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...):atom0="<<mScattererRegistry.GetObj(atom0).GetName()<<"-"<<p1->GetName()<<"("<<p1->GetMaxCovBonds()<<"):dcov="<<dcov<<",d="<<sqrt(pos->mDist2),5)
1739  }
1740  }
1741  // Remove farthest neighbours if in excess of the maximum coordination.
1742  // But keep excess neighbours if close (5%) of the last neighbour within the normal coordination number.
1743  const unsigned int maxbonds=p0->GetMaxCovBonds();
1744  float extra=vatomsneighbours.size()-maxbonds;
1745  if(extra>0)
1746  {
1747  // Check real number of bonds taking into account occupancy, and sort bonds by length
1748  REAL nbbond=0;
1749  for(std::vector<std::pair<int,float> >::const_iterator pos=vatomsneighbours.begin();pos!=vatomsneighbours.end();++pos)
1750  {
1751  nbbond+=mScattCompList(pos->first).mOccupancy;
1752  }
1753  extra = nbbond-maxbonds;
1754  if(extra>0.2)
1755  {
1756  std::sort(vatomsneighbours.begin(), vatomsneighbours.end(),ComparePairSecond);
1757  VFN_DEBUG_ENTRY("Crystal::ConnectAtoms(...): too many bonds for"<<mScattererRegistry.GetObj(atom0).GetName()
1758  <<" ?(allowed="<<maxbonds<<",nb="<<vatomsneighbours.size()<<",nb_occ="<<nbbond<<",longest="<<vatomsneighbours.back().second<<"["
1759  <<mScattererRegistry.GetObj(atom0).GetName()<<"-"<<mScattererRegistry.GetObj(vatomsneighbours.back().first).GetName()<<"])", 10)
1760  const REAL maxdist=vatomsneighbours[vatomsneighbours.size()-extra].second*1.05;
1761  while(vatomsneighbours.back().second>maxdist)
1762  {
1763  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): Remove bond="<<mScattererRegistry.GetObj(atom0).GetName()
1764  <<"-"<<mScattererRegistry.GetObj(vatomsneighbours.back().first).GetName()<<", d="<<vatomsneighbours.back().second,10)
1765  vatomsneighbours.pop_back();
1766  }
1767  VFN_DEBUG_EXIT("Crystal::ConnectAtoms(...): too many bonds for"<<mScattererRegistry.GetObj(atom0).GetName()
1768  <<" ?(allowed="<<maxbonds<<",nb="<<vatomsneighbours.size()<<",longest="<<vatomsneighbours.back().second<<"["
1769  <<mScattererRegistry.GetObj(atom0).GetName()<<"-"<<mScattererRegistry.GetObj(vatomsneighbours.back().first).GetName()<<"])", 10)
1770  }
1771  }
1772 
1773  // Add remaining atoms to molecule and mark them as asigned
1774  //if(extra>0) cout<<"Crystal::ConnectAtoms(): adding neighbours around "<<mScattererRegistry.GetObj(atom0).GetName()<<" :";
1775  for(std::vector<std::pair<int,float> >::const_iterator pos=vatomsneighbours.begin();pos!=vatomsneighbours.end();++pos)
1776  {
1777  if(vAssignedAtoms.count(pos->first)!=0)
1778  {
1779  if(extra>0) cout<<"("<<mScattererRegistry.GetObj(pos->first).GetName()<<") ";
1780  continue;
1781  }
1782  //if(extra>0) cout<<mScattererRegistry.GetObj(pos->first).GetName()<<" ";
1783  const ScatteringPowerAtom *p1=dynamic_cast<const ScatteringPowerAtom*>(mScattCompList(pos->first).mpScattPow);
1784  vAssignedAtoms.insert(pos->first);
1785  REAL x=mScattCompList(pos->first).mX;
1786  REAL y=mScattCompList(pos->first).mY;
1787  REAL z=mScattCompList(pos->first).mZ;
1788  this->FractionalToOrthonormalCoords(x,y,z);
1789  const REAL occ=mScattCompList(pos->first).mOccupancy;
1790  pmol->AddAtom(x,y,z,p1,mScattererRegistry.GetObj(pos->first).GetName(),false);
1791  pmol->GetAtomList().back()->SetOccupancy(occ);
1792  newAtoms[pos->first]=pmol->GetNbComponent()-1;
1793  molAtoms[pmol->GetAtomList().back()]=pos->first;
1794  vElementCount[p1->GetAtomicNumber()]+=1;
1795  }
1796  //if(extra>0) cout<<endl;
1797  newAtoms.erase(atom0);
1798  VFN_DEBUG_EXIT("Crystal::ConnectAtoms(...):atom0="<<atom0<<","<<mScattererRegistry.GetObj(atom0).GetName()<<"["<<p0->GetSymbol()<<"],"<<newAtoms.size()<<" new atoms. Temp Molecule:"<<pmol->GetFormula(),7)
1799  }
1800  // Check this is a valid Molecule object
1801  bool keep=false;
1802  if((vElementCount[6]>0) && (pmol->GetNbComponent()>=3)) keep=true;
1803  else
1804  {// no carbon ?
1805 
1806  std::vector<unsigned int> vnb;
1807  #ifdef __DEBUG__
1808  cout<<" Crystal::ConnectAtoms(..): Molecule ?";
1809  #endif
1810  for(unsigned int i=0;i<vElementCount.size();++i)
1811  if(vElementCount[i]!=0)
1812  {
1813  vnb.push_back(vElementCount[i]);
1814  #ifdef __DEBUG__
1815  cout<<"Z="<<i<<"("<< vElementCount[i]<<") ";
1816  #endif
1817  }
1818  #ifdef __DEBUG__
1819  cout<<endl;
1820  #endif
1821  if(vnb.size()==2)
1822  {
1823  #if 0
1824  if((vElementCount[8]==1) && (vElementCount[1]==2)) keep=true; //H2O
1825  if((vElementCount[8]==1) && (vElementCount[1]==3)) keep=true; //H3O+
1826  if((vElementCount[7]==1) && (vElementCount[1]==3)) keep=true; //NH3
1827  if((vElementCount[7]==1) && (vElementCount[1]==4)) keep=true; //NH4+
1828  if((vElementCount[7]==1) && (vElementCount[8]==2)) keep=true; //NO2
1829  if((vElementCount[7]==1) && (vElementCount[8]==3)) keep=true; //NO3-
1830  if((vElementCount[5]==1) && (vElementCount[1]==3)) keep=true; //BH3
1831  if((vElementCount[5]==1) && (vElementCount[1]==4)) keep=true; //BH4-
1832  if((vElementCount[14]==1) && (vElementCount[8]==4)) keep=true; //SiO4
1833  if((vElementCount[15]==1) && (vElementCount[8]==4)) keep=true; //PO4
1834  #endif
1835  #if 0
1836  // Accept any type of small molecule/polyedra with one center atom
1837  if( ((vnb[0]==1)||(vnb[1]==1)) && ((vnb[0]+vnb[1])>2)) keep=true;
1838  #endif
1839  // Accept any type of cluster with exactly two types of atoms
1840  keep=true;
1841  }
1842  }
1843  if(!keep)
1844  {
1845  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...):Rejected molecule: "<<pmol->GetFormula(),10)
1846  delete pmol;
1847  for(std::map<MolAtom*,int>::const_iterator pos=molAtoms.begin();pos!=molAtoms.end();++pos) vAssignedAtoms.erase(pos->second);
1848  continue;// Will start from another atom to build a molecule
1849  }
1850 
1851  // Add bonds
1852  for(unsigned int i=0;i<pmol->GetAtomList().size();i++)
1853  {
1854  for(unsigned int j=i+1;j<pmol->GetAtomList().size();j++)
1855  {
1856  const REAL d=GetBondLength(pmol->GetAtom(i), pmol->GetAtom(j));
1857  const REAL dcov= dynamic_cast<const ScatteringPowerAtom*>(&(pmol->GetAtom(i).GetScatteringPower()))->GetCovalentRadius()
1858  +dynamic_cast<const ScatteringPowerAtom*>(&(pmol->GetAtom(j).GetScatteringPower()))->GetCovalentRadius();
1859  if( ((min_relat_dist*dcov)<d) && ((max_relat_dist*dcov)>d))
1860  {
1861  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...):Add bond="<<pmol->GetAtom(i).GetName()<<"-"<<pmol->GetAtom(j).GetName()<<", d="<<d<<"(dcov="<<dcov<<")",6)
1862  pmol->AddBond(pmol->GetAtom(i),pmol->GetAtom(j),d,.01,.02,false);
1863  }
1864  }
1865  }
1866  // Remove longest bonds if it exceeds the expected coordination
1867  // :TODO: combined with the check already made, this is not fullproof, for atoms where the coordination number is not so well-defined,
1868  // e.g. Li and Na is defined as 1, but there could be more linked atoms...
1869  // If we still find a too great coordination number, remove excess ones but still keep those that are very close (5%) of the cutoff distance.
1870  for(vector<MolAtom*>::iterator pos=pmol->GetAtomList().begin();pos!=pmol->GetAtomList().end();)
1871  {
1872  pmol->BuildConnectivityTable();
1873  map<MolAtom *,set<MolAtom *> >::const_iterator p=pmol->GetConnectivityTable().find(*pos);
1874  if(p==pmol->GetConnectivityTable().end())
1875  {// While cleaning the longest bond, this atom had all his bonds removed !
1876  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...):no bond remaining for:"<<(*pos)->GetName()<<"! Removing atom from Molecule",10)
1877  //Remove MolAtom from Molecule and keep in Crystal.
1878  vAssignedAtoms.erase(molAtoms[*pos]);
1879  molAtoms.erase(*pos);
1880  pos=pmol->RemoveAtom(**pos);
1881  continue;
1882  }
1883  const unsigned int maxbonds=dynamic_cast<const ScatteringPowerAtom*>(&(p->first->GetScatteringPower()))->GetMaxCovBonds();
1884  int extra=p->second.size()-maxbonds;
1885  if(extra>0)
1886  {
1887  // Check real number of bonds taking into account occupancy, and sort bonds by length
1888  std::vector<MolBond*> vbonds;
1889  REAL nbbond=0;
1890  for(std::set<MolAtom*>::iterator p1=p->second.begin();p1!=p->second.end();++p1)
1891  {
1892  vbonds.push_back(*(pmol->FindBond(**pos,**p1)));// We can assume that exactly one bond is found
1893  nbbond+=(*p1)->GetOccupancy();
1894  }
1895  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): too many bonds for"<<(*pos)->GetName()<<" ?(allowed="<<maxbonds<<",nb="<<p->second.size()<<",nb_occ="<<nbbond<<")", 10)
1896  const int extra= (int)(nbbond-maxbonds);
1897  if(extra>0)
1898  {
1899  std::sort(vbonds.begin(), vbonds.end(),CompareBondDist);
1900  if(size_t(extra) < vbonds.size()) // Am I paranoid ?
1901  {
1902  const REAL maxdist=vbonds[vbonds.size()-extra]->GetLength()*1.05;
1903  while(vbonds.back()->GetLength()>maxdist)
1904  {
1905  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): Remove bond="<<vbonds.back()->GetAtom1().GetName()<<"-"<<vbonds.back()->GetAtom2().GetName()<<", d="<<vbonds.back()->GetLength(),10)
1906  pmol->RemoveBond(*(vbonds.back()));
1907  vbonds.pop_back();
1908  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): Next bond ="<<vbonds.back()->GetAtom1().GetName()<<"-"<<vbonds.back()->GetAtom2().GetName()<<", d="<<vbonds.back()->GetLength(),10)
1909  }
1910  }
1911  }
1912  }
1913  ++pos;
1914  }
1915  // Add all bond angles
1916  pmol->BuildConnectivityTable();
1917  for(map<MolAtom*,set<MolAtom*> >::const_iterator pos=pmol->GetConnectivityTable().begin();
1918  pos!=pmol->GetConnectivityTable().end();++pos)
1919  {
1920  for(set<MolAtom*>::const_iterator pos1=pos->second.begin();
1921  pos1!=pos->second.end();++pos1)
1922  {
1923  for(set<MolAtom*>::const_iterator pos2=pos1;
1924  pos2!=pos->second.end();++pos2)
1925  {
1926  if(pos2==pos1) continue;
1927  if(pmol->FindBondAngle(**pos1,*(pos->first),**pos2)== pmol->GetBondAngleList().end())
1928  pmol->AddBondAngle(**pos1,*(pos->first),**pos2,
1929  GetBondAngle(**pos1,*(pos->first),**pos2),0.01,0.02,false);
1930  }
1931  }
1932  }
1933  // Correct center of Molecule
1934  REAL xc=0,yc=0,zc=0;
1935  for(std::map<MolAtom*,int>::const_iterator pos=molAtoms.begin();pos!=molAtoms.end();++pos)
1936  {
1937  REAL x=mScattCompList(pos->second).mX;
1938  REAL y=mScattCompList(pos->second).mY;
1939  REAL z=mScattCompList(pos->second).mZ;
1940  this->FractionalToOrthonormalCoords(x,y,z);
1941  xc+=x;
1942  yc+=y;
1943  zc+=z;
1944  }
1945  xc /= pmol->GetNbComponent();
1946  yc /= pmol->GetNbComponent();
1947  zc /= pmol->GetNbComponent();
1948  this->OrthonormalToFractionalCoords(xc,yc,zc);
1949  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): center?"<<pmol->GetNbComponent()<<","<<molAtoms.size()<<":"<<xc<<","<<yc<<","<<zc,10)
1950  pmol->SetX(xc);
1951  pmol->SetY(yc);
1952  pmol->SetZ(zc);
1953  this->AddScatterer(pmol);
1954  (*fpObjCrystInformUser)("ConnectAtoms: found Molecule: "+pmol->GetFormula());
1955  }
1956  std::set<Scatterer*> vpAtom;
1957  for(std::set<int>::const_iterator pos=vAssignedAtoms.begin();pos!=vAssignedAtoms.end();++pos)
1958  {
1959  Scatterer *s=&(this->GetScattererRegistry().GetObj(*pos));
1960  vpAtom.insert(s);
1961  }
1962  while(vpAtom.size()>0)
1963  {
1964  VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): remove atom:"<<(*vpAtom.begin())->GetName()<<","<<vpAtom.size()<<" remaining...",6)
1965  this->RemoveScatterer(*vpAtom.begin(),true);
1966  vpAtom.erase(vpAtom.begin());
1967  }
1968  VFN_DEBUG_EXIT("Crystal::ConnectAtoms(...)",10)
1969 }
1970 
1971 void Crystal::MergeEqualScatteringPowers(const bool oneScatteringPowerPerElement)
1972 {
1973  VFN_DEBUG_ENTRY("Crystal::MergeEqualScatteringPowers("<<oneScatteringPowerPerElement<<")", 10)
1974  // Find identical scattering powers.
1975  std::set<ScatteringPower*> vremovedpow;
1976  std::map<ScatteringPower*,std::set<ScatteringPower*> > vequivpow;
1977  for(unsigned int i=0;i<this->GetScatteringPowerRegistry().GetNb();i++)
1978  {
1979  ScatteringPower *p1 = &(this->GetScatteringPowerRegistry().GetObj(i));
1980  if(vremovedpow.find(p1)!=vremovedpow.end()) continue;
1981  vequivpow[p1] = std::set<ScatteringPower*>();
1982  for(unsigned int j=i+1;j<this->GetScatteringPowerRegistry().GetNb();j++)
1983  {
1984  ScatteringPower *p2 = &(this->GetScatteringPowerRegistry().GetObj(j));
1985  if(oneScatteringPowerPerElement)
1986  {
1987  if(p1->GetClassName() != p2->GetClassName()) continue;
1988  if(p1->GetSymbol() != p2->GetSymbol()) continue;
1989  }
1990  else
1991  {
1992  if(*p1 != *p2) continue;
1993  }
1994  vequivpow[p1].insert(p2);
1995  vremovedpow.insert(p2);
1996  }
1997  }
1998  if(oneScatteringPowerPerElement)
1999  {
2000  // Average Biso and Bij
2001  for(std::map<ScatteringPower*,std::set<ScatteringPower*> >::iterator pos=vequivpow.begin();pos!=vequivpow.end();++pos)
2002  {
2003  if(pos->second.size()==0) continue;
2004  REAL b = pos->first->GetBiso();
2005  CrystVector_REAL bij(6);
2006  for(unsigned int i=0;i<6;i++) bij(i) = pos->first->GetBij(i);
2007  for(std::set<ScatteringPower*>::const_iterator pos2=pos->second.begin(); pos2!=pos->second.end();++pos2)
2008  {
2009  b += (*pos2)->GetBiso();
2010  for(unsigned int i=0;i<6;i++) bij(i) += (*pos2)->GetBij(i);
2011  }
2012  b /= pos->second.size() + 1;
2013  bij /= pos->second.size() + 1;
2014  pos->first->SetBiso(b);
2015  for(unsigned int i=0;i<6;i++) if(abs(bij(i)) > 1e-6) pos->first->SetBij(i,bij(i));
2016  }
2017  }
2018  // Update Atoms or MolAtoms with new ScatteringPower
2019  for(std::map<ScatteringPower*,std::set<ScatteringPower*> >::iterator pos=vequivpow.begin();pos!=vequivpow.end();++pos)
2020  {
2021  const unsigned int nb = pos->second.size();
2022  if(oneScatteringPowerPerElement) pos->first->SetName(pos->first->GetSymbol());
2023  if(nb>0)
2024  (*fpObjCrystInformUser)((boost::format("Merging ScatteringPower: %s[%s] (%d identical scattering powers)") % pos->first->GetName().c_str() % pos->first->GetSymbol().c_str() % pos->second.size()).str());
2025  for(std::set<ScatteringPower*>::const_iterator pos2=pos->second.begin(); pos2!=pos->second.end();++pos2)
2026  {
2027  for(unsigned int i=0;i<this->GetNbScatterer();++i)
2028  {
2029  Scatterer *p = &(this->GetScatt(i));
2030  if(p->GetClassName()=="Atom")
2031  {
2032  Atom *pat=dynamic_cast<Atom*>(p);
2033  if(&(pat->GetScatteringPower()) == (*pos2))
2034  {
2035  VFN_DEBUG_MESSAGE("Crystal:MergeEqualScatteringPowers() Atom "<<pat->GetName()<<": "<<pat->GetScatteringPower().GetName()<<"->"<<pos->first->GetName(), 10)
2036  pat->SetScatteringPower(*(pos->first));
2037  }
2038  }
2039  else if (p->GetClassName()=="Molecule")
2040  {
2041  Molecule *pmol=dynamic_cast<Molecule*>(p);
2042  for(std::vector<MolAtom*>::iterator pat=pmol->GetAtomList().begin();pat!=pmol->GetAtomList().end();++pat)
2043  {
2044  if(&((*pat)->GetScatteringPower()) == (*pos2))
2045  (*pat)->SetScatteringPower(*(pos->first));
2046  }
2047  }
2048  else
2049  {
2050  // This should only happen if a new type of scatterer was derived
2051  cout<<__FILE__<<":"<<__LINE__<<":Crystal::MergeEqualScatteringPowers(): unidentified scatterer, cannot merge scattering power..."
2052  <<(*pos2)->GetName()<<"["<<(*pos2)->GetClassName()<<"]"<<endl;
2053  }
2054  }
2055  }
2056  }
2057  // Delete duplicate scattering powers
2058  for(std::set<ScatteringPower*>::iterator pos=vremovedpow.begin();pos!=vremovedpow.end();++pos)
2059  {
2060  #ifdef __DEBUG__
2061  const unsigned int nb=(*pos)->GetClientRegistry().GetNb();
2062  if(nb>0)
2063  {
2064  VFN_DEBUG_MESSAGE("Crystal::MergeEqualScatteringPowers(): "<<nb<<" clients remaining for scattering power: "<<(*pos)->GetName()<<"["<<(*pos)->GetClassName()<<"]", 5)
2065  for(unsigned int i=0; i<nb;i++)
2066  {
2067  VFN_DEBUG_MESSAGE(" "<<&((*pos)->GetClientRegistry().GetObj(i))<<":"<<(*pos)->GetClientRegistry().GetObj(i).GetName()<<"["<<(*pos)->GetClientRegistry().GetObj(i).GetClassName()<<"]", 5)
2068  }
2069  }
2070  #endif
2071  this->RemoveScatteringPower(*pos,true);
2072  }
2073  this->UpdateDisplay();
2074  VFN_DEBUG_EXIT("Crystal::MergeEqualScatteringPowers()", 10)
2075 }
2076 
2078 {
2079  VFN_DEBUG_ENTRY("Crystal::InitOptions",10)
2080  static string UseDynPopCorrname;
2081  static string UseDynPopCorrchoices[2];
2082 
2083  static string DisplayEnantiomername;
2084  static string DisplayEnantiomerchoices[2];
2085 
2086  static bool needInitNames=true;
2087  if(true==needInitNames)
2088  {
2089  UseDynPopCorrname="Use Dynamical Occupancy Correction";
2090  UseDynPopCorrchoices[0]="No";
2091  UseDynPopCorrchoices[1]="Yes";
2092 
2093  DisplayEnantiomername="Display Enantiomer";
2094  DisplayEnantiomerchoices[0]="No";
2095  DisplayEnantiomerchoices[1]="Yes";
2096 
2097  needInitNames=false;//Only once for the class
2098  }
2099  VFN_DEBUG_MESSAGE("Crystal::Init(a,b,c,alpha,beta,gamma,Sg,name):Init options",5)
2100  mUseDynPopCorr.Init(2,&UseDynPopCorrname,UseDynPopCorrchoices);
2101  mUseDynPopCorr.SetChoice(1);
2102  this->AddOption(&mUseDynPopCorr);
2103 
2104  mDisplayEnantiomer.Init(2,&DisplayEnantiomername,DisplayEnantiomerchoices);
2105  mDisplayEnantiomer.SetChoice(0);
2106  this->AddOption(&mDisplayEnantiomer);
2107  VFN_DEBUG_EXIT("Crystal::InitOptions",10)
2108 }
2109 
2110 Crystal::Neighbour::Neighbour(const unsigned long neighbourIndex,const int sym,
2111  const REAL dist2):
2112 mNeighbourIndex(neighbourIndex),mNeighbourSymmetryIndex(sym),mDist2(dist2)
2113 {}
2114 
2115 Crystal::DistTableInternalPosition::DistTableInternalPosition(const long atomIndex, const int sym,
2116  const REAL x,const REAL y,const REAL z):
2117  mAtomIndex(atomIndex),mSymmetryIndex(sym),mX(x),mY(y),mZ(z)
2118  {}
2119 
2120 void Crystal::InitializeInterMolDistList() const
2121 {
2122  vector<int> p;
2123 
2124  GetNamedScatteringComponentList();
2125 
2126  for(long i=0;i<mInterMolDistList.size();i++) {
2127  mInterMolDistList[i].mAt1Indexes.clear();
2128  for(int j=0;j<mInterMolDistList[i].mAt1.size();j++) {
2129  p = FindScatterersInComponentList(mInterMolDistList[i].mAt1[j]);
2130  mInterMolDistList[i].mAt1Indexes.insert(mInterMolDistList[i].mAt1Indexes.end(), p.begin(), p.end());
2131  }
2132  mInterMolDistList[i].mAt2Indexes.clear();
2133  for(int j=0;j<mInterMolDistList[i].mAt2.size();j++) {
2134  p = FindScatterersInComponentList(mInterMolDistList[i].mAt2[j]);
2135  mInterMolDistList[i].mAt2Indexes.insert(mInterMolDistList[i].mAt2Indexes.end(), p.begin(), p.end());
2136  }
2137  }
2138  mInterMolDistListNeedsInit = false;
2139 }
2140 const vector<Crystal::NamedScatteringComponent>& Crystal::GetNamedScatteringComponentList() const
2141 {
2143 
2144  if(mNamedScattCompList.size()!=mScattCompList.GetNbComponent()) {
2145  mNamedScattCompList.resize(mScattCompList.GetNbComponent());
2146  }
2147  int counts = 0;
2148 
2149  //this part of code has to be derived from the GetScatteringComponentList() to be sure, that
2150  //mNamedScattCompList and mScattCompList have the same size!
2151  for(int i=0;i<mScattererRegistry.GetNb();i++) {
2152  const ScatteringComponentList list=this->GetScatt(i).GetScatteringComponentList();
2153  for(int j=0;j<list.GetNbComponent();j++) {
2154 
2155  mNamedScattCompList[counts].mDynPopCorr = list(j).mDynPopCorr;
2156  mNamedScattCompList[counts].mOccupancy = list(j).mOccupancy;
2157  mNamedScattCompList[counts].mpScattPow = list(j).mpScattPow;
2158  mNamedScattCompList[counts].mX = list(j).mX;
2159  mNamedScattCompList[counts].mY = list(j).mY;
2160  mNamedScattCompList[counts].mZ = list(j).mZ;
2161  mNamedScattCompList[counts].mName = this->GetScatt(i).GetComponentName(j);
2162  counts++;
2163  }
2164  }
2165  //this part of code has to be derived from the GetScatteringComponentList() to be sure, that
2166  //mNamedScattCompList and mScattCompList have the same size!
2167 
2168  return mNamedScattCompList;
2169 }
2170 void Crystal::printInterMolDistList() const
2171 {
2172  cout<<"Printing mInterMolDistList:"<<endl;
2173  cout<<"size: "<<mInterMolDistList.size()<<endl;
2174  for(int i=0;i<mInterMolDistList.size();i++) {
2175  cout<<"["<<i<<"]:"<<endl;
2176  cout<<"mAt1: ";
2177  for(int j=0;j<mInterMolDistList[i].mAt1.size();j++) {
2178  cout<<mInterMolDistList[i].mAt1[j]<<" ";
2179  }
2180  cout<<endl;
2181 
2182  cout<<"mAt1Indexes: ";
2183  for(int j=0;j<mInterMolDistList[i].mAt1Indexes.size();j++) {
2184  cout<<mInterMolDistList[i].mAt1Indexes[j]<<" ";
2185  }
2186  cout<<endl;
2187 
2188  cout<<"vUniqueIndexAt1: ";
2189  for(int j=0;j<mInterMolDistList[i].vUniqueIndexAt1.size();j++) {
2190  cout<<mInterMolDistList[i].vUniqueIndexAt1[j].mAtomIndex<<" ";
2191  }
2192  cout<<endl;
2193 
2194  cout<<"mAt2: ";
2195  for(int j=0;j<mInterMolDistList[i].mAt2.size();j++) {
2196  cout<<mInterMolDistList[i].mAt2[j]<<" ";
2197  }
2198  cout<<endl;
2199 
2200  cout<<"mAt2Indexes: ";
2201  for(int j=0;j<mInterMolDistList[i].mAt2Indexes.size();j++) {
2202  cout<<mInterMolDistList[i].mAt2Indexes[j]<<" ";
2203  }
2204  cout<<endl;
2205 
2206  cout<<"vPosAt2: ";
2207  for(int j=0;j<mInterMolDistList[i].vPosAt2.size();j++) {
2208  cout<<mInterMolDistList[i].vPosAt2[j].mAtomIndex<<" ";
2209  }
2210  cout<<endl;
2211 
2212  cout<<"mNbh: ";
2213  for(int j=0;j<mInterMolDistList[i].mNbh.size();j++) {
2214  cout<<"["<<j<<"]: mIndex: "<<mInterMolDistList[i].mNbh[j].mIndex<<endl;
2215  for(int k=0;k<mInterMolDistList[i].mNbh[j].mvNeighbour.size();k++) {
2216  cout<<" mDist2: "<<mInterMolDistList[i].mNbh[j].mvNeighbour[k].mDist2<<endl;
2217  cout<<" mNeighbourIndex: "<<mInterMolDistList[i].mNbh[j].mvNeighbour[k].mNeighbourIndex<<endl;
2218  cout<<" mNeighbourSymmetryIndex: "<<mInterMolDistList[i].mNbh[j].mvNeighbour[k].mNeighbourSymmetryIndex<<endl;
2219  }
2220  }
2221  cout<<endl;
2222 
2223  }
2224 
2225 }
2226 void Crystal::CalcDistTableForInterMolDistCost() const
2227 {
2228  if(mInterMolDistList.size()==0) return;
2229 
2231 
2233 
2234  if(mDistTableForInterMolMaxDistance<1.1) {
2235  //finding the maximal distance in the user-defined list
2236  mDistTableForInterMolMaxDistance = 1.0;
2237  for(int i=0;i<mInterMolDistList.size();i++) {
2238  if(mInterMolDistList[i].mDist2>0) {
2239  float d = sqrt(mInterMolDistList[i].mDist2);
2240  if(d>mDistTableForInterMolMaxDistance) {
2241  mDistTableForInterMolMaxDistance = d;
2242  }
2243  }
2244  }
2245  mDistTableForInterMolMaxDistance*=mDistMaxMultiplier;
2246  }
2247  //mDistTableForInterMolMaxDistance = 10;
2248  const long nbComponent=mScattCompList.GetNbComponent();
2249 
2250  // Get range and origin of the (pseudo) asymmetric unit
2251  const REAL asux0=this->GetSpaceGroup().GetAsymUnit().Xmin();
2252  const REAL asuy0=this->GetSpaceGroup().GetAsymUnit().Ymin();
2253  const REAL asuz0=this->GetSpaceGroup().GetAsymUnit().Zmin();
2254 
2255  const REAL asux1=this->GetSpaceGroup().GetAsymUnit().Xmax();
2256  const REAL asuy1=this->GetSpaceGroup().GetAsymUnit().Ymax();
2257  const REAL asuz1=this->GetSpaceGroup().GetAsymUnit().Zmax();
2258 
2259  const REAL halfasuxrange=(asux1-asux0)*0.5+1e-5;
2260  const REAL halfasuyrange=(asuy1-asuy0)*0.5+1e-5;
2261  const REAL halfasuzrange=(asuz1-asuz0)*0.5+1e-5;
2262 
2263  const REAL asuxc=0.5*(asux0+asux1);
2264  const REAL asuyc=0.5*(asuy0+asuy1);
2265  const REAL asuzc=0.5*(asuz0+asuz1);
2266 
2267  const REAL maxdx=halfasuxrange+mDistTableForInterMolMaxDistance/GetLatticePar(0);
2268  const REAL maxdy=halfasuyrange+mDistTableForInterMolMaxDistance/GetLatticePar(1);
2269  const REAL maxdz=halfasuzrange+mDistTableForInterMolMaxDistance/GetLatticePar(2);
2270 
2271  const REAL asymUnitMargin2 = mDistTableForInterMolMaxDistance*mDistTableForInterMolMaxDistance;
2272 
2273 
2274  // No need to loop on a,b,c translations if maxDist is small enough
2275  bool loopOnLattice=true;
2276  if( ((this->GetLatticePar(0)*.5)>mDistTableForInterMolMaxDistance)
2277  &&((this->GetLatticePar(1)*.5)>mDistTableForInterMolMaxDistance)
2278  &&((this->GetLatticePar(2)*.5)>mDistTableForInterMolMaxDistance)) loopOnLattice=false;
2279 
2280  CrystMatrix_REAL symmetricsCoords;
2281  const int nbSymmetrics=this->GetSpaceGroup().GetNbSymmetrics(false,false);
2282 
2283  //mInterMolDistList has to be initiallized first!
2284  if(mInterMolDistListNeedsInit) {
2285  //GetNamedScatteringComponentList(); is part of InitializeInterMolDistList(), we dont need to call it again...
2286  InitializeInterMolDistList();
2287  } else {
2288  //Update the mNamedScattCompList
2289  GetNamedScatteringComponentList();
2290  }
2291 
2292  //recalculation of mInterMolDistList
2293  for(long i=0;i<mInterMolDistList.size();i++) {
2294  mInterMolDistList[i].vUniqueIndexAt1.clear();
2295 
2296  //calculate equiv positions for all At1 atoms and identify which one is in ASU
2297  for(int k=0;k<mInterMolDistList[i].mAt1Indexes.size();k++) {
2298 
2299  symmetricsCoords=this->GetSpaceGroup().GetAllSymmetrics(mNamedScattCompList[mInterMolDistList[i].mAt1Indexes[k]].mX,
2300  mNamedScattCompList[mInterMolDistList[i].mAt1Indexes[k]].mY,
2301  mNamedScattCompList[mInterMolDistList[i].mAt1Indexes[k]].mZ,
2302  false,false,false);
2303 
2304  bool hasUnique=false;
2305  for(int j=0;j<nbSymmetrics;j++)
2306  {
2307  // take the closest position (using lattice translations) to the center of the ASU
2308  REAL x=fmod(symmetricsCoords(j,0)-asuxc,(REAL)1.0);if(x<-.5)x+=1;else if(x>.5)x-=1;
2309  REAL y=fmod(symmetricsCoords(j,1)-asuyc,(REAL)1.0);if(y<-.5)y+=1;else if(y>.5)y-=1;
2310  REAL z=fmod(symmetricsCoords(j,2)-asuzc,(REAL)1.0);if(z<-.5)z+=1;else if(z>.5)z-=1;
2311 
2312  //cout<<i<<","<<j<<":"<<FormatFloat(x,8,5)<<","<<FormatFloat(y,8,5)<<","<<FormatFloat(z,8,5)<<endl;
2313  if( (abs(x)<maxdx) && (abs(y)<maxdy) && (abs(z)<maxdz) ) {
2314  // Get one reference atom strictly within the pseudo-ASU
2315  if(!hasUnique) {
2316  if( (abs(x)<halfasuxrange) && (abs(y)<halfasuyrange) && (abs(z)<halfasuzrange) )
2317  {
2318  hasUnique=true;
2319  mInterMolDistList[i].vUniqueIndexAt1.push_back(DistTableInternalPosition(mInterMolDistList[i].mAt1Indexes[k], j, x+asuxc, y+asuyc, z+asuzc));
2320  }
2321  }
2322  }
2323  }
2324  if(!hasUnique)
2325  {
2326  throw ObjCrystException("One atom did not have any symmetric in the ASU !");
2327  }
2328  }
2329  mInterMolDistList[i].vPosAt2.clear();
2330 
2331  //calculate equiv positions for all At2 atoms and save it
2332  for(int k=0;k<mInterMolDistList[i].mAt2Indexes.size();k++) {
2333 
2334  symmetricsCoords=this->GetSpaceGroup().GetAllSymmetrics(mNamedScattCompList[mInterMolDistList[i].mAt2Indexes[k]].mX,
2335  mNamedScattCompList[mInterMolDistList[i].mAt2Indexes[k]].mY,
2336  mNamedScattCompList[mInterMolDistList[i].mAt2Indexes[k]].mZ,
2337  false,false,false);
2338  for(int j=0;j<nbSymmetrics;j++)
2339  {
2340  // take the closest position (using lattice translations) to the center of the ASU
2341  REAL x=fmod(symmetricsCoords(j,0)-asuxc,(REAL)1.0);if(x<-.5)x+=1;else if(x>.5)x-=1;
2342  REAL y=fmod(symmetricsCoords(j,1)-asuyc,(REAL)1.0);if(y<-.5)y+=1;else if(y>.5)y-=1;
2343  REAL z=fmod(symmetricsCoords(j,2)-asuzc,(REAL)1.0);if(z<-.5)z+=1;else if(z>.5)z-=1;
2344 
2345  //cout<<i<<","<<j<<":"<<FormatFloat(x,8,5)<<","<<FormatFloat(y,8,5)<<","<<FormatFloat(z,8,5)<<endl;
2346  if( (abs(x)<maxdx) && (abs(y)<maxdy) && (abs(z)<maxdz) ) {
2347  mInterMolDistList[i].vPosAt2.push_back(DistTableInternalPosition(mInterMolDistList[i].mAt2Indexes[k], j, x+asuxc, y+asuyc, z+asuzc));
2348  }
2349  }
2350  }
2351 
2352  }
2353 
2354  const CrystMatrix_REAL* pOrthMatrix=&(this->GetOrthMatrix());
2355 
2356  const REAL m00=(*pOrthMatrix)(0,0);
2357  const REAL m01=(*pOrthMatrix)(0,1);
2358  const REAL m02=(*pOrthMatrix)(0,2);
2359  const REAL m11=(*pOrthMatrix)(1,1);
2360  const REAL m12=(*pOrthMatrix)(1,2);
2361  const REAL m22=(*pOrthMatrix)(2,2);
2362 
2363 
2364  for(long i=0;i<mInterMolDistList.size();i++)
2365  {
2366  mInterMolDistList[i].mNbh.clear();
2367  //search for distances between At1 and At2 atoms
2368  for(long q=0;q<mInterMolDistList[i].vUniqueIndexAt1.size();q++) {
2369  NeighbourHood nbh;
2370  nbh.mIndex = mInterMolDistList[i].vUniqueIndexAt1[q].mAtomIndex;
2371  nbh.mUniquePosSymmetryIndex = mInterMolDistList[i].vUniqueIndexAt1[q].mSymmetryIndex;
2372  //mImdTable.push_back(nbh);
2373  mInterMolDistList[i].mNbh.push_back(nbh);
2374 
2375  //std::vector<Crystal::Neighbour> * const vnb=&(mImdTable[mImdTable.size()-1].mvNeighbour);
2376  vector<Crystal::Neighbour> * const vnb=&(mInterMolDistList[i].mNbh[mInterMolDistList[i].mNbh.size()-1].mvNeighbour);
2377  const REAL x0i=mInterMolDistList[i].vUniqueIndexAt1[q].mX;
2378  const REAL y0i=mInterMolDistList[i].vUniqueIndexAt1[q].mY;
2379  const REAL z0i=mInterMolDistList[i].vUniqueIndexAt1[q].mZ;
2380  for(unsigned long j=0;j<mInterMolDistList[i].vPosAt2.size();j++)
2381  {
2382  //if((mInterMolDistList[i].vUniqueIndexAt1[q]==j) && (!loopOnLattice)) continue;// distance to self !
2383  // Start with the smallest absolute coordinates possible
2384  REAL x=fmod(mInterMolDistList[i].vPosAt2[j].mX - x0i,(REAL)1.0);if(x<-.5)x+=1;if(x>.5)x-=1;
2385  REAL y=fmod(mInterMolDistList[i].vPosAt2[j].mY - y0i,(REAL)1.0);if(y<-.5)y+=1;if(y>.5)y-=1;
2386  REAL z=fmod(mInterMolDistList[i].vPosAt2[j].mZ - z0i,(REAL)1.0);if(z<-.5)z+=1;if(z>.5)z-=1;
2387 
2388  const REAL x0=m00 * x + m01 * y + m02 * z;
2389  const REAL y0= m11 * y + m12 * z;
2390  const REAL z0= m22 * z;
2391 
2392  if(loopOnLattice)// distance to self !
2393  {//Now loop over lattice translations
2394  for(int sz=-1;sz<=1;sz+=2)// Sign of translation
2395  {
2396  for(int nz=(sz+1)/2;;++nz)
2397  {
2398  const REAL z=z0+sz*nz*m22;
2399  if(abs(z)>mDistTableForInterMolMaxDistance) break;
2400  for(int sy=-1;sy<=1;sy+=2)// Sign of translation
2401  {
2402  for(int ny=(sy+1)/2;;++ny)
2403  {
2404  const REAL y=y0 + sy*ny*m11 + sz*nz*m12;
2405  if(abs(y)>mDistTableForInterMolMaxDistance) break;
2406  for(int sx=-1;sx<=1;sx+=2)// Sign of translation
2407  {
2408  for(int nx=(sx+1)/2;;++nx)
2409  {
2410  //if((vUniqueIndex[mImdTable[i].mIndex]==j) && (nx==0) && (ny==0) && (nz==0)) continue;// distance to self !
2411  const REAL x=x0 + sx*nx*m00 + sy*ny*m01 + sz*nz*m02;
2412  if(abs(x)>mDistTableForInterMolMaxDistance) break;
2413  const REAL d2=x*x+y*y+z*z;
2414  if(d2<0.001) continue; // distance to self !
2415  if(d2<=asymUnitMargin2)
2416  {
2417  Neighbour neigh(mInterMolDistList[i].vPosAt2[j].mAtomIndex,mInterMolDistList[i].vPosAt2[j].mSymmetryIndex,d2);
2418  vnb->push_back(neigh);
2419  #if 0
2420  if(!this->IsBeingRefined()) cout<<" "<<vPos[j].mAtomIndex<<":"
2421  <<mScattCompList(vPos[j].mAtomIndex).mpScattPow->GetName()<<":"
2422  <<vPos[j].mSymmetryIndex<<":"
2423  <<FormatFloat(vPos[j].mX,8,5)<<","
2424  <<FormatFloat(vPos[j].mY,8,5)<<","<<","
2425  <<FormatFloat(vPos[j].mZ,8,5)<<","<<" vector="
2426  <<FormatFloat(x,8,5)<<","
2427  <<FormatFloat(y,8,5)<<","
2428  <<FormatFloat(z,8,5)<<":"<<sqrt(d2)<<","
2429  <<"("<<sx*nx<<","<<sy*ny<<","<<sz*nz<<")"<<endl;
2430  #endif
2431  }
2432  }
2433  }
2434  }
2435  }
2436  }
2437  }
2438  }
2439  else
2440  {
2441  const REAL d2=x0*x0+y0*y0+z0*z0;
2442  if(d2<=asymUnitMargin2)
2443  {
2444  Neighbour neigh(mInterMolDistList[i].vPosAt2[j].mAtomIndex,mInterMolDistList[i].vPosAt2[j].mSymmetryIndex,d2);
2445  vnb->push_back(neigh);
2446  #if 0
2447  if(!this->IsBeingRefined()) cout<<vPos[j].mAtomIndex<<":"
2448  <<mScattCompList(vPos[j].mAtomIndex).mpScattPow->GetName()<<":"
2449  <<vPos[j].mSymmetryIndex<<":"
2450  <<vPos[j].mX<<","
2451  <<vPos[j].mY<<","
2452  <<vPos[j].mZ<<" vector="
2453  <<x0<<","<<y0<<","<<z0<<":"<<sqrt(d2)<<","<<asymUnitMargin2<<endl;
2454  #endif
2455  }
2456  }
2457 
2458  }
2459  }
2460 
2461  }
2462  //printInterMolDistList();
2464 }
2465 void Crystal::CalcDistTable(const bool fast) const
2466 {
2468  if(!this->IsBeingRefined())
2469  {
2472  }
2473 
2475  &&(mDistTableClock>this->GetClockMetricMatrix())) return;
2476  VFN_DEBUG_ENTRY("Crystal::CalcDistTable(fast="<<fast<<"),maxDist="<<mDistTableMaxDistance,4)
2477 
2478  const long nbComponent=mScattCompList.GetNbComponent();
2479 
2480  mvDistTableSq.resize(nbComponent);
2481  {
2482  std::vector<NeighbourHood>::iterator pos;
2483  for(pos=mvDistTableSq.begin();pos<mvDistTableSq.end();pos++)
2484  pos->mvNeighbour.clear();
2485  }
2486  VFN_DEBUG_MESSAGE("Crystal::CalcDistTable():1",3)
2487 
2488  // Get range and origin of the (pseudo) asymmetric unit
2489  const REAL asux0=this->GetSpaceGroup().GetAsymUnit().Xmin();
2490  const REAL asuy0=this->GetSpaceGroup().GetAsymUnit().Ymin();
2491  const REAL asuz0=this->GetSpaceGroup().GetAsymUnit().Zmin();
2492 
2493  const REAL asux1=this->GetSpaceGroup().GetAsymUnit().Xmax();
2494  const REAL asuy1=this->GetSpaceGroup().GetAsymUnit().Ymax();
2495  const REAL asuz1=this->GetSpaceGroup().GetAsymUnit().Zmax();
2496 
2497  const REAL halfasuxrange=(asux1-asux0)*0.5+1e-5;
2498  const REAL halfasuyrange=(asuy1-asuy0)*0.5+1e-5;
2499  const REAL halfasuzrange=(asuz1-asuz0)*0.5+1e-5;
2500 
2501  const REAL asuxc=0.5*(asux0+asux1);
2502  const REAL asuyc=0.5*(asuy0+asuy1);
2503  const REAL asuzc=0.5*(asuz0+asuz1);
2504 
2505  const REAL maxdx=halfasuxrange+mDistTableMaxDistance/GetLatticePar(0);
2506  const REAL maxdy=halfasuyrange+mDistTableMaxDistance/GetLatticePar(1);
2507  const REAL maxdz=halfasuzrange+mDistTableMaxDistance/GetLatticePar(2);
2508 
2509  // List of all positions within or near the first atom generated
2510  std::vector<DistTableInternalPosition> vPos;
2511  // index of unique atoms in vPos, which are strictly in the asymmetric unit
2512  std::vector<unsigned long> vUniqueIndex(nbComponent);
2513 
2514  const REAL asymUnitMargin2 = mDistTableMaxDistance*mDistTableMaxDistance;
2515 
2516  if(true)//(true==fast)
2517  {
2518  VFN_DEBUG_MESSAGE("Crystal::CalcDistTable(fast):2",3)
2519  TAU_PROFILE("Crystal::CalcDistTable(fast=true)","Matrix (string&)",TAU_DEFAULT);
2520  TAU_PROFILE_TIMER(timer1,"DiffractionData::CalcDistTable1","", TAU_FIELD);
2521  TAU_PROFILE_TIMER(timer2,"DiffractionData::CalcDistTable2","", TAU_FIELD);
2522 
2523  TAU_PROFILE_START(timer1);
2524 
2525  // No need to loop on a,b,c translations if mDistTableMaxDistance is small enough
2526  bool loopOnLattice=true;
2527  if( ((this->GetLatticePar(0)*.5)>mDistTableMaxDistance)
2528  &&((this->GetLatticePar(1)*.5)>mDistTableMaxDistance)
2529  &&((this->GetLatticePar(2)*.5)>mDistTableMaxDistance)) loopOnLattice=false;
2530 
2531  CrystMatrix_REAL symmetricsCoords;
2532 
2533  const int nbSymmetrics=this->GetSpaceGroup().GetNbSymmetrics(false,false);
2534 
2535  // Get the list of all atoms within or near the asymmetric unit
2536  for(long i=0;i<nbComponent;i++)
2537  {
2538  VFN_DEBUG_MESSAGE("Crystal::CalcDistTable(fast):3:component "<<i,0)
2539  // generate all symmetrics, excluding translations
2540  symmetricsCoords=this->GetSpaceGroup().GetAllSymmetrics(mScattCompList(i).mX,
2541  mScattCompList(i).mY,
2542  mScattCompList(i).mZ,
2543  false,false,false);
2544  mvDistTableSq[i].mIndex=i;//USELESS ?
2545  bool hasUnique=false;
2546  for(int j=0;j<nbSymmetrics;j++)
2547  {
2548  // take the closest position (using lattice translations) to the center of the ASU
2549  REAL x=fmod(symmetricsCoords(j,0)-asuxc,(REAL)1.0);if(x<-.5)x+=1;else if(x>.5)x-=1;
2550  REAL y=fmod(symmetricsCoords(j,1)-asuyc,(REAL)1.0);if(y<-.5)y+=1;else if(y>.5)y-=1;
2551  REAL z=fmod(symmetricsCoords(j,2)-asuzc,(REAL)1.0);if(z<-.5)z+=1;else if(z>.5)z-=1;
2552 
2553  //cout<<i<<","<<j<<":"<<FormatFloat(x,8,5)<<","<<FormatFloat(y,8,5)<<","<<FormatFloat(z,8,5)<<endl;
2554  if( (abs(x)<maxdx) && (abs(y)<maxdy) && (abs(z)<maxdz) )
2555  vPos.push_back(DistTableInternalPosition(i, j, x+asuxc, y+asuyc, z+asuzc));
2556  // Get one reference atom strictly within the pseudo-ASU
2557  if(!hasUnique)
2558  if( (abs(x)<halfasuxrange) && (abs(y)<halfasuyrange) && (abs(z)<halfasuzrange) )
2559  {
2560  hasUnique=true;
2561  vUniqueIndex[i]=vPos.size()-1;
2562  mvDistTableSq[i].mUniquePosSymmetryIndex=j;
2563  }
2564  }
2565  if(!hasUnique)
2566  {
2567  throw ObjCrystException("One atom did not have any symmetric in the ASU !");
2568  }
2569  }
2570  TAU_PROFILE_STOP(timer1);
2571  TAU_PROFILE_START(timer2);
2572  // Compute interatomic vectors & distance
2573  // between (i) unique atoms and (ii) all remaining atoms
2574 
2575  const CrystMatrix_REAL* pOrthMatrix=&(this->GetOrthMatrix());
2576 
2577  const REAL m00=(*pOrthMatrix)(0,0);
2578  const REAL m01=(*pOrthMatrix)(0,1);
2579  const REAL m02=(*pOrthMatrix)(0,2);
2580  const REAL m11=(*pOrthMatrix)(1,1);
2581  const REAL m12=(*pOrthMatrix)(1,2);
2582  const REAL m22=(*pOrthMatrix)(2,2);
2583 
2584  for(long i=0;i<nbComponent;i++)
2585  {
2586  VFN_DEBUG_MESSAGE("Crystal::CalcDistTable(fast):4:component "<<i,0)
2587  #if 0
2588  if(!this->IsBeingRefined()) cout<<endl<<"Unique pos:"<<vUniqueIndex[i]<<":"
2589  <<vPos[vUniqueIndex[i]].mAtomIndex<<":"
2590  <<mScattCompList(vPos[vUniqueIndex[i]].mAtomIndex).mpScattPow->GetName()<<":"
2591  <<vPos[vUniqueIndex[i]].mSymmetryIndex<<":"
2592  <<FormatFloat(vPos[vUniqueIndex[i]].mX,8,5)<<","
2593  <<FormatFloat(vPos[vUniqueIndex[i]].mY,8,5)<<","
2594  <<FormatFloat(vPos[vUniqueIndex[i]].mZ,8,5)<<endl;
2595  #endif
2596  std::vector<Crystal::Neighbour> * const vnb=&(mvDistTableSq[i].mvNeighbour);
2597  const REAL x0i=vPos[vUniqueIndex[i] ].mX;
2598  const REAL y0i=vPos[vUniqueIndex[i] ].mY;
2599  const REAL z0i=vPos[vUniqueIndex[i] ].mZ;
2600  for(unsigned long j=0;j<vPos.size();j++)
2601  {
2602  if((vUniqueIndex[i]==j) && (!loopOnLattice)) continue;// distance to self !
2603  // Start with the smallest absolute coordinates possible
2604  REAL x=fmod(vPos[j].mX - x0i,(REAL)1.0);if(x<-.5)x+=1;if(x>.5)x-=1;
2605  REAL y=fmod(vPos[j].mY - y0i,(REAL)1.0);if(y<-.5)y+=1;if(y>.5)y-=1;
2606  REAL z=fmod(vPos[j].mZ - z0i,(REAL)1.0);if(z<-.5)z+=1;if(z>.5)z-=1;
2607 
2608  const REAL x0=m00 * x + m01 * y + m02 * z;
2609  const REAL y0= m11 * y + m12 * z;
2610  const REAL z0= m22 * z;
2611 
2612  if(loopOnLattice)// distance to self !
2613  {//Now loop over lattice translations
2614  for(int sz=-1;sz<=1;sz+=2)// Sign of translation
2615  {
2616  for(int nz=(sz+1)/2;;++nz)
2617  {
2618  const REAL z=z0+sz*nz*m22;
2619  if(abs(z)>mDistTableMaxDistance) break;
2620  for(int sy=-1;sy<=1;sy+=2)// Sign of translation
2621  {
2622  for(int ny=(sy+1)/2;;++ny)
2623  {
2624  const REAL y=y0 + sy*ny*m11 + sz*nz*m12;
2625  if(abs(y)>mDistTableMaxDistance) break;
2626  for(int sx=-1;sx<=1;sx+=2)// Sign of translation
2627  {
2628  for(int nx=(sx+1)/2;;++nx)
2629  {
2630  if((vUniqueIndex[i]==j) && (nx==0) && (ny==0) && (nz==0)) continue;// distance to self !
2631  const REAL x=x0 + sx*nx*m00 + sy*ny*m01 + sz*nz*m02;
2632  if(abs(x)>mDistTableMaxDistance) break;
2633  const REAL d2=x*x+y*y+z*z;
2634  if(d2<=asymUnitMargin2)
2635  {
2636  Neighbour neigh(vPos[j].mAtomIndex,vPos[j].mSymmetryIndex,d2);
2637  vnb->push_back(neigh);
2638  #if 0
2639  if(!this->IsBeingRefined()) cout<<" "<<vPos[j].mAtomIndex<<":"
2640  <<mScattCompList(vPos[j].mAtomIndex).mpScattPow->GetName()<<":"
2641  <<vPos[j].mSymmetryIndex<<":"
2642  <<FormatFloat(vPos[j].mX,8,5)<<","
2643  <<FormatFloat(vPos[j].mY,8,5)<<","<<","
2644  <<FormatFloat(vPos[j].mZ,8,5)<<","<<" vector="
2645  <<FormatFloat(x,8,5)<<","
2646  <<FormatFloat(y,8,5)<<","
2647  <<FormatFloat(z,8,5)<<":"<<sqrt(d2)<<","
2648  <<"("<<sx*nx<<","<<sy*ny<<","<<sz*nz<<")"<<endl;
2649  #endif
2650  }
2651  }
2652  }
2653  }
2654  }
2655  }
2656  }
2657  }
2658  else
2659  {
2660  const REAL d2=x0*x0+y0*y0+z0*z0;
2661  if(d2<=asymUnitMargin2)
2662  {
2663  Neighbour neigh(vPos[j].mAtomIndex,vPos[j].mSymmetryIndex,d2);
2664  vnb->push_back(neigh);
2665  #if 0
2666  if(!this->IsBeingRefined()) cout<<vPos[j].mAtomIndex<<":"
2667  <<mScattCompList(vPos[j].mAtomIndex).mpScattPow->GetName()<<":"
2668  <<vPos[j].mSymmetryIndex<<":"
2669  <<vPos[j].mX<<","
2670  <<vPos[j].mY<<","
2671  <<vPos[j].mZ<<" vector="
2672  <<x0<<","<<y0<<","<<z0<<":"<<sqrt(d2)<<","<<asymUnitMargin2<<endl;
2673  #endif
2674  }
2675  }
2676 
2677  }
2678  }
2679  TAU_PROFILE_STOP(timer2);
2680  }
2682  VFN_DEBUG_EXIT("Crystal::CalcDistTable()",4)
2683 }
2684 
2686  mDeleteSubObjInDestructor=b;
2687 }
2688 
2689 #ifdef __WX__CRYST__
2690 WXCrystObjBasic* Crystal::WXCreate(wxWindow* parent)
2691 {
2692  VFN_DEBUG_ENTRY("Crystal::WXCreate(wxWindow*)",6)
2693  //:TODO: Check mpWXCrystObj==0
2694  mpWXCrystObj=new WXCrystal(parent,this);
2695  VFN_DEBUG_EXIT("Crystal::WXCreate(wxWindow*)",6)
2696  return mpWXCrystObj;
2697 }
2698 #endif
2699 
2700 }//namespace
The namespace which includes all objects (crystallographic and algorithmic) in ObjCryst++.
Definition: doc-main.h:25
REAL GetBondLength(const MolAtom &at1, const MolAtom &at2)
Get The Bond Length between two atoms.
Definition: Molecule.cpp:62
REAL GetBondAngle(const MolAtom &at1, const MolAtom &at2, const MolAtom &at3)
Get The Bond Angle of 3 atoms.
Definition: Molecule.cpp:98
ObjRegistry< Crystal > gCrystalRegistry("List of all Crystals")
Global registry for all Crystal objects.
Definition: Crystal.h:669
ObjRegistry< RefinableObj > gTopRefinableObjRegistry("Global Top RefinableObj registry")
This is a special registry for 'top' object for an optimization.
The basic atom scatterer, in a crystal.
Definition: Atom.h:58
void SetScatteringPower(const ScatteringPower &pow)
Change the ScatteringPower for this atom.
Definition: Atom.cpp:487
const ScatteringPower & GetScatteringPower() const
Get the ScatteringPowerAtom corresponding to this atom.
Definition: Atom.cpp:484
Crystal class: Unit cell, spacegroup, scatterers.
Definition: Crystal.h:98
void ResetDynPopCorr() const
Reset Dynamical Population Correction factors (ie set it to 1)
Definition: Crystal.cpp:833
RefinableObjClock mMasterClockScatteringPower
master clock recording every change in Scattering Powers
Definition: Crystal.h:632
virtual void CIFOutput(ostream &os, double mindist=0.5) const
output Crystal structure as a cif file
Definition: Crystal.cpp:1234
~Crystal()
Crystal destructor.
Definition: Crystal.cpp:145
virtual void XMLOutput(ostream &os, int indent=0) const
Output to stream in well-formed XML.
REAL GetBondValenceCost() const
Get the Bond-Valence cost function, which compares the expected valence to the one computed from Bond...
Definition: Crystal.cpp:1531
ostream & POVRayDescription(ostream &os, const CrystalPOVRayOptions &options) const
XMLOutput POV-Ray Description for this Crystal.
Definition: Crystal.cpp:529
RefinableObjClock mClockDynPopCorr
Definition: Crystal.h:630
CrystMatrix_REAL GetMinDistanceTable(const REAL minDistance=0.1) const
Minimum interatomic distance between all scattering components (atoms) in the crystal.
Definition: Crystal.cpp:455
ScatteringComponentList mScattCompList
The list of all scattering components in the crystal.
Definition: Crystal.h:611
RefinableObjClock mBondValenceParClock
Last Time Bond Valence parameters were changed.
Definition: Crystal.h:644
REAL mBondValenceCostScale
Bond Valence cost scale factor.
Definition: Crystal.h:652
RefinableObjClock mBondValenceCalcClock
Last time Bond Valences were calculated.
Definition: Crystal.h:646
void CalcDistTable(const bool fast) const
Compute the distance Table (mDistTable) for all scattering components.
Definition: Crystal.cpp:2465
ScatteringPower & GetScatteringPower(const string &name)
Find a ScatteringPower from its name. Names must be unique in a given Crystal.
Definition: Crystal.cpp:284
void PrintMinDistanceTable(const REAL minDistance=0.1, ostream &os=cout) const
Print the minimum distance table between all scattering centers (atoms) in the crystal.
Definition: Crystal.cpp:496
std::map< long, REAL > mvBondValenceCalc
List of calculated bond valences, as a map, the key being the index of the atom in Crystal::mScattCom...
Definition: Crystal.h:655
Crystal()
Default Constructor.
Definition: Crystal.cpp:57
ObjRegistry< Scatterer > & GetScattererRegistry()
Get the registry of scatterers.
Definition: Crystal.cpp:232
void SetUseDynPopCorr(const int use)
Set the use of dynamical population correction (Crystal::mUseDynPopCorr).
Definition: Crystal.cpp:859
RefinableObjClock mBumpMergeCostClock
Last Time Anti-bump parameters were changed.
Definition: Crystal.h:569
virtual const ScatteringComponentList & GetScatteringComponentList() const
Get the list of all scattering components.
Definition: Crystal.cpp:298
virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type=gpRefParTypeObjCryst)
Make a random move of the current configuration.
Definition: Crystal.cpp:1198
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 InitOptions()
Init options.
Definition: Crystal.cpp:2077
RefinableObjClock mDistTableForInterMolDistClock
The time when the distance table was last calculated.
Definition: Crystal.h:590
int GetUseDynPopCorr() const
Get dynamical population correction setting.
Definition: Crystal.cpp:866
void AddScatteringPower(ScatteringPower *scattPow)
Add a ScatteringPower for this Crystal.
Definition: Crystal.cpp:241
int FindScatterer(const string &scattName) const
Find a scatterer (its index # in mpScatterrer[]) with a given name.
Definition: Crystal.cpp:871
const RefinableObjClock & GetClockScattererList() const
When was the list of scatterers last changed ?
Definition: Crystal.cpp:1196
RefinableObjClock mClockScattererList
Last time the list of Scatterers was changed.
Definition: Crystal.h:624
ObjRegistry< ScatteringPower > mScatteringPowerRegistry
The registry of ScatteringPower for this Crystal.
Definition: Crystal.h:620
map< pair< const ScatteringPower *, const ScatteringPower * >, REAL > mvBondValenceRo
Map of Bond Valence "Ro" parameters for each couple of ScatteringPower.
Definition: Crystal.h:642
void CalcBondValenceSum() const
Calculate all Bond Valences.
Definition: Crystal.cpp:1565
virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false)
This should be called by any optimization class at the begining of an optimization.
Definition: Crystal.cpp:1468
RefinableObjClock mClockNeighborTable
Definition: Crystal.h:628
void MergeEqualScatteringPowers(const bool oneScatteringPowerPerElement)
Merge all equal scattering powers.
Definition: Crystal.cpp:1971
REAL GetWeight() const
Weight for the crystal formula, in atomic units (g/mol).
Definition: Crystal.cpp:438
REAL mDistTableMaxDistance
The distance up to which the distance table & neighbours needs to be calculated.
Definition: Crystal.h:604
REAL GetDynPopCorr(const Scatterer *pscatt, unsigned int component) const
Access the Dynamical Occupancy Correction for a given component (atom) in a given Scatterer.
Definition: Crystal.cpp:841
ObjRegistry< Scatterer > mScattererRegistry
The registry of scatterers for this UnitCell.
Definition: Crystal.h:559
VBumpMergePar mvBumpMergePar
Anti-bump parameters map.
Definition: Crystal.h:562
ObjRegistry< ScatteringPower > & GetScatteringPowerRegistry()
Get the registry of ScatteringPower included in this Crystal.
Definition: Crystal.cpp:236
const RefinableObjClock & GetClockScattCompList() const
Get the list of all scattering components.
Definition: Crystal.cpp:335
REAL GetBumpMergeCost() const
Get the Anti-bumping/pro-Merging cost function.
Definition: Crystal.cpp:938
RefinableObjClock mBumpMergeParClock
Last Time Anti-bump parameters were changed.
Definition: Crystal.h:567
RefObjOpt mUseDynPopCorr
Use Dynamical population correction (ScatteringComponent::mDynPopCorr) during Structure factor calcul...
Definition: Crystal.h:617
RefObjOpt mDisplayEnantiomer
Display the enantiomeric (mirror along x) structure in 3D? This can be helpful for non-centrosymmetri...
Definition: Crystal.h:637
virtual const string & GetClassName() const
Name for this class ("RefinableObj", "Crystal",...).
Definition: Crystal.cpp:182
Scatterer & GetScatt(const string &scattName)
Provides an access to the scatterers.
Definition: Crystal.cpp:212
void RemoveScatteringPower(ScatteringPower *scattPow, const bool del=true)
Remove a ScatteringPower for this Crystal.
Definition: Crystal.cpp:251
void RemoveBumpMergeDistance(const ScatteringPower &scatt1, const ScatteringPower &scatt2)
Remove an Anti-bumping distance between two scattering types.
Definition: Crystal.cpp:997
void RemoveScatterer(Scatterer *scatt, const bool del=true)
Remove a Scatterer. This also deletes the scatterer unless del=false.
Definition: Crystal.cpp:199
RefinableObjClock mClockScattCompList
Definition: Crystal.h:626
std::string GetFormula() const
Formula with atoms in alphabetic order.
Definition: Crystal.cpp:405
virtual void XMLInput(istream &is, const XMLCrystTag &tag)
Input the crystal structure from a stream.
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
REAL mBumpMergeCost
Current bump-merge cost.
Definition: Crystal.h:571
RefinableObjClock mDistTableClock
The time when the distance table was last calculated.
Definition: Crystal.h:602
void SetBumpMergeDistance(const ScatteringPower &scatt1, const ScatteringPower &scatt2, const REAL dist=1.5)
Set the Anti-bumping distance between two scattering types.
Definition: Crystal.cpp:978
virtual REAL GetLogLikelihood() const
Get -log(likelihood) of the current configuration for the object.
Definition: Crystal.cpp:1229
RefinableObjClock mLatticeClock
Clock for lattice paramaters.
Definition: Crystal.h:614
void CalcDynPopCorr(const REAL overlapDist=1., const REAL mergeDist=.0) const
Compute the 'Dynamical population correction for all atoms. Atoms which are considered "equivalent" (...
Definition: Crystal.cpp:776
RefinableObjClock mBondValenceCostClock
Last time the Bond Valence cost was calculated.
Definition: Crystal.h:648
void SetDeleteSubObjInDestructor(const bool b)
Set whether to delete the Scatterers and ScatteringPowers in the destructor.
Definition: Crystal.cpp:2685
REAL mBumpMergeScale
Bump-merge scale factor.
Definition: Crystal.h:573
virtual void GetGeneGroup(const RefinableObj &obj, CrystVector_uint &groupIndex, unsigned int &firstGroup) const
Get the gene group assigned to each parameter.
Definition: Crystal.cpp:1449
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
std::map< pair< const ScatteringPower *, const ScatteringPower * >, Crystal::BumpMergePar > VBumpMergePar
Anti-bump parameters.
Definition: Crystal.h:337
REAL mBondValenceCost
Current Bond Valence cost.
Definition: Crystal.h:650
const RefinableObjClock & GetMasterClockScatteringPower() const
Get the clock which reports all changes in ScatteringPowers.
Definition: Crystal.cpp:294
Storage for anti-bump/merge parameters.
Definition: Crystal.h:322
Exception class for ObjCryst++ library.
Definition: General.h:122
Class to store POV-Ray output options.
Definition: General.h:178
MolAtom : atom inside a Molecule.
Definition: Molecule.h:59
Bond between two atoms, also a restraint on the associated bond length.
Definition: Molecule.h:165
Molecule : class for complex scatterer descriptions using cartesian coordinates with bond length/angl...
Definition: Molecule.h:760
void AddBondAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3, const REAL angle, const REAL sigma, const REAL delta, const bool updateDisplay=true)
Add a bond angle restraint.
Definition: Molecule.cpp:4041
void BuildConnectivityTable() const
Build the Connectivity table.
Definition: Molecule.cpp:5369
vector< MolBondAngle * >::const_iterator FindBondAngle(const MolAtom &at1, const MolAtom &at0, const MolAtom &at2) const
Searches whether a bond between three atoms already exists, searching for either (at1,...
Definition: Molecule.cpp:4072
vector< MolAtom * >::iterator RemoveAtom(MolAtom &, const bool del=true)
Remove an atom.
Definition: Molecule.cpp:3932
vector< MolBond * >::const_iterator FindBond(const MolAtom &, const MolAtom &) const
Searches whether a bond between two atoms already exists.
Definition: Molecule.cpp:4020
void AddAtom(const REAL x, const REAL y, const REAL z, const ScatteringPower *pPow, const string &name, const bool updateDisplay=true)
Add an atom.
Definition: Molecule.cpp:3876
virtual int GetNbComponent() const
Number of components in the scatterer (eg number of point scatterers)
Definition: Molecule.cpp:3240
std::string GetFormula() const
Formula with atoms in alphabetic order.
Definition: Molecule.cpp:2193
vector< MolBond * >::iterator RemoveBond(const MolBond &, const bool del=true)
Remove a bond.
Definition: Molecule.cpp:4001
void AddBond(MolAtom &atom1, MolAtom &atom2, const REAL length, const REAL sigma, const REAL delta, const REAL bondOrder=1., const bool updateDisplay=true)
Add a bond.
Definition: Molecule.cpp:3988
const map< MolAtom *, set< MolAtom * > > & GetConnectivityTable()
Get the connectivity table.
Definition: Molecule.cpp:4639
Generic type of scatterer: can be an atom, or a more complex assembly of atoms.
Definition: Scatterer.h:131
virtual const string & GetClassName() const
Name for this class ("RefinableObj", "Crystal",...).
Definition: Scatterer.cpp:97
virtual int GetNbComponent() const =0
Number of components in the scatterer (eg number of point scatterers)
virtual string GetComponentName(const int i) const =0
Name for the i-th component of this scatterer.
virtual void SetZ(const REAL z)
Z coordinate (fractionnal) of the scatterer (for complex scatterers, this corresponds to the position...
Definition: Scatterer.cpp:111
virtual void SetY(const REAL y)
Y coordinate (fractionnal) of the scatterer (for complex scatterers, this corresponds to the position...
Definition: Scatterer.cpp:110
virtual ostream & POVRayDescription(ostream &os, const CrystalPOVRayOptions &options) const =0
REAL GetX() const
X coordinate (fractionnal) of the scatterer (for complex scatterers, this corresponds to the position...
Definition: Scatterer.cpp:103
REAL GetZ() const
Z coordinate (fractionnal) of the scatterer (for complex scatterers, this corresponds to the position...
Definition: Scatterer.cpp:105
virtual const ScatteringComponentList & GetScatteringComponentList() const =0
Get the list of all scattering components for this scatterer.
void SetCrystal(Crystal &)
Set the crystal in which is included this Scatterer.
Definition: Scatterer.cpp:136
REAL GetY() const
Y coordinate (fractionnal) of the scatterer (for complex scatterers, this corresponds to the position...
Definition: Scatterer.cpp:104
virtual void SetX(const REAL x)
X coordinate (fractionnal) of the scatterer (for complex scatterers, this corresponds to the position...
Definition: Scatterer.cpp:109
Abstract Base Class to describe the scattering power of any Scatterer component in a crystal.
virtual const string & GetClassName() const
Name for this class ("RefinableObj", "Crystal",...).
const RefinableObjClock & GetMaximumLikelihoodParClock() const
Get the clock value for the last change on the maximum likelihood parameters (positionnal error,...
virtual const string & GetSymbol() const
Symbol for this Scattering power (the atom name for atoms)
The Scattering Power for an Atom.
virtual const string & GetSymbol() const
Returns the symbol ('Ta', 'O2-',...) of the atom.
REAL GetCovalentRadius() const
Covalent Radius for this atom, in Angstroems (from cctbx)
REAL GetAtomicWeight() const
Atomic weight (g/mol) for this atom.
unsigned int GetMaxCovBonds() const
Maximum number of covalent bonds (from openbabel element.txt)
int GetAtomicNumber() const
Atomic number for this atom.
A scattering position in a crystal, associated with the corresponding occupancy and a pointer to the ...
const ScatteringPower * mpScattPow
The ScatteringPower associated with this position.
REAL mDynPopCorr
Dynamical Population Correction.
list of scattering positions in a crystal, associated with the corresponding occupancy and a pointer ...
long GetNbComponent() const
Number of components.
void Print() const
Print the list of Scattering components. For debugging.
char GetExtension() const
Extension to space group symbol ('1','2':origin choice ; 'R','H'=rhomboedral/hexagonal)
Definition: SpaceGroup.cpp:470
int GetNbSymmetrics(const bool noCenter=false, const bool noTransl=false) const
Return the number of equivalent positions in the spacegroup, ie the multilicity of the general positi...
Definition: SpaceGroup.cpp:418
CrystMatrix_REAL GetAllSymmetrics(const REAL x, const REAL y, const REAL z, const bool noCenter=false, const bool noTransl=false, const bool noIdentical=false) const
Get all equivalent positions of a (xyz) position.
Definition: SpaceGroup.cpp:276
const AsymmetricUnit & GetAsymUnit() const
Get the AsymmetricUnit for this spacegroup.
Definition: SpaceGroup.cpp:247
const cctbx::sgtbx::space_group & GetCCTbxSpg() const
Get the underlying cctbx Spacegroup object.
Definition: SpaceGroup.cpp:464
CrystVector_REAL GetLatticePar() const
Lattice parameters (a,b,c,alpha,beta,gamma) as a 6-element vector in Angstroems and radians.
Definition: UnitCell.cpp:92
const RefinableObjClock & GetClockMetricMatrix() const
last time the metric matrices were changed
Definition: UnitCell.cpp:334
REAL GetVolume() const
Volume of Unit Cell (in Angstroems)
Definition: UnitCell.cpp:336
virtual 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 UnitCell parameters.
Definition: UnitCell.cpp:349
void OrthonormalToFractionalCoords(REAL &x, REAL &y, REAL &z) const
Get fractional cartesian coordinates for a set of (x,y,z) orthonormal coordinates.
Definition: UnitCell.cpp:273
const SpaceGroup & GetSpaceGroup() const
Access to the SpaceGroup object.
Definition: UnitCell.cpp:322
const CrystMatrix_REAL & GetOrthMatrix() const
Get the orthogonalization matrix (UnitCell::mOrthMatrix)for the UnitCell in real space.
Definition: UnitCell.cpp:244
const RefinableObjClock & GetClockLatticePar() const
last time the Lattice parameters were changed
Definition: UnitCell.cpp:333
void FractionalToOrthonormalCoords(REAL &x, REAL &y, REAL &z) const
Get orthonormal cartesian coordinates for a set of (x,y,z) fractional coordinates.
Definition: UnitCell.cpp:263
class to input or output a well-formatted xml beginning or ending tag.
class of refinable parameter types.
Definition: RefinableObj.h:80
We need to record exactly when refinable objects have been modified for the last time (to avoid re-co...
Definition: RefinableObj.h:140
void Reset()
Reset a Clock to 0, to force an update.
void AddChild(const RefinableObjClock &)
Add a 'child' clock.
void RemoveChild(const RefinableObjClock &)
remove a child clock. This also tells the child clock to remove the parent.
void Click()
Record an event for this clock (generally, the 'time' an object has been modified,...
Object Registry.
Definition: RefinableObj.h:645
Generic Refinable Object.
Definition: RefinableObj.h:784
bool IsBeingRefined() const
Is the object being refined ? (Can be refined by one algorithm at a time only.)
virtual void RegisterClient(RefinableObj &) const
Register a new object using this object.
RefinablePar & GetPar(const long i)
Access all parameters in the order they were inputted.
virtual const string & GetName() const
Name of the object.
long GetNbPar() const
Total number of refinable parameter in the object.
virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false)
This should be called by any optimization class at the begining of an optimization.
const RefinableObjClock & GetClockMaster() const
This clocks records any change in the object. See refinableObj::mClockMaster.
void AddOption(RefObjOpt *opt)
virtual void DeRegisterClient(RefinableObj &) const
Deregister an object (which not any more) using this object.
virtual void UpdateDisplay() const
If there is an interface, this should be automatically be called each time there is a 'new,...
RefinableObjClock mClockMaster
Master clock, which is changed whenever the object has been altered.
string mName
Name for this RefinableObject. Should be unique, at least in the same scope.+.
void AddSubRefObj(RefinableObj &)
void SetGlobalOptimStep(const RefParType *type, const REAL step)
Change the maximum step to use during Global Optimization algorithms.
void RemoveSubRefObj(RefinableObj &)
virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type=gpRefParTypeObjCryst)
Make a random move of the current configuration.
output a number as a formatted float:
output a string with a fixed length (adding necessary space or removing excess characters) :
Abstract base class for all objects in wxCryst.
Definition: wxCryst.h:128
wxCryst class for Crystals
Definition: wxCrystal.h:81