FOX/ObjCryst++  2022
Molecule.cpp
1 /* ObjCryst++ Object-Oriented Crystallographic Library
2  (c) 2000-2009 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; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 /* Molecule.cpp
19 * Source file for the Molecule scatterer
20 *
21 */
22 #include <sstream>
23 #include <fstream>
24 #include <iterator>
25 #include <algorithm>
26 #include <iomanip>
27 #include <ctime>
28 #include <boost/format.hpp>
29 
30 #include "ObjCryst/Quirks/VFNStreamFormat.h"
31 #include "ObjCryst/ObjCryst/Molecule.h"
32 #include "ObjCryst/ObjCryst/ZScatterer.h"
33 #include "ObjCryst/RefinableObj/GlobalOptimObj.h"
34 
35 #ifdef OBJCRYST_GL
36  #ifdef __DARWIN__
37  #include <OpenGL/glu.h>
38  #else
39  #include <GL/glu.h>
40  #endif
41 #endif
42 
43 #ifdef __WX__CRYST__
44  #include "ObjCryst/wxCryst/wxMolecule.h"
45 #endif
46 
47 //#include <xmmintrin.h>
48 
49 // Try new approach for rigid bodies ?
50 #define RIGID_BODY_STRICT_EXPERIMENTAL
51 
52 // Tighter restraints x**2+x**4+x**6 instead of just X**2
53 #undef RESTRAINT_X2_X4_X6
54 
55 using namespace std;
56 
57 
58 namespace ObjCryst
59 {
60 XYZ::XYZ(REAL x0,REAL y0,REAL z0):x(x0),y(y0),z(z0){};
61 
62 REAL GetBondLength(const MolAtom&at1,const MolAtom&at2)
63 {
64  //TAU_PROFILE("GetBondLength()","REAL (...)",TAU_DEFAULT);
65 
66  /*
67  __m128 m128=_mm_set_ps(0.0f,
68  at1.GetZ()-at2.GetZ(),
69  at1.GetY()-at2.GetY(),
70  at1.GetX()-at2.GetX());
71 
72  __m128 a = _mm_mul_ps(m128,m128);
73 
74  // horizontal add
75  __m128 b = _mm_add_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0,0,0,0)),
76  _mm_add_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(1,1,1,1)),
77  _mm_shuffle_ps(a, a, _MM_SHUFFLE(2,2,2,2))));
78  union m128_float
79  {
80  __m128 m128;
81  struct
82  {
83  float x, y, z, pad;
84  };
85  };
86  union m128_float l;
87  l.m128 = _mm_sqrt_ss(b);
88 
89  return l.x;
90  */
91  return sqrt( (at1.GetX()-at2.GetX())
92  *(at1.GetX()-at2.GetX())
93  +(at1.GetY()-at2.GetY())
94  *(at1.GetY()-at2.GetY())
95  +(at1.GetZ()-at2.GetZ())
96  *(at1.GetZ()-at2.GetZ()) );
97 }
98 REAL GetBondAngle(const MolAtom &at1,const MolAtom &at2,const MolAtom &at3)
99 {
100  //TAU_PROFILE("GetBondAngle()","REAL (...)",TAU_DEFAULT);
101  const REAL x21=at1.GetX()-at2.GetX();
102  const REAL y21=at1.GetY()-at2.GetY();
103  const REAL z21=at1.GetZ()-at2.GetZ();
104  const REAL x23=at3.GetX()-at2.GetX();
105  const REAL y23=at3.GetY()-at2.GetY();
106  const REAL z23=at3.GetZ()-at2.GetZ();
107  const REAL norm21_norm23= sqrt( (x21*x21+y21*y21+z21*z21)
108  *(x23*x23+y23*y23+z23*z23)+1e-6);
109  const REAL angle=(x21*x23+y21*y23+z21*z23)/norm21_norm23;
110  if(angle>=1) return 0;
111  if(angle<=-1) return M_PI;
112  return acos(angle);
113 }
114 REAL GetDihedralAngle(const MolAtom &at1,const MolAtom &at2,const MolAtom &at3,const MolAtom &at4)
115 {
116  //TAU_PROFILE("GetDihedralAngle()","REAL (...)",TAU_DEFAULT);
117  const REAL x21=at1.GetX()-at2.GetX();
118  const REAL y21=at1.GetY()-at2.GetY();
119  const REAL z21=at1.GetZ()-at2.GetZ();
120 
121  const REAL x34=at4.GetX()-at3.GetX();
122  const REAL y34=at4.GetY()-at3.GetY();
123  const REAL z34=at4.GetZ()-at3.GetZ();
124 
125  const REAL x23=at3.GetX()-at2.GetX();
126  const REAL y23=at3.GetY()-at2.GetY();
127  const REAL z23=at3.GetZ()-at2.GetZ();
128 
129  // v21 x v23
130  const REAL x123= y21*z23-z21*y23;
131  const REAL y123= z21*x23-x21*z23;
132  const REAL z123= x21*y23-y21*x23;
133 
134  // v32 x v34 (= -v23 x v34)
135  const REAL x234= -(y23*z34-z23*y34);
136  const REAL y234= -(z23*x34-x23*z34);
137  const REAL z234= -(x23*y34-y23*x34);
138 
139  const REAL norm123_norm234= sqrt( (x123*x123+y123*y123+z123*z123)
140  *(x234*x234+y234*y234+z234*z234)+1e-6);
141 
142  REAL angle=(x123*x234+y123*y234+z123*z234)/norm123_norm234;
143  if(angle>= 1) angle=0;
144  else
145  {
146  if(angle<=-1) angle=M_PI;
147  else angle=acos(angle);
148  }
149  if((x21*x234 + y21*y234 + z21*z234)<0) return -angle;
150  return angle;
151 }
152 
153 
155  const map<MolAtom*,set<MolAtom*> > &connect,
156  set<MolAtom*> &atomlist,const MolAtom* finalAtom)
157 {
158  const pair<set<MolAtom*>::iterator,bool> status=atomlist.insert(atom);
159  if(false==status.second) return;
160  if(finalAtom==atom) return;
161  map<MolAtom*,set<MolAtom*> >::const_iterator c=connect.find(atom);
162  set<MolAtom*>::const_iterator pos;
163  for(pos=c->second.begin();pos!=c->second.end();++pos)
164  {
165  ExpandAtomGroupRecursive(*pos,connect,atomlist,finalAtom);
166  }
167 }
168 
170  const map<MolAtom*,set<MolAtom*> > &connect,
171  map<MolAtom*,unsigned long> &atomlist,const unsigned long maxdepth,unsigned long depth)
172 {
173  if(atomlist.count(atom)>0)
174  if(atomlist[atom]<=depth) return;
175  atomlist[atom]=depth;
176  if(depth==maxdepth) return;//maxdepth reached
177  map<MolAtom*,set<MolAtom*> >::const_iterator c=connect.find(atom);
178  set<MolAtom*>::const_iterator pos;
179  for(pos=c->second.begin();pos!=c->second.end();++pos)
180  {
181  ExpandAtomGroupRecursive(*pos,connect,atomlist,maxdepth,depth+1);
182  }
183 }
184 
185 //######################################################################
186 //
187 // MolAtom
188 //
189 //######################################################################
190 
191 MolAtom::MolAtom(const REAL x, const REAL y, const REAL z,
192  const ScatteringPower *pPow, const string &name, Molecule &parent):
193 mName(name),mX(x),mY(y),mZ(z),mOccupancy(1.),mpScattPow(pPow),mpMol(&parent),mIsInRing(false),mIsNonFlipAtom(false)
194 #ifdef __WX__CRYST__
195 ,mpWXCrystObj(0)
196 #endif
197 {
198  VFN_DEBUG_MESSAGE("MolAtom::MolAtom()",4)
199 }
200 
202 {
203 #ifdef __WX__CRYST__
204 this->WXDelete();
205 #endif
206 }
207 
208 void MolAtom::SetName(const string &name)
209 {
210  mName=name;
211  // Set parameter's name in the parent molecule
212  // The atom should already be part of a Molecule, but just in case be careful
213  if((mName!="") && (mpMol!=0))
214  {
215  try
216  {
217  mpMol->GetPar(&mX).SetName(mpMol->GetName()+"_"+mName+"_x");
218  mpMol->GetPar(&mY).SetName(mpMol->GetName()+"_"+mName+"_y");
219  mpMol->GetPar(&mZ).SetName(mpMol->GetName()+"_"+mName+"_z");
220  }
221  catch(const ObjCrystException &except)
222  {
223  cerr<<"MolAtom::SetName(): Atom parameters not yet declared in a Molecule ?"<<endl;
224  }
225  }
226 }
227 
228 const string& MolAtom::GetName()const{return mName;}
229  string& MolAtom::GetName() {return mName;}
230 
231 const Molecule& MolAtom::GetMolecule()const{return *mpMol;}
232  Molecule& MolAtom::GetMolecule() {return *mpMol;}
233 
234 const REAL& MolAtom::X()const{return mX;}
235 const REAL& MolAtom::Y()const{return mY;}
236 const REAL& MolAtom::Z()const{return mZ;}
237 
238 REAL& MolAtom::X(){return mX;}
239 REAL& MolAtom::Y(){return mY;}
240 REAL& MolAtom::Z(){return mZ;}
241 
242 REAL MolAtom::GetX()const{return mX;}
243 REAL MolAtom::GetY()const{return mY;}
244 REAL MolAtom::GetZ()const{return mZ;}
245 REAL MolAtom::GetOccupancy()const{return mOccupancy;}
246 
247 void MolAtom::SetX(const REAL a)const{ mX=a;mpMol->GetAtomPositionClock().Click();}
248 void MolAtom::SetY(const REAL a)const{ mY=a;mpMol->GetAtomPositionClock().Click();}
249 void MolAtom::SetZ(const REAL a)const{ mZ=a;mpMol->GetAtomPositionClock().Click();}
250 void MolAtom::SetOccupancy(const REAL a){ mOccupancy=a;}
251 
252 bool MolAtom::IsDummy()const{return mpScattPow==0;}
253 const ScatteringPower& MolAtom::GetScatteringPower()const{return *mpScattPow;}
254 
255 void MolAtom::SetScatteringPower(const ScatteringPower& pow)
256 {
257  if(mpScattPow!=&pow)
258  {
259  mpScattPow=&pow;
260  this->GetMolecule().GetAtomScattPowClock().Click();
261  }
262 }
263 
264 void MolAtom::XMLOutput(ostream &os,int indent)const
265 {
266  VFN_DEBUG_ENTRY("MolAtom::XMLOutput()",4)
267  for(int i=0;i<indent;i++) os << " " ;
268  XMLCrystTag tag("Atom",false,true);
269  tag.AddAttribute("Name",this->GetName());
270  if(!this->IsDummy())tag.AddAttribute("ScattPow",this->GetScatteringPower().GetName());
271  {
272  stringstream ss;
273  ss.precision(os.precision());
274  ss <<mX;
275  tag.AddAttribute("x",ss.str());
276  }
277  {
278  stringstream ss;
279  ss.precision(os.precision());
280  ss <<mY;
281  tag.AddAttribute("y",ss.str());
282  }
283  {
284  stringstream ss;
285  ss.precision(os.precision());
286  ss <<mZ;
287  tag.AddAttribute("z",ss.str());
288  }
289  {
290  stringstream ss;
291  ss.precision(os.precision());
292  ss <<mOccupancy;
293  tag.AddAttribute("Occup",ss.str());
294  }
295  if(mIsNonFlipAtom) tag.AddAttribute("NonFlip","1");
296  os <<tag<<endl;
297  VFN_DEBUG_EXIT("MolAtom::XMLOutput()",4)
298 }
299 
300 void MolAtom::XMLInput(istream &is,const XMLCrystTag &tag)
301 {
302  VFN_DEBUG_ENTRY("MolAtom::XMLInput()",7)
303  string name;
304  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
305  {
306  if("Name"==tag.GetAttributeName(i))
307  {
308  name=tag.GetAttributeValue(i);
309  }
310  if("ScattPow"==tag.GetAttributeName(i))
311  {
312  mpScattPow=&(mpMol->GetCrystal().GetScatteringPower(tag.GetAttributeValue(i)));
313  }
314  if("x"==tag.GetAttributeName(i))
315  {
316  stringstream ss(tag.GetAttributeValue(i));
317  ss >>mX;
318  }
319  if("y"==tag.GetAttributeName(i))
320  {
321  stringstream ss(tag.GetAttributeValue(i));
322  ss >>mY;
323  }
324  if("z"==tag.GetAttributeName(i))
325  {
326  stringstream ss(tag.GetAttributeValue(i));
327  ss >>mZ;
328  }
329  if("Occup"==tag.GetAttributeName(i))
330  {
331  stringstream ss(tag.GetAttributeValue(i));
332  ss >>mOccupancy;
333  }
334  if("NonFlip"==tag.GetAttributeName(i))
335  {
336  stringstream ss(tag.GetAttributeValue(i));
337  ss >>mIsNonFlipAtom;
338  }
339  }
340  this->SetName(name);
341  VFN_DEBUG_EXIT("MolAtom::XMLInput()",7)
342 }
343 
344 void MolAtom::SetIsInRing(const bool r)const{mIsInRing=r;}
345 bool MolAtom::IsInRing()const{return mIsInRing;}
346 
347 void MolAtom::SetNonFlipAtom(const bool nonflip)
348 {
349  // :KLUDGE: should be using a specific clock ?
350  if(mIsNonFlipAtom != nonflip) this->GetMolecule().GetRigidGroupClock().Click();
351  mIsNonFlipAtom = nonflip;
352 }
353 
355 {
356  return mIsNonFlipAtom;
357 }
358 
359 size_t MolAtom::int_ptr() const {return (size_t)this;}
360 
361 #ifdef __WX__CRYST__
362 WXCrystObjBasic* MolAtom::WXCreate(wxWindow* parent)
363 {
364  VFN_DEBUG_ENTRY("MolAtom::WXCreate()",5)
365  mpWXCrystObj=new WXMolAtom(parent,this);
366  VFN_DEBUG_EXIT("MolAtom::WXCreate()",5)
367  return mpWXCrystObj;
368 }
369 WXCrystObjBasic* MolAtom::WXGet(){return mpWXCrystObj;}
370 void MolAtom::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;}
371 void MolAtom::WXNotifyDelete(){mpWXCrystObj=0;}
372 #endif
373 //######################################################################
374 //
375 // MolBond
376 //
377 //######################################################################
379  const REAL length0, const REAL sigma, const REAL delta,
380  Molecule &parent,const REAL bondOrder):
381 mAtomPair(make_pair(&atom1,&atom2)),
382 mLength0(length0),mDelta(delta),mSigma(sigma),
383 mBondOrder(bondOrder),mIsFreeTorsion(false),mpMol(&parent)
384 #ifdef __WX__CRYST__
385 ,mpWXCrystObj(0)
386 #endif
387 {}
388 
390 {
391 #ifdef __WX__CRYST__
392 this->WXDelete();
393 #endif
394 }
395 
396 const Molecule& MolBond::GetMolecule()const{return *mpMol;}
397  Molecule& MolBond::GetMolecule() {return *mpMol;}
398 
399 string MolBond::GetName()const
400 {return this->GetAtom1().GetName()+"-"+this->GetAtom2().GetName();}
401 
402 void MolBond::XMLOutput(ostream &os,int indent)const
403 {
404  VFN_DEBUG_ENTRY("MolBond::XMLOutput()",4)
405  for(int i=0;i<indent;i++) os << " " ;
406  XMLCrystTag tag("Bond",false,true);
407  tag.AddAttribute("Atom1",mAtomPair.first->GetName());
408  tag.AddAttribute("Atom2",mAtomPair.second->GetName());
409  {
410  stringstream ss;
411  ss.precision(os.precision());
412  ss <<mLength0;
413  tag.AddAttribute("Length",ss.str());
414  }
415  {
416  stringstream ss;
417  ss.precision(os.precision());
418  ss <<mDelta;
419  tag.AddAttribute("Delta",ss.str());
420  }
421  {
422  stringstream ss;
423  ss.precision(os.precision());
424  ss <<mSigma;
425  tag.AddAttribute("Sigma",ss.str());
426  }
427  {
428  stringstream ss;
429  ss.precision(os.precision());
430  ss <<mBondOrder;
431  tag.AddAttribute("BondOrder",ss.str());
432  }
433  {
434  stringstream ss;
435  ss.precision(os.precision());
436  ss <<mIsFreeTorsion;
437  tag.AddAttribute("FreeTorsion",ss.str());
438  }
439  os <<tag<<endl;
440  VFN_DEBUG_EXIT("MolBond::XMLOutput()",4)
441 }
442 
443 void MolBond::XMLInput(istream &is,const XMLCrystTag &tag)
444 {
445  VFN_DEBUG_ENTRY("MolBond::XMLInput():",7)
446  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
447  {
448  if("Atom1"==tag.GetAttributeName(i))
449  {
450  mAtomPair.first=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
451  }
452  if("Atom2"==tag.GetAttributeName(i))
453  {
454  mAtomPair.second=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
455  }
456  if("Length"==tag.GetAttributeName(i))
457  {
458  stringstream ss(tag.GetAttributeValue(i));
459  ss >>mLength0;
460  }
461  if("Delta"==tag.GetAttributeName(i))
462  {
463  stringstream ss(tag.GetAttributeValue(i));
464  ss >>mDelta;
465  }
466  if("Sigma"==tag.GetAttributeName(i))
467  {
468  stringstream ss(tag.GetAttributeValue(i));
469  ss >>mSigma;
470  }
471  if("BondOrder"==tag.GetAttributeName(i))
472  {
473  stringstream ss(tag.GetAttributeValue(i));
474  ss >>mBondOrder;
475  }
476  if("FreeTorsion"==tag.GetAttributeName(i))
477  {
478  stringstream ss(tag.GetAttributeValue(i));
479  ss >>mIsFreeTorsion;
480  }
481  }
482  VFN_DEBUG_EXIT("MolBond::XMLInput():",7)
483 }
484 
485 REAL MolBond::GetLogLikelihood()const{return this->GetLogLikelihood(false,true);}
486 
487 REAL MolBond::GetLogLikelihood(const bool calcDeriv, const bool recalc)const
488 {
489  if(!recalc) return mLLK;
490  VFN_DEBUG_ENTRY("MolBond::GetLogLikelihood():",2)
491  //TAU_PROFILE("MolBond::GetLogLikelihood()","REAL (bool,bool)",TAU_DEFAULT);
492  //const REAL length=this->GetLength();
493  const REAL x=this->GetAtom2().GetX()-this->GetAtom1().GetX();
494  const REAL y=this->GetAtom2().GetY()-this->GetAtom1().GetY();
495  const REAL z=this->GetAtom2().GetZ()-this->GetAtom1().GetZ();
496  const REAL length=sqrt(abs(x*x+y*y+z*z));
497 
498  if(calcDeriv)
499  {
500  const REAL tmp2=1/(length+1e-10);
501  mDerivAtom1.x=-x*tmp2;
502  mDerivAtom1.y=-y*tmp2;
503  mDerivAtom1.z=-z*tmp2;
504 
505  mDerivAtom2.x=-mDerivAtom1.x;
506  mDerivAtom2.y=-mDerivAtom1.y;
507  mDerivAtom2.z=-mDerivAtom1.z;
508  }
509 
510  if(mSigma<1e-6)
511  {
512  if(calcDeriv) mDerivLLKCoeff=0;
513  mLLK=0;
514  return 0;
515  }
516  mLLK=length-(mLength0+mDelta);
517  if(mLLK>0)
518  {
519  mLLK /= mSigma;
520  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
521  #ifdef RESTRAINT_X2_X4_X6
522  const float mLLK2=mLLK*mLLK;
523  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
524  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
525  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
526  mLLK=mLLK2*(1+mLLK2);
527  #else
528  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
529  mLLK *= mLLK;
530  #endif
531  VFN_DEBUG_EXIT("MolBond::GetLogLikelihood():",2)
532  return mLLK;
533  }
534  mLLK=length-(mLength0-mDelta);
535  if(mLLK<0)
536  {
537  mLLK /= mSigma;
538  #ifdef RESTRAINT_X2_X4_X6
539  const float mLLK2=mLLK*mLLK;
540  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
541  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
542  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
543  mLLK=mLLK2*(1+mLLK2);
544  #else
545  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
546  mLLK *= mLLK;
547  #endif
548  VFN_DEBUG_EXIT("MolBond::GetLogLikelihood():",2)
549  return mLLK;
550  }
551  if(calcDeriv) mDerivLLKCoeff=0;
552  mLLK=0;
553  VFN_DEBUG_EXIT("MolBond::GetLogLikelihood():",2)
554  return mLLK;
555 }
556 
557 REAL MolBond::GetDeriv(const map<const MolAtom*,XYZ> &m, const bool llk)const
558 {
559  //TAU_PROFILE("MolBond::GetDeriv()","REAL (mak,bool)",TAU_DEFAULT);
560  REAL d=0;
561  map<const MolAtom*,XYZ>::const_iterator pos;
562  pos=m.find(mAtomPair.first);
563  if(pos!=m.end())
564  d+= pos->second.x*mDerivAtom1.x
565  +pos->second.y*mDerivAtom1.y
566  +pos->second.z*mDerivAtom1.z;
567  pos=m.find(mAtomPair.second);
568  if(pos!=m.end())
569  d+= pos->second.x*mDerivAtom2.x
570  +pos->second.y*mDerivAtom2.y
571  +pos->second.z*mDerivAtom2.z;
572  if(llk) return mDerivLLKCoeff*d;
573  return d;
574 }
575 
576 void MolBond::CalcGradient(std::map<MolAtom*,XYZ> &m)const
577 {
578  this->GetLogLikelihood(true,true);
579  map<MolAtom*,XYZ>::iterator pos;
580  pos=m.find(mAtomPair.first);
581  if(pos!=m.end())
582  {
583  pos->second.x+=mDerivLLKCoeff*mDerivAtom1.x;
584  pos->second.y+=mDerivLLKCoeff*mDerivAtom1.y;
585  pos->second.z+=mDerivLLKCoeff*mDerivAtom1.z;
586  }
587  pos=m.find(mAtomPair.second);
588  if(pos!=m.end())
589  {
590  pos->second.x+=mDerivLLKCoeff*mDerivAtom2.x;
591  pos->second.y+=mDerivLLKCoeff*mDerivAtom2.y;
592  pos->second.z+=mDerivLLKCoeff*mDerivAtom2.z;
593  }
594  #if 0
595  // Display gradient - for tests
596  cout<<this->GetName()<<" :LLK"<<endl;
597  for(map<MolAtom*,XYZ>::const_iterator pos=m.begin();pos!=m.end();++pos)
598  {
599  char buf[100];
600  sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)",
601  pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z);
602  cout<<buf<<endl;
603  }
604  #endif
605 }
606 
607 const MolAtom& MolBond::GetAtom1()const{return *(mAtomPair.first);}
608 const MolAtom& MolBond::GetAtom2()const{return *(mAtomPair.second);}
609 MolAtom& MolBond::GetAtom1(){return *(mAtomPair.first);}
610 MolAtom& MolBond::GetAtom2(){return *(mAtomPair.second);}
611 void MolBond::SetAtom1(MolAtom &at){mAtomPair.first =&at;}
612 void MolBond::SetAtom2(MolAtom &at){mAtomPair.second=&at;}
613 REAL MolBond::GetLength()const
614 {
615  return GetBondLength(GetAtom1(),this->GetAtom2());
616 }
617 
618 REAL MolBond::GetLength0()const{return mLength0;}
619 REAL MolBond::GetLengthDelta()const{return mDelta;}
620 REAL MolBond::GetLengthSigma()const{return mSigma;}
621 REAL MolBond::GetBondOrder()const{return mBondOrder;}
622 
623 REAL& MolBond::Length0(){return mLength0;}
624 REAL& MolBond::LengthDelta(){return mDelta;}
625 REAL& MolBond::LengthSigma(){return mSigma;}
626 REAL& MolBond::BondOrder(){return mBondOrder;}
627 
628 void MolBond::SetLength0(const REAL a){mLength0=a;}
629 void MolBond::SetLengthDelta(const REAL a){mDelta=a;}
630 void MolBond::SetLengthSigma(const REAL a){mSigma=a;}
631 void MolBond::SetBondOrder(const REAL a){mBondOrder=a;}
632 
633 bool MolBond::IsFreeTorsion()const{return mIsFreeTorsion;}
634 void MolBond::SetFreeTorsion(const bool isFreeTorsion)
635 {
636  if(mIsFreeTorsion==isFreeTorsion) return;
637  mIsFreeTorsion=isFreeTorsion;
639 }
640 
641 size_t MolBond::int_ptr() const {return (size_t)this;}
642 
643 #ifdef __WX__CRYST__
644 WXCrystObjBasic* MolBond::WXCreate(wxWindow* parent)
645 {
646  VFN_DEBUG_ENTRY("MolBond::WXCreate()",5)
647  mpWXCrystObj=new WXMolBond(parent,this);
648  VFN_DEBUG_EXIT("MolBond::WXCreate()",5)
649  return mpWXCrystObj;
650 }
651 WXCrystObjBasic* MolBond::WXGet(){return mpWXCrystObj;}
652 void MolBond::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;}
653 void MolBond::WXNotifyDelete(){mpWXCrystObj=0;}
654 #endif
655 //######################################################################
656 //
657 // MolBondAngle
658 //
659 //######################################################################
661  const REAL angle, const REAL sigma, const REAL delta,
662  Molecule &parent):
663 mAngle0(angle),mDelta(delta),mSigma(sigma),mpMol(&parent)
664 #ifdef __WX__CRYST__
665 ,mpWXCrystObj(0)
666 #endif
667 {
668  mvpAtom.push_back(&atom1);
669  mvpAtom.push_back(&atom2);
670  mvpAtom.push_back(&atom3);
671 }
672 
674 {
675 #ifdef __WX__CRYST__
676 this->WXDelete();
677 #endif
678 }
679 
680 const Molecule& MolBondAngle::GetMolecule()const{return *mpMol;}
681  Molecule& MolBondAngle::GetMolecule() {return *mpMol;}
682 
683 string MolBondAngle::GetName()const
684 {
685  return this->GetAtom1().GetName()+"-"
686  +this->GetAtom2().GetName()+"-"
687  +this->GetAtom3().GetName();
688 }
689 
690 void MolBondAngle::XMLOutput(ostream &os,int indent)const
691 {
692  VFN_DEBUG_ENTRY("MolBondAngle::XMLOutput()",4)
693  for(int i=0;i<indent;i++) os << " " ;
694  XMLCrystTag tag("BondAngle",false,true);
695  tag.AddAttribute("Atom1",this->GetAtom1().GetName());
696  tag.AddAttribute("Atom2",this->GetAtom2().GetName());
697  tag.AddAttribute("Atom3",this->GetAtom3().GetName());
698  {
699  stringstream ss;
700  ss.precision(os.precision());
701  ss <<mAngle0*RAD2DEG;
702  tag.AddAttribute("Angle",ss.str());
703  }
704  {
705  stringstream ss;
706  ss.precision(os.precision());
707  ss <<mDelta*RAD2DEG;
708  tag.AddAttribute("Delta",ss.str());
709  }
710  {
711  stringstream ss;
712  ss.precision(os.precision());
713  ss <<mSigma*RAD2DEG;
714  tag.AddAttribute("Sigma",ss.str());
715  }
716  os <<tag<<endl;
717  VFN_DEBUG_EXIT("MolBondAngle::XMLOutput()",4)
718 }
719 
720 void MolBondAngle::XMLInput(istream &is,const XMLCrystTag &tag)
721 {
722  VFN_DEBUG_ENTRY("MolBondAngle::XMLInput():",4)
723  mvpAtom.resize(3);
724  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
725  {
726  if("Atom1"==tag.GetAttributeName(i))
727  {
728  mvpAtom[0]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
729  }
730  if("Atom2"==tag.GetAttributeName(i))
731  {
732  mvpAtom[1]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
733  }
734  if("Atom3"==tag.GetAttributeName(i))
735  {
736  mvpAtom[2]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
737  }
738  if("Angle"==tag.GetAttributeName(i))
739  {
740  stringstream ss(tag.GetAttributeValue(i));
741  ss >>mAngle0;
742  mAngle0*=DEG2RAD;
743  }
744  if("Delta"==tag.GetAttributeName(i))
745  {
746  stringstream ss(tag.GetAttributeValue(i));
747  ss >>mDelta;
748  mDelta*=DEG2RAD;
749  }
750  if("Sigma"==tag.GetAttributeName(i))
751  {
752  stringstream ss(tag.GetAttributeValue(i));
753  ss >>mSigma;
754  mSigma*=DEG2RAD;
755  }
756  }
757  VFN_DEBUG_EXIT("MolBondAngle::XMLInput():",4)
758 }
759 REAL& MolBondAngle::Angle0()
760 {
761  return mAngle0;
762 }
763 REAL& MolBondAngle::AngleDelta(){return mDelta;}
764 REAL& MolBondAngle::AngleSigma(){return mSigma;}
765 
766 REAL MolBondAngle::GetAngle0()const{return mAngle0;}
767 REAL MolBondAngle::GetAngleDelta()const{return mDelta;}
768 REAL MolBondAngle::GetAngleSigma()const{return mSigma;}
769 
770 void MolBondAngle::SetAngle0(const REAL angle){mAngle0=angle;}
771 void MolBondAngle::SetAngleDelta(const REAL delta){mDelta=delta;}
772 void MolBondAngle::SetAngleSigma(const REAL sigma){mSigma=sigma;}
773 
774 REAL MolBondAngle::GetAngle()const
775 {
776  return GetBondAngle(this->GetAtom1(),this->GetAtom2(),this->GetAtom3());
777 }
778 
779 REAL MolBondAngle::GetLogLikelihood()const{return this->GetLogLikelihood(false,true);}
780 
781 REAL MolBondAngle::GetLogLikelihood(const bool calcDeriv, const bool recalc)const
782 {
783  if(!recalc) return mLLK;
784  VFN_DEBUG_ENTRY("MolBondAngle::GetLogLikelihood():",2)
785  //TAU_PROFILE("MolBondAngle::GetLogLikelihood()","REAL (bool,bool)",TAU_DEFAULT);
786  //const REAL angle=this->GetAngle();
787  const REAL x21=this->GetAtom1().GetX()-this->GetAtom2().GetX();
788  const REAL y21=this->GetAtom1().GetY()-this->GetAtom2().GetY();
789  const REAL z21=this->GetAtom1().GetZ()-this->GetAtom2().GetZ();
790  const REAL x23=this->GetAtom3().GetX()-this->GetAtom2().GetX();
791  const REAL y23=this->GetAtom3().GetY()-this->GetAtom2().GetY();
792  const REAL z23=this->GetAtom3().GetZ()-this->GetAtom2().GetZ();
793 
794  const REAL n1=sqrt(abs(x21*x21+y21*y21+z21*z21));
795  const REAL n3=sqrt(abs(x23*x23+y23*y23+z23*z23));
796  const REAL p=x21*x23+y21*y23+z21*z23;
797 
798  const REAL a0=p/(n1*n3+1e-10);
799  REAL angle;
800  if(a0>=1) angle=0;
801  else
802  {
803  if(a0<=-1) angle=M_PI;
804  else angle=acos(a0);
805  }
806 
807  if(calcDeriv)
808  {
809  const REAL s=1/(sqrt(1-a0*a0+1e-6));
810  const REAL s0=-s/(n1*n3+1e-10);
811  const REAL s1= s*p/(n3*n1*n1*n1+1e-10);
812  const REAL s3= s*p/(n1*n3*n3*n3+1e-10);
813  mDerivAtom1.x=s0*x23+s1*x21;
814  mDerivAtom1.y=s0*y23+s1*y21;
815  mDerivAtom1.z=s0*z23+s1*z21;
816 
817  mDerivAtom3.x=s0*x21+s3*x23;
818  mDerivAtom3.y=s0*y21+s3*y23;
819  mDerivAtom3.z=s0*z21+s3*z23;
820 
821  mDerivAtom2.x=-(mDerivAtom1.x+mDerivAtom3.x);
822  mDerivAtom2.y=-(mDerivAtom1.y+mDerivAtom3.y);
823  mDerivAtom2.z=-(mDerivAtom1.z+mDerivAtom3.z);
824  }
825 
826  if(mSigma<1e-6)
827  {
828  if(calcDeriv) mDerivLLKCoeff=0;
829  mLLK=0;
830  return 0;
831  }
832 
833  mLLK=angle-(mAngle0+mDelta);
834  if(mLLK>0)
835  {
836  mLLK/=mSigma;
837  #ifdef RESTRAINT_X2_X4_X6
838  const float mLLK2=mLLK*mLLK;
839  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
840  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
841  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
842  mLLK=mLLK2*(1+mLLK2);
843  #else
844  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
845  mLLK *= mLLK;
846  #endif
847  VFN_DEBUG_EXIT("MolBondAngle::GetLogLikelihood():",2)
848  return mLLK;
849  }
850  mLLK=angle-(mAngle0-mDelta);
851  if(mLLK<0)
852  {
853  mLLK/=mSigma;
854  #ifdef RESTRAINT_X2_X4_X6
855  const float mLLK2=mLLK*mLLK;
856  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
857  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
858  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
859  mLLK=mLLK2*(1+mLLK2);
860  #else
861  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
862  mLLK *= mLLK;
863  #endif
864  VFN_DEBUG_EXIT("MolBondAngle::GetLogLikelihood():",2)
865  return mLLK;
866  }
867  VFN_DEBUG_EXIT("MolBondAngle::GetLogLikelihood():",2)
868  if(calcDeriv) mDerivLLKCoeff=0;
869  mLLK=0;
870  return mLLK;
871 }
872 
873 REAL MolBondAngle::GetDeriv(const std::map<const MolAtom*,XYZ> &m,const bool llk)const
874 {
875  //TAU_PROFILE("MolBondAngle::GetDeriv()","REAL (mak,bool)",TAU_DEFAULT);
876  REAL d=0;
877  map<const MolAtom*,XYZ>::const_iterator pos;
878  pos=m.find(mvpAtom[0]);
879  if(pos!=m.end())
880  d+= pos->second.x*mDerivAtom1.x
881  +pos->second.y*mDerivAtom1.y
882  +pos->second.z*mDerivAtom1.z;
883  pos=m.find(mvpAtom[1]);
884  if(pos!=m.end())
885  d+= pos->second.x*mDerivAtom2.x
886  +pos->second.y*mDerivAtom2.y
887  +pos->second.z*mDerivAtom2.z;
888  pos=m.find(mvpAtom[2]);
889  if(pos!=m.end())
890  d+= pos->second.x*mDerivAtom3.x
891  +pos->second.y*mDerivAtom3.y
892  +pos->second.z*mDerivAtom3.z;
893  if(llk) return mDerivLLKCoeff*d;
894  return d;
895 }
896 
897 void MolBondAngle::CalcGradient(std::map<MolAtom*,XYZ> &m)const
898 {
899  this->GetLogLikelihood(true,true);
900  map<MolAtom*,XYZ>::iterator pos;
901  pos=m.find(mvpAtom[0]);
902  if(pos!=m.end())
903  {
904  pos->second.x+=mDerivLLKCoeff*mDerivAtom1.x;
905  pos->second.y+=mDerivLLKCoeff*mDerivAtom1.y;
906  pos->second.z+=mDerivLLKCoeff*mDerivAtom1.z;
907  }
908  pos=m.find(mvpAtom[1]);
909  if(pos!=m.end())
910  {
911  pos->second.x+=mDerivLLKCoeff*mDerivAtom2.x;
912  pos->second.y+=mDerivLLKCoeff*mDerivAtom2.y;
913  pos->second.z+=mDerivLLKCoeff*mDerivAtom2.z;
914  }
915  pos=m.find(mvpAtom[2]);
916  if(pos!=m.end())
917  {
918  pos->second.x+=mDerivLLKCoeff*mDerivAtom3.x;
919  pos->second.y+=mDerivLLKCoeff*mDerivAtom3.y;
920  pos->second.z+=mDerivLLKCoeff*mDerivAtom3.z;
921  }
922  #if 0
923  // Display gradient - for tests
924  cout<<this->GetName()<<" :LLK"<<endl;
925  for(map<MolAtom*,XYZ>::const_iterator pos=m.begin();pos!=m.end();++pos)
926  {
927  char buf[100];
928  sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)",
929  pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z);
930  cout<<buf<<endl;
931  }
932  #endif
933 }
934 
935 const MolAtom& MolBondAngle::GetAtom1()const{return *(mvpAtom[0]);}
936 const MolAtom& MolBondAngle::GetAtom2()const{return *(mvpAtom[1]);}
937 const MolAtom& MolBondAngle::GetAtom3()const{return *(mvpAtom[2]);}
938 MolAtom& MolBondAngle::GetAtom1(){return *(mvpAtom[0]);}
939 MolAtom& MolBondAngle::GetAtom2(){return *(mvpAtom[1]);}
940 MolAtom& MolBondAngle::GetAtom3(){return *(mvpAtom[2]);}
941 void MolBondAngle::SetAtom1(MolAtom& at){mvpAtom[0]=&at;}
942 void MolBondAngle::SetAtom2(MolAtom& at){mvpAtom[1]=&at;}
943 void MolBondAngle::SetAtom3(MolAtom& at){mvpAtom[2]=&at;}
944 //MolAtom& MolBondAngle::GetAtom1(){return *(mvpAtom[0]);}
945 //MolAtom& MolBondAngle::GetAtom2(){return *(mvpAtom[1]);}
946 //MolAtom& MolBondAngle::GetAtom3(){return *(mvpAtom[2]);}
947 std::size_t MolBondAngle::size() const {return mvpAtom.size();}
948 vector<MolAtom*>::const_iterator MolBondAngle::begin() const {return mvpAtom.begin();}
949 vector<MolAtom*>::const_iterator MolBondAngle::end() const {return mvpAtom.end();}
950 
951 size_t MolBondAngle::int_ptr() const {return (size_t)this;}
952 
953 #ifdef __WX__CRYST__
954 WXCrystObjBasic* MolBondAngle::WXCreate(wxWindow* parent)
955 {
956  VFN_DEBUG_ENTRY("MolBondAngle::WXCreate()",5)
957  mpWXCrystObj=new WXMolBondAngle(parent,this);
958  VFN_DEBUG_EXIT("MolBondAngle::WXCreate()",5)
959  return mpWXCrystObj;
960 }
961 WXCrystObjBasic* MolBondAngle::WXGet(){return mpWXCrystObj;}
962 void MolBondAngle::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;}
963 void MolBondAngle::WXNotifyDelete(){mpWXCrystObj=0;}
964 #endif
965 //######################################################################
966 //
967 // MolDihedralAngle
968 //
969 //######################################################################
971  MolAtom &atom3, MolAtom &atom4,
972  const REAL angle, const REAL sigma, const REAL delta,
973  Molecule &parent):
974 mAngle0(angle),mDelta(delta),mSigma(sigma),mpMol(&parent)
975 #ifdef __WX__CRYST__
976 ,mpWXCrystObj(0)
977 #endif
978 {
979  VFN_DEBUG_ENTRY("MolDihedralAngle::MolDihedralAngle()",5)
980  mvpAtom.push_back(&atom1);
981  mvpAtom.push_back(&atom2);
982  mvpAtom.push_back(&atom3);
983  mvpAtom.push_back(&atom4);
984  // We want the angle in [-pi;pi]
985  mAngle0=fmod((REAL)mAngle0,(REAL)(2*M_PI));
986  if(mAngle0<(-M_PI)) mAngle0+=2*M_PI;
987  if(mAngle0>M_PI) mAngle0-=2*M_PI;
988  VFN_DEBUG_EXIT("MolDihedralAngle::MolDihedralAngle()",5)
989 }
990 
992 {
993 #ifdef __WX__CRYST__
994 this->WXDelete();
995 #endif
996 }
997 
998 const Molecule& MolDihedralAngle::GetMolecule()const{return *mpMol;}
999  Molecule& MolDihedralAngle::GetMolecule() {return *mpMol;}
1000 
1001 string MolDihedralAngle::GetName()const
1002 {
1003  return this->GetAtom1().GetName()+"-"
1004  +this->GetAtom2().GetName()+"-"
1005  +this->GetAtom3().GetName()+"-"
1006  +this->GetAtom4().GetName();
1007 }
1008 
1009 void MolDihedralAngle::XMLOutput(ostream &os,int indent)const
1010 {
1011  VFN_DEBUG_ENTRY("MolDihedralAngle::XMLOutput()",4)
1012  for(int i=0;i<indent;i++) os << " " ;
1013  XMLCrystTag tag("DihedralAngle",false,true);
1014  tag.AddAttribute("Atom1",this->GetAtom1().GetName());
1015  tag.AddAttribute("Atom2",this->GetAtom2().GetName());
1016  tag.AddAttribute("Atom3",this->GetAtom3().GetName());
1017  tag.AddAttribute("Atom4",this->GetAtom4().GetName());
1018  {
1019  stringstream ss;
1020  ss.precision(os.precision());
1021  ss <<mAngle0*RAD2DEG;
1022  tag.AddAttribute("Angle",ss.str());
1023  }
1024  {
1025  stringstream ss;
1026  ss.precision(os.precision());
1027  ss <<mDelta*RAD2DEG;
1028  tag.AddAttribute("Delta",ss.str());
1029  }
1030  {
1031  stringstream ss;
1032  ss.precision(os.precision());
1033  ss <<mSigma*RAD2DEG;
1034  tag.AddAttribute("Sigma",ss.str());
1035  }
1036  os <<tag<<endl;
1037  VFN_DEBUG_EXIT("MolDihedralAngle::XMLOutput()",4)
1038 }
1039 
1040 void MolDihedralAngle::XMLInput(istream &is,const XMLCrystTag &tag)
1041 {
1042  VFN_DEBUG_ENTRY("MolDihedralAngle::XMLInput():",5)
1043  mvpAtom.resize(4);
1044  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
1045  {
1046  if("Atom1"==tag.GetAttributeName(i))
1047  {
1048  mvpAtom[0]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
1049  }
1050  if("Atom2"==tag.GetAttributeName(i))
1051  {
1052  mvpAtom[1]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
1053  }
1054  if("Atom3"==tag.GetAttributeName(i))
1055  {
1056  mvpAtom[2]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
1057  }
1058  if("Atom4"==tag.GetAttributeName(i))
1059  {
1060  mvpAtom[3]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
1061  }
1062  if("Angle"==tag.GetAttributeName(i))
1063  {
1064  stringstream ss(tag.GetAttributeValue(i));
1065  ss >>mAngle0;
1066  mAngle0*=DEG2RAD;
1067  }
1068  if("Delta"==tag.GetAttributeName(i))
1069  {
1070  stringstream ss(tag.GetAttributeValue(i));
1071  ss >>mDelta;
1072  mDelta*=DEG2RAD;
1073  }
1074  if("Sigma"==tag.GetAttributeName(i))
1075  {
1076  stringstream ss(tag.GetAttributeValue(i));
1077  ss >>mSigma;
1078  mSigma*=DEG2RAD;
1079  }
1080  }
1081  VFN_DEBUG_EXIT("MolDihedralAngle::XMLInput():",5)
1082 }
1083 
1084 REAL MolDihedralAngle::GetAngle()const
1085 {
1086  //Get the angle [2pi] closest to the restraint
1087  const REAL angle=GetDihedralAngle(this->GetAtom1(),this->GetAtom2(),this->GetAtom3(),this->GetAtom4());
1088  if((angle-mAngle0)>M_PI) return angle-2*M_PI;
1089  else if((angle-mAngle0)<(-M_PI)) return angle+2*M_PI;
1090 
1091  return angle;
1092 }
1093 
1094 REAL& MolDihedralAngle::Angle0(){return mAngle0;}
1095 REAL& MolDihedralAngle::AngleDelta(){return mDelta;}
1096 REAL& MolDihedralAngle::AngleSigma(){return mSigma;}
1097 
1098 REAL MolDihedralAngle::GetAngle0()const{return mAngle0;}
1099 REAL MolDihedralAngle::GetAngleDelta()const{return mDelta;}
1100 REAL MolDihedralAngle::GetAngleSigma()const{return mSigma;}
1101 
1102 void MolDihedralAngle::SetAngle0(const REAL angle){mAngle0=angle;}
1103 void MolDihedralAngle::SetAngleDelta(const REAL delta){mDelta=delta;}
1104 void MolDihedralAngle::SetAngleSigma(const REAL sigma){mSigma=sigma;}
1105 
1106 REAL MolDihedralAngle::GetLogLikelihood()const{return this->GetLogLikelihood(false,true);}
1107 
1108 REAL MolDihedralAngle::GetLogLikelihood(const bool calcDeriv, const bool recalc)const
1109 {
1110  if(!recalc) return mLLK;
1111  VFN_DEBUG_ENTRY("MolDihedralAngle::GetLogLikelihood():",2)
1112  //TAU_PROFILE("MolDihedralAngle::GetLogLikelihood()","REAL (bool,bool)",TAU_DEFAULT);
1113  const REAL x21=this->GetAtom1().GetX()-this->GetAtom2().GetX();
1114  const REAL y21=this->GetAtom1().GetY()-this->GetAtom2().GetY();
1115  const REAL z21=this->GetAtom1().GetZ()-this->GetAtom2().GetZ();
1116 
1117  const REAL x34=this->GetAtom4().GetX()-this->GetAtom3().GetX();
1118  const REAL y34=this->GetAtom4().GetY()-this->GetAtom3().GetY();
1119  const REAL z34=this->GetAtom4().GetZ()-this->GetAtom3().GetZ();
1120 
1121  const REAL x23=this->GetAtom3().GetX()-this->GetAtom2().GetX();
1122  const REAL y23=this->GetAtom3().GetY()-this->GetAtom2().GetY();
1123  const REAL z23=this->GetAtom3().GetZ()-this->GetAtom2().GetZ();
1124 
1125  // v21 x v23
1126  const REAL x123= y21*z23-z21*y23;
1127  const REAL y123= z21*x23-x21*z23;
1128  const REAL z123= x21*y23-y21*x23;
1129 
1130  // v32 x v34 (= -v23 x v34)
1131  const REAL x234= -(y23*z34-z23*y34);
1132  const REAL y234= -(z23*x34-x23*z34);
1133  const REAL z234= -(x23*y34-y23*x34);
1134 
1135  const REAL n123= sqrt(x123*x123+y123*y123+z123*z123+1e-7);
1136  const REAL n234= sqrt(x234*x234+y234*y234+z234*z234+1e-6);
1137 
1138  const REAL p=x123*x234+y123*y234+z123*z234;
1139  const REAL a0=p/(n123*n234+1e-10);
1140  REAL angle;
1141  if(a0>= 1) angle=0;
1142  else
1143  {
1144  if(a0<=-1) angle=M_PI;
1145  else angle=acos(a0);
1146  }
1147  REAL sgn=1.0;
1148  if((x21*x34 + y21*y34 + z21*z34)<0) {angle=-angle;sgn=-1;}
1149 
1150 
1151  if(calcDeriv)
1152  {
1153  const REAL s=sgn/(sqrt(1-a0*a0+1e-6));
1154  const REAL s0=-s/(n123*n234+1e-10);
1155  const REAL s1= s*p/(n234*n123*n123*n123+1e-10);
1156  const REAL s3= s*p/(n123*n234*n234*n234+1e-10);
1157  mDerivAtom1.x=s0*(-z23*y234+y23*z234)+s1*(-z23*y123+y23*z123);
1158  mDerivAtom1.y=s0*(-x23*z234+z23*x234)+s1*(-x23*z123+z23*x123);
1159  mDerivAtom1.z=s0*(-y23*x234+x23*y234)+s1*(-y23*x123+x23*y123);
1160 
1161  mDerivAtom4.x=s0*(-z23*y123+y23*z123)+s3*(-z23*y234+y23*z234);
1162  mDerivAtom4.y=s0*(-x23*z123+z23*x123)+s3*(-x23*z234+z23*x234);
1163  mDerivAtom4.z=s0*(-y23*x123+x23*y123)+s3*(-y23*x234+x23*y234);
1164 
1165  mDerivAtom2.x=s0*((z23-z21)*y234-y123*z34+(y21-y23)*z234+z123*y34)+s1*(y123*(z23-z21)+z123*(y21-y23))+s3*(-y234*z34+z234*y34);
1166  mDerivAtom2.y=s0*((x23-x21)*z234-z123*x34+(z21-z23)*x234+x123*z34)+s1*(z123*(x23-x21)+x123*(z21-z23))+s3*(-z234*x34+x234*z34);
1167  mDerivAtom2.z=s0*((y23-y21)*x234-x123*y34+(x21-x23)*y234+y123*x34)+s1*(x123*(y23-y21)+y123*(x21-x23))+s3*(-x234*y34+y234*x34);
1168 
1169  mDerivAtom3.x=-(mDerivAtom1.x+mDerivAtom2.x+mDerivAtom4.x);
1170  mDerivAtom3.y=-(mDerivAtom1.y+mDerivAtom2.y+mDerivAtom4.y);
1171  mDerivAtom3.z=-(mDerivAtom1.z+mDerivAtom2.z+mDerivAtom4.z);
1172  }
1173 
1174  if(mSigma<1e-6)
1175  {
1176  if(calcDeriv) mDerivLLKCoeff=0;
1177  mLLK=0;
1178  return mLLK;
1179  }
1180  mLLK=angle-(mAngle0+mDelta);
1181  if(mLLK<(-M_PI)) mLLK += 2*M_PI;
1182  if(mLLK> M_PI ) mLLK -= 2*M_PI;
1183  if(mLLK>0)
1184  {
1185  mLLK/=mSigma;
1186  #ifdef RESTRAINT_X2_X4_X6
1187  const float mLLK2=mLLK*mLLK;
1188  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
1189  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
1190  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
1191  mLLK=mLLK2*(1+mLLK2);
1192  #else
1193  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
1194  mLLK *= mLLK;
1195  #endif
1196  VFN_DEBUG_EXIT("MolDihedralAngle::GetLogLikelihood():",2)
1197  return mLLK;
1198  }
1199  mLLK=angle-(mAngle0-mDelta);
1200  if(mLLK<(-M_PI)) mLLK += 2*M_PI;
1201  if(mLLK> M_PI ) mLLK -= 2*M_PI;
1202  if(mLLK<0)
1203  {
1204  mLLK/=mSigma;
1205  #ifdef RESTRAINT_X2_X4_X6
1206  const float mLLK2=mLLK*mLLK;
1207  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
1208  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
1209  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
1210  mLLK=mLLK2*(1+mLLK2);
1211  #else
1212  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
1213  mLLK *= mLLK;
1214  #endif
1215  VFN_DEBUG_EXIT("MolDihedralAngle::GetLogLikelihood():",2)
1216  return mLLK;
1217  }
1218  VFN_DEBUG_EXIT("MolDihedralAngle::GetLogLikelihood():",2)
1219  if(calcDeriv) mDerivLLKCoeff=0;
1220  mLLK=0;
1221  return 0;
1222 }
1223 
1224 REAL MolDihedralAngle::GetDeriv(const std::map<const MolAtom*,XYZ> &m,const bool llk)const
1225 {
1226  //TAU_PROFILE("MolDihedralAngle::GetDeriv()","REAL (mak,bool)",TAU_DEFAULT);
1227  REAL d=0;
1228  map<const MolAtom*,XYZ>::const_iterator pos;
1229  pos=m.find(mvpAtom[0]);
1230  if(pos!=m.end())
1231  d+= pos->second.x*mDerivAtom1.x
1232  +pos->second.y*mDerivAtom1.y
1233  +pos->second.z*mDerivAtom1.z;
1234  pos=m.find(mvpAtom[1]);
1235  if(pos!=m.end())
1236  d+= pos->second.x*mDerivAtom2.x
1237  +pos->second.y*mDerivAtom2.y
1238  +pos->second.z*mDerivAtom2.z;
1239  pos=m.find(mvpAtom[2]);
1240  if(pos!=m.end())
1241  d+= pos->second.x*mDerivAtom3.x
1242  +pos->second.y*mDerivAtom3.y
1243  +pos->second.z*mDerivAtom3.z;
1244  pos=m.find(mvpAtom[3]);
1245  if(pos!=m.end())
1246  d+= pos->second.x*mDerivAtom4.x
1247  +pos->second.y*mDerivAtom4.y
1248  +pos->second.z*mDerivAtom4.z;
1249  if(llk) return mDerivLLKCoeff*d;
1250  return d;
1251 }
1252 
1253 void MolDihedralAngle::CalcGradient(std::map<MolAtom*,XYZ> &m)const
1254 {
1255  this->GetLogLikelihood(true,true);
1256  map<MolAtom*,XYZ>::iterator pos;
1257  pos=m.find(mvpAtom[0]);
1258  if(pos!=m.end())
1259  {
1260  pos->second.x+=mDerivLLKCoeff*mDerivAtom1.x;
1261  pos->second.y+=mDerivLLKCoeff*mDerivAtom1.y;
1262  pos->second.z+=mDerivLLKCoeff*mDerivAtom1.z;
1263  }
1264  pos=m.find(mvpAtom[1]);
1265  if(pos!=m.end())
1266  {
1267  pos->second.x+=mDerivLLKCoeff*mDerivAtom2.x;
1268  pos->second.y+=mDerivLLKCoeff*mDerivAtom2.y;
1269  pos->second.z+=mDerivLLKCoeff*mDerivAtom2.z;
1270  }
1271  pos=m.find(mvpAtom[2]);
1272  if(pos!=m.end())
1273  {
1274  pos->second.x+=mDerivLLKCoeff*mDerivAtom3.x;
1275  pos->second.y+=mDerivLLKCoeff*mDerivAtom3.y;
1276  pos->second.z+=mDerivLLKCoeff*mDerivAtom3.z;
1277  }
1278  pos=m.find(mvpAtom[3]);
1279  if(pos!=m.end())
1280  {
1281  pos->second.x+=mDerivLLKCoeff*mDerivAtom4.x;
1282  pos->second.y+=mDerivLLKCoeff*mDerivAtom4.y;
1283  pos->second.z+=mDerivLLKCoeff*mDerivAtom4.z;
1284  }
1285  #if 0
1286  // Display gradient - for tests
1287  cout<<this->GetName()<<" :LLK"<<endl;
1288  for(map<MolAtom*,XYZ>::const_iterator pos=m.begin();pos!=m.end();++pos)
1289  {
1290  char buf[100];
1291  sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)",
1292  pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z);
1293  cout<<buf<<endl;
1294  }
1295  #endif
1296 }
1297 
1298 const MolAtom& MolDihedralAngle::GetAtom1()const{return *(mvpAtom[0]);}
1299 const MolAtom& MolDihedralAngle::GetAtom2()const{return *(mvpAtom[1]);}
1300 const MolAtom& MolDihedralAngle::GetAtom3()const{return *(mvpAtom[2]);}
1301 const MolAtom& MolDihedralAngle::GetAtom4()const{return *(mvpAtom[3]);}
1302 void MolDihedralAngle::SetAtom1(MolAtom& at){mvpAtom[0]=&at;}
1303 void MolDihedralAngle::SetAtom2(MolAtom& at){mvpAtom[1]=&at;}
1304 void MolDihedralAngle::SetAtom3(MolAtom& at){mvpAtom[2]=&at;}
1305 void MolDihedralAngle::SetAtom4(MolAtom& at){mvpAtom[3]=&at;}
1306 MolAtom& MolDihedralAngle::GetAtom1(){return *(mvpAtom[0]);}
1307 MolAtom& MolDihedralAngle::GetAtom2(){return *(mvpAtom[1]);}
1308 MolAtom& MolDihedralAngle::GetAtom3(){return *(mvpAtom[2]);}
1309 MolAtom& MolDihedralAngle::GetAtom4(){return *(mvpAtom[3]);}
1310 std::size_t MolDihedralAngle::size() const {return mvpAtom.size();}
1311 vector<MolAtom*>::const_iterator MolDihedralAngle::begin() const {return mvpAtom.begin();}
1312 vector<MolAtom*>::const_iterator MolDihedralAngle::end() const {return mvpAtom.end();}
1313 
1314 size_t MolDihedralAngle::int_ptr() const {return (size_t)this;}
1315 
1316 #ifdef __WX__CRYST__
1317 WXCrystObjBasic* MolDihedralAngle::WXCreate(wxWindow* parent)
1318 {
1319  VFN_DEBUG_ENTRY("MolDihedralAngle::WXCreate()",5)
1320  mpWXCrystObj=new WXMolDihedralAngle(parent,this);
1321  VFN_DEBUG_EXIT("MolDihedralAngle::WXCreate()",5)
1322  return mpWXCrystObj;
1323 }
1324 WXCrystObjBasic* MolDihedralAngle::WXGet(){return mpWXCrystObj;}
1325 void MolDihedralAngle::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;}
1326 void MolDihedralAngle::WXNotifyDelete(){mpWXCrystObj=0;}
1327 #endif
1328 //######################################################################
1329 //
1330 // RigidGroup
1331 //
1332 //######################################################################
1333 string RigidGroup::GetName()const
1334 {
1335  set<MolAtom *>::const_iterator at=this->begin();
1336  string name=(*at++)->GetName();
1337  for(;at!=this->end();++at) name+=", "+(*at)->GetName();
1338  return name;
1339 }
1340 
1341 size_t RigidGroup::int_ptr() const {return (size_t)this;}
1342 
1343 //######################################################################
1344 //
1345 // MolRing
1346 //
1347 //######################################################################
1348 MolRing::MolRing()
1349 {}
1350 
1351 const std::list<MolAtom*>& MolRing::GetAtomList()const
1352 {return mvpAtom;}
1353 
1354 std::list<MolAtom*>& MolRing::GetAtomList()
1355 {return mvpAtom;}
1356 
1357 size_t MolRing::int_ptr() const {return (size_t)this;}
1358 
1359 //######################################################################
1360 //
1361 // Quaternion
1362 //
1363 //######################################################################
1365 mQ0(1),mQ1(0),mQ2(0),mQ3(0),mIsUniQuaternion(true)
1366 {
1367  VFN_DEBUG_MESSAGE("Quaternion::Quaternion()",5)
1368 }
1369 
1371  const REAL q1,
1372  const REAL q2,
1373  const REAL q3,
1374  bool unit):
1375 mQ0(q0),mQ1(q1),mQ2(q2),mQ3(q3),mIsUniQuaternion(unit)
1376 {
1377  VFN_DEBUG_MESSAGE("Quaternion::Quaternion()",5)
1378  if(unit) this->Normalize();
1379 }
1380 
1381 Quaternion::~Quaternion()
1382 {
1383  VFN_DEBUG_MESSAGE("Quaternion::~Quaternion()",5)
1384 }
1385 
1387  const REAL v1,
1388  const REAL v2,
1389  const REAL v3)
1390 {
1391  VFN_DEBUG_MESSAGE("Quaternion::RotationQuaternion()",4)
1392  const REAL s=sin(ang/2.)/sqrt(v1*v1+v2*v2+v3*v3+1e-7);
1393  return Quaternion(cos(ang/2.),s*v1,s*v2,s*v3,
1394  true);
1395 }
1396 
1398 {
1399  return Quaternion(mQ0,-mQ1,-mQ2,-mQ3);
1400 }
1402 {
1403  // http://www.cs.berkeley.edu/~laura/cs184/quat/quaternion.html
1404  return Quaternion
1405  (this->Q0()*q.Q0()-this->Q1()*q.Q1()-this->Q2()*q.Q2()-this->Q3()*q.Q3(),
1406  this->Q0()*q.Q1()+this->Q1()*q.Q0()+this->Q2()*q.Q3()-this->Q3()*q.Q2(),
1407  this->Q0()*q.Q2()-this->Q1()*q.Q3()+this->Q2()*q.Q0()+this->Q3()*q.Q1(),
1408  this->Q0()*q.Q3()+this->Q1()*q.Q2()-this->Q2()*q.Q1()+this->Q3()*q.Q0(),false);
1409 }
1410 
1411 void Quaternion::operator*=(const Quaternion &q)
1412 {
1413  //cout<<"Quaternion::operator*= before:";this->XMLOutput(cout);
1414  //cout<<"Quaternion::operator*= by :";q.XMLOutput(cout);
1415  const REAL q1=this->Q0()*q.Q1()+this->Q1()*q.Q0()+this->Q2()*q.Q3()-this->Q3()*q.Q2();
1416  const REAL q2=this->Q0()*q.Q2()+this->Q2()*q.Q0()-this->Q1()*q.Q3()+this->Q3()*q.Q1();
1417  const REAL q3=this->Q0()*q.Q3()+this->Q3()*q.Q0()+this->Q1()*q.Q2()-this->Q2()*q.Q1();
1418  this->Q0()= this->Q0()*q.Q0()-this->Q1()*q.Q1()-this->Q2()*q.Q2()-this->Q3()*q.Q3();
1419  this->Q1()=q1;
1420  this->Q2()=q2;
1421  this->Q3()=q3;
1422  this->Normalize();
1423  //cout<<"Quaternion::operator*= after :";this->XMLOutput(cout);
1424 }
1425 
1426 void Quaternion::XMLOutput(ostream &os,int indent)const
1427 {
1428  VFN_DEBUG_ENTRY("Quaternion::XMLOutput()",4)
1429  for(int i=0;i<indent;i++) os << " " ;
1430  XMLCrystTag tag("Quaternion",false,true);
1431  //#error "which atoms for this bond ?"
1432  {
1433  stringstream ss;
1434  ss.precision(os.precision());
1435  ss <<mQ0;
1436  tag.AddAttribute("Q0",ss.str());
1437  }
1438  {
1439  stringstream ss;
1440  ss.precision(os.precision());
1441  ss <<mQ1;
1442  tag.AddAttribute("Q1",ss.str());
1443  }
1444  {
1445  stringstream ss;
1446  ss.precision(os.precision());
1447  ss <<mQ2;
1448  tag.AddAttribute("Q2",ss.str());
1449  }
1450  {
1451  stringstream ss;
1452  ss.precision(os.precision());
1453  ss <<mQ3;
1454  tag.AddAttribute("Q3",ss.str());
1455  }
1456  {
1457  stringstream ss;
1458  ss.precision(os.precision());
1459  ss <<mIsUniQuaternion;
1460  tag.AddAttribute("IsUnitQuaternion",ss.str());
1461  }
1462  os <<tag<<endl;
1463  VFN_DEBUG_EXIT("Quaternion::XMLOutput()",4)
1464 }
1465 
1466 void Quaternion::XMLInput(istream &is,const XMLCrystTag &tag)
1467 {
1468  VFN_DEBUG_ENTRY("Quaternion::XMLInput()",5)
1469  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
1470  {
1471  if("Q0"==tag.GetAttributeName(i))
1472  {
1473  stringstream ss(tag.GetAttributeValue(i));
1474  ss >>mQ0;
1475  }
1476  if("Q1"==tag.GetAttributeName(i))
1477  {
1478  stringstream ss(tag.GetAttributeValue(i));
1479  ss >>mQ1;
1480  }
1481  if("Q2"==tag.GetAttributeName(i))
1482  {
1483  stringstream ss(tag.GetAttributeValue(i));
1484  ss >>mQ2;
1485  }
1486  if("Q3"==tag.GetAttributeName(i))
1487  {
1488  stringstream ss(tag.GetAttributeValue(i));
1489  ss >>mQ3;
1490  }
1491  if("IsUnitQuaternion"==tag.GetAttributeName(i))
1492  {
1493  stringstream ss(tag.GetAttributeValue(i));
1494  ss >>mIsUniQuaternion;
1495  }
1496  }
1497  if(mIsUniQuaternion) this->Normalize();
1498  VFN_DEBUG_EXIT("Quaternion::XMLInput()",5)
1499 }
1500 
1501 void Quaternion::RotateVector(REAL &v1,REAL &v2, REAL &v3)const
1502 {
1503  #if 0
1504  //#error P should not be a _UNIT_ quaternion...
1505  Quaternion P(0,v1,v2,v3,false);
1506  //cout<<"RotQuat:(n="<<this->GetNorm()<<")";this->XMLOutput(cout);
1507  //cout<<"before :(n="<<P.GetNorm()<<")";P.XMLOutput(cout);
1508  P= (*this)* P * this->GetConjugate();
1509  //cout<<"rotated:(n="<<P.GetNorm()<<")";P.XMLOutput(cout);
1510  v1=P.Q1();
1511  v2=P.Q2();
1512  v3=P.Q3();
1513  #endif
1514  const REAL p0=-mQ1*v1 - mQ2*v2 - mQ3*v3;
1515  const REAL p1= mQ0*v1 + mQ2*v3 - mQ3*v2;
1516  const REAL p2= mQ0*v2 - mQ1*v3 + mQ3*v1;
1517  const REAL p3= mQ0*v3 + mQ1*v2 - mQ2*v1;
1518 
1519  v1 =-p0*mQ1 + p1*mQ0 - p2*mQ3 + p3*mQ2;
1520  v2 =-p0*mQ2 + p2*mQ0 + p1*mQ3 - p3*mQ1;
1521  v3 =-p0*mQ3 + p3*mQ0 - p1*mQ2 + p2*mQ1;
1522 }
1523 
1525 {
1526  const REAL norm=sqrt( this->Q0()*this->Q0()
1527  +this->Q1()*this->Q1()
1528  +this->Q2()*this->Q2()
1529  +this->Q3()*this->Q3());
1530  mQ0 /= norm;
1531  mQ1 /= norm;
1532  mQ2 /= norm;
1533  mQ3 /= norm;
1534 }
1535 REAL Quaternion::GetNorm()const
1536 {return sqrt( this->Q0()*this->Q0()
1537  +this->Q1()*this->Q1()
1538  +this->Q2()*this->Q2()
1539  +this->Q3()*this->Q3());}
1540 
1541 const REAL& Quaternion::Q0()const{return mQ0;}
1542 const REAL& Quaternion::Q1()const{return mQ1;}
1543 const REAL& Quaternion::Q2()const{return mQ2;}
1544 const REAL& Quaternion::Q3()const{return mQ3;}
1545 REAL& Quaternion::Q0(){return mQ0;}
1546 REAL& Quaternion::Q1(){return mQ1;}
1547 REAL& Quaternion::Q2(){return mQ2;}
1548 REAL& Quaternion::Q3(){return mQ3;}
1549 //######################################################################
1550 //
1551 // Molecule Stretch Modes
1552 //
1553 //######################################################################
1554 StretchMode::~StretchMode(){}
1555 
1557  const MolBond *pBond):
1558 mpAtom0(&at0),mpAtom1(&at1),mpBond(pBond)
1559 {
1560  mBaseAmplitude=0.1;
1561  mpMol = &(at1.GetMolecule());
1562 }
1563 
1564 StretchModeBondLength::~StretchModeBondLength(){}
1565 
1566 void StretchModeBondLength::CalcDeriv(const bool derivllk)const
1567 {
1568  //TAU_PROFILE("StretchModeBondLength::CalcDeriv()","void ()",TAU_DEFAULT);
1569  // Derivative of the atom positions
1570  //mDerivXYZ.clear();
1571  REAL dx=mpAtom1->GetX()-mpAtom0->GetX();
1572  REAL dy=mpAtom1->GetY()-mpAtom0->GetY();
1573  REAL dz=mpAtom1->GetZ()-mpAtom0->GetZ();
1574  const REAL n=sqrt(dx*dx+dy*dy+dz*dz+1e-7);
1575  if(n<1e-6) return;//:KLUDGE: ?
1576  dx/=n;
1577  dy/=n;
1578  dz/=n;
1579  for(set<MolAtom *>::const_iterator pos=mvTranslatedAtomList.begin();
1580  pos!=mvTranslatedAtomList.end();++pos)
1581  {
1582  XYZ *const p=&(mDerivXYZ[*pos]);
1583  p->x=dx;
1584  p->y=dy;
1585  p->z=dz;
1586  }
1587  // Derivative of the LLK
1588  if(derivllk)
1589  {
1590  mLLKDeriv=0;
1591  for(map<const MolBond*,REAL>::const_iterator pos=this->mvpBrokenBond.begin();
1592  pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1593  for(map<const MolBondAngle*,REAL>::const_iterator pos=this->mvpBrokenBondAngle.begin();
1594  pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1595  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=this->mvpBrokenDihedralAngle.begin();
1596  pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1597  }
1598 }
1599 
1600 void StretchModeBondLength::Print(ostream &os,bool full)const
1601 {
1602  cout<<mpAtom0->GetName()<<"-"<<mpAtom1->GetName();
1603  if(full)
1604  {
1605  cout<<", Translated Atoms:";
1606  for(set<MolAtom*>::const_iterator atom=mvTranslatedAtomList.begin();
1607  atom!=mvTranslatedAtomList.end();++atom)
1608  {
1609  cout<<(*atom)->GetName()<<",";
1610  }
1611  }
1612 }
1613 
1614 void StretchModeBondLength::Stretch(const REAL amplitude,
1615  const bool keepCenter)
1616 {
1617  REAL dx=mpAtom1->GetX()-mpAtom0->GetX();
1618  REAL dy=mpAtom1->GetY()-mpAtom0->GetY();
1619  REAL dz=mpAtom1->GetZ()-mpAtom0->GetZ();
1620  const REAL l=sqrt(dx*dx+dy*dy+dz*dz+1e-7);
1621  if(l<1e-6) return;// :KLUDGE:
1622  const REAL change=amplitude/l;
1623  dx*=change;
1624  dy*=change;
1625  dz*=change;
1626  mpMol->TranslateAtomGroup(mvTranslatedAtomList,dx,dy,dz,keepCenter);
1627 }
1628 
1629 void StretchModeBondLength::RandomStretch(const REAL amplitude,
1630  const bool keepCenter)
1631 {
1632  mpMol->BondLengthRandomChange(*this,amplitude,keepCenter);
1633 }
1634 
1636  const MolBondAngle *pBondAngle):
1637 mpAtom0(&at0),mpAtom1(&at1),mpAtom2(&at2),mpBondAngle(pBondAngle)
1638 {
1639  mBaseAmplitude=M_PI*0.02;
1640  mpMol = &(at1.GetMolecule());
1641 }
1642 
1643 StretchModeBondAngle::~StretchModeBondAngle(){}
1644 
1645 void StretchModeBondAngle::CalcDeriv(const bool derivllk)const
1646 {
1647  //TAU_PROFILE("StretchModeBondAngle::CalcDeriv()","void ()",TAU_DEFAULT);
1648  // Derivative of the atomic positions
1649  const REAL x1=mpAtom1->GetX(),
1650  y1=mpAtom1->GetY(),
1651  z1=mpAtom1->GetZ();
1652 
1653  const REAL dx10=mpAtom0->GetX()-x1,
1654  dy10=mpAtom0->GetY()-y1,
1655  dz10=mpAtom0->GetZ()-z1,
1656  dx12=mpAtom2->GetX()-x1,
1657  dy12=mpAtom2->GetY()-y1,
1658  dz12=mpAtom2->GetZ()-z1;
1659 
1660  REAL vx=dy10*dz12-dz10*dy12,
1661  vy=dz10*dx12-dx10*dz12,
1662  vz=dx10*dy12-dy10*dx12;
1663  //const REAL n=sqrt((dx10*dx10+dy10*dy10+dz10*dz10)*(dx12*dx12+dy12*dy12+dz12*dz12))+1e-10;
1664  const REAL n=sqrt(vx*vx+vy*vy+vz*vz+1e-10);
1665  vx/=n;
1666  vy/=n;
1667  vz/=n;
1668 
1669  if(n<1e-6)
1670  {
1671  mDerivXYZ.clear();
1672  return;//:KLUDGE: ?
1673  }
1674 
1675  for(set<MolAtom *>::const_iterator pos=mvRotatedAtomList.begin();
1676  pos!=mvRotatedAtomList.end();++pos)
1677  {
1678  XYZ *const p=&(mDerivXYZ[*pos]);
1679  const REAL x=(*pos)->GetX()-x1,
1680  y=(*pos)->GetY()-y1,
1681  z=(*pos)->GetZ()-z1;
1682  p->x=z*vy-y*vz;
1683  p->y=x*vz-z*vx;
1684  p->z=y*vx-x*vy;
1685  }
1686  // Derivative of the LLK
1687  if(derivllk)
1688  {
1689  mLLKDeriv=0;
1690  for(map<const MolBond*,REAL>::const_iterator pos=this->mvpBrokenBond.begin();
1691  pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1692  for(map<const MolBondAngle*,REAL>::const_iterator pos=this->mvpBrokenBondAngle.begin();
1693  pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1694  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=this->mvpBrokenDihedralAngle.begin();
1695  pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1696  }
1697 }
1698 
1699 void StretchModeBondAngle::Print(ostream &os,bool full)const
1700 {
1701  cout<<mpAtom0->GetName()<<"-"<<mpAtom1->GetName()<<"-"<<mpAtom2->GetName();
1702  if(full)
1703  {
1704  cout<<", Rotated Atoms:";
1705  for(set<MolAtom*>::const_iterator atom=mvRotatedAtomList.begin();
1706  atom!=mvRotatedAtomList.end();++atom)
1707  {
1708  cout<<(*atom)->GetName()<<",";
1709  }
1710  }
1711 }
1712 
1713 void StretchModeBondAngle::Stretch(const REAL amplitude,
1714  const bool keepCenter)
1715 {
1716  REAL dx10=mpAtom0->GetX()-mpAtom1->GetX();
1717  REAL dy10=mpAtom0->GetY()-mpAtom1->GetY();
1718  REAL dz10=mpAtom0->GetZ()-mpAtom1->GetZ();
1719  REAL dx12=mpAtom2->GetX()-mpAtom1->GetX();
1720  REAL dy12=mpAtom2->GetY()-mpAtom1->GetY();
1721  REAL dz12=mpAtom2->GetZ()-mpAtom1->GetZ();
1722 
1723  const REAL vx=dy10*dz12-dz10*dy12;
1724  const REAL vy=dz10*dx12-dx10*dz12;
1725  const REAL vz=dx10*dy12-dy10*dx12;
1726  mpMol->RotateAtomGroup(*mpAtom1,vx,vy,vz,mvRotatedAtomList,amplitude,keepCenter);
1727 }
1728 
1729 void StretchModeBondAngle::RandomStretch(const REAL amplitude,
1730  const bool keepCenter)
1731 {
1732  mpMol->BondAngleRandomChange(*this,amplitude,keepCenter);
1733 }
1734 
1736  const MolDihedralAngle *pAngle):
1737 mpAtom1(&at1),mpAtom2(&at2),mpDihedralAngle(pAngle)
1738 {
1739  mBaseAmplitude=M_PI*0.02;
1740  mpMol = &(at1.GetMolecule());
1741 }
1742 
1743 StretchModeTorsion::~StretchModeTorsion(){}
1744 
1745 void StretchModeTorsion::CalcDeriv(const bool derivllk)const
1746 {
1747  //TAU_PROFILE("StretchModeTorsion::CalcDeriv()","void ()",TAU_DEFAULT);
1748  // Derivative of the LLK
1749  //mDerivXYZ.clear();
1750  const REAL x1=mpAtom1->GetX(),
1751  y1=mpAtom1->GetY(),
1752  z1=mpAtom1->GetZ();
1753 
1754  REAL vx=mpAtom2->GetX()-x1,
1755  vy=mpAtom2->GetY()-y1,
1756  vz=mpAtom2->GetZ()-z1;
1757 
1758  const REAL n=sqrt(vx*vx+vy*vy+vz*vz+1e-10);
1759  vx/=n;
1760  vy/=n;
1761  vz/=n;
1762 
1763  for(set<MolAtom *>::const_iterator pos=mvRotatedAtomList.begin();
1764  pos!=mvRotatedAtomList.end();++pos)
1765  {
1766  XYZ *const p=&(mDerivXYZ[*pos]);
1767  const REAL x=(*pos)->GetX()-x1,
1768  y=(*pos)->GetY()-y1,
1769  z=(*pos)->GetZ()-z1;
1770  p->x=z*vy-y*vz;
1771  p->y=x*vz-z*vx;
1772  p->z=y*vx-x*vy;
1773  }
1774  // Derivative of the LLK
1775  if(derivllk)
1776  {
1777  mLLKDeriv=0;
1778  for(map<const MolBond*,REAL>::const_iterator pos=this->mvpBrokenBond.begin();
1779  pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1780  for(map<const MolBondAngle*,REAL>::const_iterator pos=this->mvpBrokenBondAngle.begin();
1781  pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1782  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=this->mvpBrokenDihedralAngle.begin();
1783  pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1784  }
1785 }
1786 
1787 void StretchModeTorsion::Print(ostream &os,bool full)const
1788 {
1789  cout<<mpAtom1->GetName()<<"-"<<mpAtom2->GetName();
1790  if(full)
1791  {
1792  cout<<", Rotated Atoms:";
1793  for(set<MolAtom*>::const_iterator atom=mvRotatedAtomList.begin();
1794  atom!=mvRotatedAtomList.end();++atom)
1795  {
1796  cout<<(*atom)->GetName()<<",";
1797  }
1798  }
1799 }
1800 
1801 void StretchModeTorsion::Stretch(const REAL amplitude, const bool keepCenter)
1802 {
1803  mpMol->RotateAtomGroup(*mpAtom1,*mpAtom2,mvRotatedAtomList,amplitude,keepCenter);
1804 }
1805 
1806 void StretchModeTorsion::RandomStretch(const REAL amplitude,
1807  const bool keepCenter)
1808 {
1809  mpMol->DihedralAngleRandomChange(*this,amplitude,keepCenter);
1810 }
1811 
1812 
1813 //######################################################################
1814 //
1815 // StretchModeTwist
1816 //
1817 //######################################################################
1819 mpAtom1(&at1),mpAtom2(&at2)
1820 {
1821  mBaseAmplitude=M_PI*0.02;
1822  mpMol = &(at1.GetMolecule());
1823 }
1824 
1825 StretchModeTwist::~StretchModeTwist(){}
1826 
1827 void StretchModeTwist::CalcDeriv(const bool derivllk)const
1828 {// Identical to StretchModeTorsion::CalcDeriv()
1829  // Derivative of the LLK
1830  //mDerivXYZ.clear();
1831  const REAL x1=mpAtom1->GetX(),
1832  y1=mpAtom1->GetY(),
1833  z1=mpAtom1->GetZ();
1834 
1835  REAL vx=mpAtom2->GetX()-x1,
1836  vy=mpAtom2->GetY()-y1,
1837  vz=mpAtom2->GetZ()-z1;
1838 
1839  const REAL n=sqrt(vx*vx+vy*vy+vz*vz+1e-10);
1840  vx/=n;
1841  vy/=n;
1842  vz/=n;
1843 
1844  for(set<MolAtom *>::const_iterator pos=mvRotatedAtomList.begin();
1845  pos!=mvRotatedAtomList.end();++pos)
1846  {
1847  XYZ *const p=&(mDerivXYZ[*pos]);
1848  const REAL x=(*pos)->GetX()-x1,
1849  y=(*pos)->GetY()-y1,
1850  z=(*pos)->GetZ()-z1;
1851  p->x=z*vy-y*vz;
1852  p->y=x*vz-z*vx;
1853  p->z=y*vx-x*vy;
1854  }
1855  // Derivative of the LLK
1856  if(derivllk)
1857  {
1858  mLLKDeriv=0;
1859  for(map<const MolBond*,REAL>::const_iterator pos=this->mvpBrokenBond.begin();
1860  pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1861  for(map<const MolBondAngle*,REAL>::const_iterator pos=this->mvpBrokenBondAngle.begin();
1862  pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1863  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=this->mvpBrokenDihedralAngle.begin();
1864  pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1865  }
1866 }
1867 
1868 void StretchModeTwist::Print(ostream &os,bool full)const
1869 {
1870  os<<mpAtom1->GetName()<<"/"<<mpAtom2->GetName()<<"-"<<mpAtom2->GetName();
1871  if(full)
1872  {
1873  os<<", Rotated Atoms:";
1874  for(set<MolAtom*>::const_iterator atom=mvRotatedAtomList.begin();
1875  atom!=mvRotatedAtomList.end();++atom)
1876  {
1877  os<<(*atom)->GetName()<<",";
1878  }
1879  }
1880 }
1881 
1882 void StretchModeTwist::Stretch(const REAL amplitude, const bool keepCenter)
1883 {
1884  mpMol->RotateAtomGroup(*mpAtom1,*mpAtom2,mvRotatedAtomList,amplitude,keepCenter);
1885 }
1886 
1887 void StretchModeTwist::RandomStretch(const REAL amplitude,
1888  const bool keepCenter)
1889 {
1890  const REAL dx=mpAtom2->GetX()-mpAtom1->GetX();
1891  const REAL dy=mpAtom2->GetY()-mpAtom1->GetY();
1892  const REAL dz=mpAtom2->GetZ()-mpAtom1->GetZ();
1893  if((abs(dx)+abs(dy)+abs(dz))<1e-6) return;// :KLUDGE:
1894  const REAL change=(REAL)(2.*rand()-RAND_MAX)/(REAL)RAND_MAX*mBaseAmplitude*amplitude;
1895  mpMol->RotateAtomGroup(*mpAtom1,*mpAtom2,mvRotatedAtomList,change,keepCenter);
1896 }
1897 
1898 //######################################################################
1899 //
1900 // MDAtomGroup
1901 //
1902 //######################################################################
1904 
1905 MDAtomGroup::MDAtomGroup(set<MolAtom*> &vat,
1906  set<MolBond*> &vb,
1907  set<MolBondAngle*> &va,
1908  set<MolDihedralAngle*> &vd):
1909 mvpAtom(vat)
1910 {
1911  // Use vector instead of sets for MolecularDynamicsEvolve & general
1912  // storage in molecule compatibility
1913  for(set<MolBond*>::iterator pos=vb.begin();pos!=vb.end();++pos)
1914  mvpBond.push_back(*pos);
1915  for(set<MolBondAngle*>::iterator pos=va.begin();pos!=va.end();++pos)
1916  mvpBondAngle.push_back(*pos);
1917  for(set<MolDihedralAngle*>::iterator pos=vd.begin();pos!=vd.end();++pos)
1918  mvpDihedralAngle.push_back(*pos);
1919 }
1920 
1921 void MDAtomGroup::Print(ostream &os,bool full)const
1922 {
1923  if(full) os<<"MDAtomGroup: ";
1924  for(set<MolAtom*>::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
1925  os<<(*pos)->GetName()<<" ";
1926  if(full)
1927  {
1928  os<<endl<<" Involving bond restraints:";
1929  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
1930  os<<(*pos)->GetName()<<" ";
1931  os<<endl<<" Involving bond angle restraints:";
1932  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
1933  os<<(*pos)->GetName()<<" ";
1934  os<<endl<<" Involving dihedral angle restraints:";
1935  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos)
1936  os<<(*pos)->GetName()<<" ";
1937  os<<endl;
1938  }
1939 }
1940 
1941 //######################################################################
1942 //
1943 // Molecule
1944 //
1945 //######################################################################
1946 Molecule::Molecule(Crystal &cryst, const string &name):
1947 mDeleteSubObjInDestructor(1), mBaseRotationAmplitude(M_PI*0.02), mIsSelfOptimizing(false),
1948 mpCenterAtom(0), mMDMoveFreq(0.0), mMDMoveEnergy(40.), mLogLikelihoodScale(1.0)
1949 {
1950  VFN_DEBUG_MESSAGE("Molecule::Molecule()",5)
1951  mpCryst=&cryst;
1952  {
1953  RefinablePar tmp(name+"_x",&mXYZ(0),0.,1.,
1954  gpRefParTypeScattTranslX,
1955  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
1957  tmp.SetDerivStep(1e-5);
1958  this->AddPar(tmp);
1959  }
1960  {
1961  RefinablePar tmp(name+"_y",&mXYZ(1),0,1,
1962  gpRefParTypeScattTranslY,
1963  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
1965  tmp.SetDerivStep(1e-5);
1966  this->AddPar(tmp);
1967  }
1968  {
1969  RefinablePar tmp(name+"_z",&mXYZ(2),0,1,
1970  gpRefParTypeScattTranslZ,
1971  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
1973  tmp.SetDerivStep(1e-5);
1974  this->AddPar(tmp);
1975  }
1976  {
1977  RefinablePar tmp(name+"_Occ",&mOccupancy,0,1,
1978  gpRefParTypeScattOccup,
1979  REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.,1.);
1981  tmp.SetDerivStep(1e-5);
1982  this->AddPar(tmp);
1983  }
1984  {
1985  RefinablePar tmp(name+"_Q0",&(mQuat.Q0()),0,1,
1986  gpRefParTypeScattOrient,
1987  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
1989  tmp.SetGlobalOptimStep(0.04);
1990  tmp.SetDerivStep(1e-4);
1991  this->AddPar(tmp);
1992  }
1993  {
1994  RefinablePar tmp(name+"_Q1",&(mQuat.Q1()),0,1,
1995  gpRefParTypeScattOrient,
1996  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
1998  tmp.SetGlobalOptimStep(0.04);
1999  tmp.SetDerivStep(1e-4);
2000  this->AddPar(tmp);
2001  }
2002  {
2003  RefinablePar tmp(name+"_Q2",&(mQuat.Q2()),0,1,
2004  gpRefParTypeScattOrient,
2005  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
2007  tmp.SetGlobalOptimStep(0.04);
2008  tmp.SetDerivStep(1e-4);
2009  this->AddPar(tmp);
2010  }
2011  {
2012  RefinablePar tmp(name+"_Q3",&(mQuat.Q3()),0,1,
2013  gpRefParTypeScattOrient,
2014  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
2016  tmp.SetGlobalOptimStep(0.04);
2017  tmp.SetDerivStep(1e-4);
2018  this->AddPar(tmp);
2019  }
2020  this->SetName(name);
2021  mLocalParamSet=this->CreateParamSet("saved parameters for local minimization");
2022  this->InitOptions();
2023  mClockScatterer.AddChild(mClockAtomList);
2024  mClockScatterer.AddChild(mClockBondList);
2025  mClockScatterer.AddChild(mClockBondAngleList);
2026  mClockScatterer.AddChild(mClockDihedralAngleList);
2027  mClockScatterer.AddChild(mClockRingList);
2028  mClockScatterer.AddChild(mClockRigidGroup);
2029  mClockScatterer.AddChild(mClockAtomPosition);
2030  mClockScatterer.AddChild(mClockAtomScattPow);
2031  mClockScatterer.AddChild(mClockOrientation);
2032 }
2033 
2035 mDeleteSubObjInDestructor(old.mDeleteSubObjInDestructor), mIsSelfOptimizing(false), mpCenterAtom(0)
2036 {
2037  VFN_DEBUG_ENTRY("Molecule::Molecule(old&)",5)
2038  // a hack, but const-correct
2039  mpCryst=&(gCrystalRegistry.GetObj(gCrystalRegistry.Find(old.GetCrystal())));
2040  {
2041  RefinablePar tmp(this->GetName()+"_x",&mXYZ(0),0.,1.,
2042  gpRefParTypeScattTranslX,
2043  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
2045  tmp.SetDerivStep(1e-5);
2046  this->AddPar(tmp);
2047  }
2048  {
2049  RefinablePar tmp(this->GetName()+"_y",&mXYZ(1),0,1,
2050  gpRefParTypeScattTranslY,
2051  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
2053  tmp.SetDerivStep(1e-5);
2054  this->AddPar(tmp);
2055  }
2056  {
2057  RefinablePar tmp(this->GetName()+"_z",&mXYZ(2),0,1,
2058  gpRefParTypeScattTranslZ,
2059  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
2061  tmp.SetDerivStep(1e-5);
2062  this->AddPar(tmp);
2063  }
2064  {
2065  RefinablePar tmp(this->GetName()+"_Occ",&mOccupancy,0,1,
2066  gpRefParTypeScattOccup,
2067  REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.,1.);
2069  tmp.SetDerivStep(1e-5);
2070  this->AddPar(tmp);
2071  }
2072  {
2073  RefinablePar tmp(this->GetName()+"Q0",&(mQuat.Q0()),0,1,
2074  gpRefParTypeScattOrient,
2075  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
2077  tmp.SetGlobalOptimStep(0.04);
2078  tmp.SetDerivStep(1e-4);
2079  this->AddPar(tmp);
2080  }
2081  {
2082  RefinablePar tmp(this->GetName()+"Q1",&(mQuat.Q1()),0,1,
2083  gpRefParTypeScattOrient,
2084  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
2086  tmp.SetGlobalOptimStep(0.04);
2087  tmp.SetDerivStep(1e-4);
2088  this->AddPar(tmp);
2089  }
2090  {
2091  RefinablePar tmp(this->GetName()+"Q2",&(mQuat.Q2()),0,1,
2092  gpRefParTypeScattOrient,
2093  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
2095  tmp.SetGlobalOptimStep(0.04);
2096  tmp.SetDerivStep(1e-4);
2097  this->AddPar(tmp);
2098  }
2099  {
2100  RefinablePar tmp(this->GetName()+"Q3",&(mQuat.Q3()),0,1,
2101  gpRefParTypeScattOrient,
2102  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
2104  tmp.SetGlobalOptimStep(0.04);
2105  tmp.SetDerivStep(1e-4);
2106  this->AddPar(tmp);
2107  }
2108  mLocalParamSet=this->CreateParamSet("saved parameters for local minimization");
2109  this->InitOptions();
2110  mClockScatterer.AddChild(mClockAtomList);
2111  mClockScatterer.AddChild(mClockBondList);
2112  mClockScatterer.AddChild(mClockBondAngleList);
2113  mClockScatterer.AddChild(mClockDihedralAngleList);
2114  mClockScatterer.AddChild(mClockRingList);
2115  mClockScatterer.AddChild(mClockRigidGroup);
2116  mClockScatterer.AddChild(mClockAtomPosition);
2117  mClockScatterer.AddChild(mClockAtomScattPow);
2118  mClockScatterer.AddChild(mClockOrientation);
2119 
2120  mClockRestraint.AddChild(mClockAtomList);
2121  mClockRestraint.AddChild(mClockBondList);
2122  mClockRestraint.AddChild(mClockBondAngleList);
2123  mClockRestraint.AddChild(mClockDihedralAngleList);
2124  mClockRestraint.AddChild(mClockRingList);
2125  mClockRestraint.AddChild(mClockRigidGroup);
2126 
2127  stringstream str;
2128  old.XMLOutput(str);
2129  XMLCrystTag tag(str);
2130  this->XMLInput(str,tag);
2131  VFN_DEBUG_EXIT("Molecule::Molecule(old&)",5)
2132 }
2133 
2135 {
2136  VFN_DEBUG_ENTRY("Molecule::~Molecule()",5)
2138  {
2139  {
2140  vector<MolAtom*>::iterator pos;
2141  for(pos=mvpAtom.begin();pos!=mvpAtom.end();pos++) delete *pos;
2142  }
2143  {
2144  vector<MolBond*>::iterator pos;
2145  for(pos=mvpBond.begin();pos!=mvpBond.end();pos++) delete *pos;
2146  }
2147  {
2148  vector<MolBondAngle*>::iterator pos;
2149  for(pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();pos++) delete *pos;
2150  }
2151  {
2152  vector<MolDihedralAngle*>::iterator pos;
2153  for(pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();pos++) delete *pos;
2154  }
2155  }
2156  VFN_DEBUG_EXIT("Molecule::~Molecule()",5)
2157 }
2158 
2160 {
2161  VFN_DEBUG_MESSAGE("Molecule::CreateCopy()",5)
2162  return new Molecule(*this);
2163 }
2164 
2165 const string& Molecule::GetClassName() const
2166 {
2167  static const string className="Molecule";
2168  return className;
2169 }
2170 
2171 void Molecule::SetName(const string &name)
2172 {
2173  if(mName==name) return;
2174  this->RefinableObj::SetName(name);
2175  // Set parameter's name including the Molecule's name
2176  try
2177  {
2178  this->GetPar(&mXYZ(0)).SetName(mName+"_x");
2179  this->GetPar(&mXYZ(1)).SetName(mName+"_y");
2180  this->GetPar(&mXYZ(2)).SetName(mName+"_z");
2181  this->GetPar(&mOccupancy).SetName(mName+"_Occ");
2182  this->GetPar(&(mQuat.Q0())).SetName(mName+"_Q0");
2183  this->GetPar(&(mQuat.Q1())).SetName(mName+"_Q1");
2184  this->GetPar(&(mQuat.Q2())).SetName(mName+"_Q2");
2185  this->GetPar(&(mQuat.Q3())).SetName(mName+"_Q3");
2186  }
2187  catch(const ObjCrystException &except)
2188  {
2189  cerr<<"Molecule::SetName(): parameters not yet declared in a Molecule ?"<<endl;
2190  }
2191 }
2192 
2193 std::string Molecule::GetFormula() const
2194 {
2195  if(this->GetNbComponent()==0) return "";
2196  std::map<std::string,float> velts;
2197  for(std::vector<MolAtom*>::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
2198  {
2199  if((*pos)->IsDummy()) continue;
2200  string p=(*pos)->GetScatteringPower().GetSymbol();
2201  if(velts.count(p)==0)
2202  velts[p]=(*pos)->GetOccupancy();
2203  else velts[p]+=(*pos)->GetOccupancy();
2204  }
2205  stringstream s;
2206  s<<std::setprecision(2);
2207  for(std::map<std::string,float>::const_iterator pos=velts.begin();pos!=velts.end();++pos)
2208  {
2209  if(pos!=velts.begin()) s<<" ";
2210  float nb=pos->second;
2211  if(abs(round(nb)-nb)<0.005)
2212  {
2213  if(int(round(nb))==1) s<<pos->first;
2214  else s<<pos->first<<int(round(nb));
2215  }
2216  else s<<pos->first<<nb;
2217  }
2218  return s.str();
2219 }
2220 
2221 void Molecule::Print()const
2222 {
2223  VFN_DEBUG_MESSAGE("Molecule::Print()",5)
2224  this->XMLOutput(cout);
2225 }
2226 
2227 void Molecule::XMLOutput(ostream &os,int indent)const
2228 {
2229  VFN_DEBUG_ENTRY("Molecule::XMLOutput()",4)
2230 
2231  // :KLUDGE: this may be dangerous if the molecule is beaing refined !
2232  this->ResetRigidGroupsPar();
2233 
2234  for(int i=0;i<indent;i++) os << " " ;
2235  XMLCrystTag tag("Molecule");
2236  tag.AddAttribute("Name",mName);
2237  stringstream sst;
2238  sst<<mMDMoveFreq;
2239  tag.AddAttribute("MDMoveFreq",sst.str());
2240  sst.str("");
2241  sst<<mMDMoveEnergy;
2242  tag.AddAttribute("MDMoveEnergy",sst.str());
2243  sst.str("");
2244  sst<<mLogLikelihoodScale;
2245  tag.AddAttribute("LogLikelihoodScale",sst.str());
2246  os <<tag<<endl;
2247  indent++;
2248 
2249  mQuat.Normalize();
2250  mQuat.XMLOutput(os,indent);
2251 
2252  this->GetPar(mXYZ.data()+0).XMLOutput(os,"x",indent);
2253  os <<endl;
2254 
2255  this->GetPar(mXYZ.data()+1).XMLOutput(os,"y",indent);
2256  os <<endl;
2257 
2258  this->GetPar(mXYZ.data()+2).XMLOutput(os,"z",indent);
2259  os <<endl;
2260 
2261  this->GetPar(&mOccupancy).XMLOutput(os,"Occup",indent);
2262  os <<endl<<endl;
2263 
2264  for(unsigned int i=0;i<this->GetNbOption();i++)
2265  {
2266  this->GetOption(i).XMLOutput(os,indent);
2267  os <<endl;
2268  }
2269  os <<endl;
2270 
2271  {
2272  vector<MolAtom*>::const_iterator pos;
2273  for(pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
2274  (*pos)->XMLOutput(os,indent);
2275  }
2276  {
2277  vector<MolBond*>::const_iterator pos;
2278  for(pos=mvpBond.begin();pos!=mvpBond.end();++pos)
2279  (*pos)->XMLOutput(os,indent);
2280  }
2281  {
2282  vector<MolBondAngle*>::const_iterator pos;
2283  for(pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
2284  (*pos)->XMLOutput(os,indent);
2285  }
2286  {
2287  vector<MolDihedralAngle*>::const_iterator pos;
2288  for(pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos)
2289  (*pos)->XMLOutput(os,indent);
2290  }
2291  {
2292  vector<RigidGroup*>::const_iterator pos;
2293  for(pos=mvRigidGroup.begin();pos!=mvRigidGroup.end();++pos)
2294  {
2295  XMLCrystTag tagg("RigidGroup",false,true);
2296  // Need to use Atom1, Atom2 etc.. so a valid XML is produced
2297  // See https://github.com/vincefn/objcryst/issues/52
2298  // This won't be backwards-compatible
2299  int idx = 0;
2300  for (set<MolAtom*>::const_iterator at = (*pos)->begin(); at != (*pos)->end(); ++at)
2301  tagg.AddAttribute((boost::format("Atom%d") %idx++).str(), (*at)->GetName());
2302  /*
2303  tagg.AddAttribute("Q0",(*pos)->mQuat.Q0());
2304  tagg.AddAttribute("Q1",(*pos)->mQuat.Q1());
2305  tagg.AddAttribute("Q2",(*pos)->mQuat.Q2());
2306  tagg.AddAttribute("Q3",(*pos)->mQuat.Q3());
2307  tagg.AddAttribute("dX",(*pos)->mX);
2308  tagg.AddAttribute("dY",(*pos)->mY);
2309  tagg.AddAttribute("dZ",(*pos)->mZ);
2310  */
2311  for(int i=0;i<indent;i++) os << " " ;
2312  os <<tagg<<endl;
2313  }
2314  }
2315  if(this->GetCenterAtom()!=0)
2316  {
2317 
2318  XMLCrystTag tagg("CenterAtom",false,true);
2319  tagg.AddAttribute("Name",this->GetCenterAtom()->GetName());
2320  for(int i=0;i<indent;i++) os << " " ;
2321  os <<tagg<<endl;
2322  }
2323 
2324  indent--;
2325  tag.SetIsEndTag(true);
2326  for(int i=0;i<indent;i++) os << " " ;
2327  os <<tag<<endl;
2328  VFN_DEBUG_EXIT("Molecule::XMLOutput()",4)
2329 }
2330 
2331 void Molecule::XMLInput(istream &is,const XMLCrystTag &tag)
2332 {
2333  VFN_DEBUG_ENTRY("Molecule::XMLInput()",5)
2334  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
2335  {
2336  if("Name"==tag.GetAttributeName(i))
2337  {
2338  mName=tag.GetAttributeValue(i);
2339  }
2340  if("MDMoveFreq"==tag.GetAttributeName(i))
2341  {
2342  mMDMoveFreq=string2floatC(tag.GetAttributeValue(i));
2343  }
2344  if("MDMoveEnergy"==tag.GetAttributeName(i))
2345  {
2346  mMDMoveEnergy=string2floatC(tag.GetAttributeValue(i));
2347  }
2348  if("LogLikelihoodScale"==tag.GetAttributeName(i))
2349  {
2350  mLogLikelihoodScale=string2floatC(tag.GetAttributeValue(i));
2351  }
2352  }
2353  while(true)
2354  {
2355  XMLCrystTag tagg(is);
2356  if(("Molecule"==tagg.GetName())&&tagg.IsEndTag())
2357  {
2358  //this->XMLOutput(cout);
2359  this->UpdateDisplay();
2360  VFN_DEBUG_EXIT("Molecule::XMLInput():"<<this->GetName(),5)
2361  return;
2362  }
2363  if("Quaternion"==tagg.GetName())
2364  {
2365  mQuat.XMLInput(is,tagg);
2366  }
2367  if("Atom"==tagg.GetName())
2368  {
2369  this->AddAtom(0.,0.,0.,(ScatteringPower *)0,"",false);
2370  mvpAtom.back()->XMLInput(is,tagg);
2371  }
2372  if("Bond"==tagg.GetName())
2373  {
2374  this->AddBond(this->GetAtom(0),this->GetAtom(1),1.5,.01,.05,1.,false);
2375  mvpBond.back()->XMLInput(is,tagg);
2376  }
2377  if("BondAngle"==tagg.GetName())
2378  {
2379  this->AddBondAngle(this->GetAtom(0),this->GetAtom(1),this->GetAtom(2),1.5,.01,.05,false);
2380  mvpBondAngle.back()->XMLInput(is,tagg);
2381  }
2382  if("DihedralAngle"==tagg.GetName())
2383  {
2384  this->AddDihedralAngle(this->GetAtom(0),this->GetAtom(1),
2385  this->GetAtom(2),this->GetAtom(3),1.5,.01,.05,false);
2386  mvpDihedralAngle.back()->XMLInput(is,tagg);
2387  }
2388  if("RigidGroup"==tagg.GetName())
2389  {
2390  RigidGroup s;
2391  for(unsigned int i=0;i<tagg.GetNbAttribute();i++)
2392  if(tagg.GetAttributeName(i).rfind("Atom", 0)==0)
2393  s.insert(&(this->GetAtom(tagg.GetAttributeValue(i))));
2394  this->AddRigidGroup(s);
2395  }
2396  if("CenterAtom"==tagg.GetName())
2397  {
2398  RigidGroup s;
2399  for(unsigned int i=0;i<tagg.GetNbAttribute();i++)
2400  if("Name"==tagg.GetAttributeName(i))
2401  this->SetCenterAtom(this->GetAtom(tagg.GetAttributeValue(i)));
2402  }
2403  if("Option"==tagg.GetName())
2404  {
2405  for(unsigned int i=0;i<tagg.GetNbAttribute();i++)
2406  if("Name"==tagg.GetAttributeName(i))
2407  mOptionRegistry.GetObj(tagg.GetAttributeValue(i)).XMLInput(is,tagg);
2408  continue;
2409  }
2410  if("Par"==tagg.GetName())
2411  {
2412  for(unsigned int i=0;i<tagg.GetNbAttribute();i++)
2413  {
2414  if("Name"==tagg.GetAttributeName(i))
2415  {
2416  if("x"==tagg.GetAttributeValue(i))
2417  {
2418  this->GetPar(mXYZ.data()+0).XMLInput(is,tagg);
2419  break;
2420  }
2421  if("y"==tagg.GetAttributeValue(i))
2422  {
2423  this->GetPar(mXYZ.data()+1).XMLInput(is,tagg);
2424  break;
2425  }
2426  if("z"==tagg.GetAttributeValue(i))
2427  {
2428  this->GetPar(mXYZ.data()+2).XMLInput(is,tagg);
2429  break;
2430  }
2431  if("Occup"==tagg.GetAttributeValue(i))
2432  {
2433  this->GetPar(&mOccupancy).XMLInput(is,tagg);
2434  break;
2435  }
2436  }
2437  }
2438  }
2439  }
2440  VFN_DEBUG_EXIT("Molecule::XMLInput()",5)
2441 }
2442 
2444 {
2445  this->ResetRigidGroupsPar();
2447 }
2448 
2449 void Molecule::BeginOptimization(const bool allowApproximations,const bool enableRestraints)
2450 {
2451  if(this->IsBeingRefined())
2452  {
2453  // RefinableObj::BeginOptimization() will increase the optimization depth
2454  this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints);
2455  return;
2456  }
2457  TAU_PROFILE("Molecule::BeginOptimization()","void (bool,bool)",TAU_DEFAULT);
2458  #if 1 // Is doing this automatically too dangerous ?
2459  if( (!mIsSelfOptimizing)
2460  &&(mAutoOptimizeConformation.GetChoice()==0))
2461  {
2462  if(this->GetLogLikelihood()>(mvpRestraint.size()*500))
2463  {
2464  (*fpObjCrystInformUser)("Optimizing initial conformation of Molecule:"+this->GetName());
2465  this->OptimizeConformation(100000,(REAL)(mvpRestraint.size()));
2466  (*fpObjCrystInformUser)("Finished optimizing initial conformation of Molecule:"+this->GetName());
2467  }
2468  mAutoOptimizeConformation.SetChoice(1);
2469  }
2470  #endif
2471 
2472  RefinableObjClock clockConf, clockMode;
2473  clockConf=mClockAtomList;
2474  if(clockConf<mClockBondList) clockConf=mClockBondList;
2475  if(clockConf<mClockBondAngleList) clockConf=mClockBondAngleList;
2476  if(clockConf<mClockDihedralAngleList) clockConf=mClockDihedralAngleList;
2477  if(clockConf<mClockRigidGroup) clockConf=mClockRigidGroup;
2478  if(clockConf<mClockAtomScattPow) clockConf=mClockAtomScattPow;
2479 
2480  clockMode=mClockConnectivityTable;
2481  if(clockMode<mClockRingList) clockMode=mClockRingList;
2482  if(clockMode<mClockRotorGroup) clockMode=mClockRotorGroup;
2483  if(clockMode<mClockFlipGroup) clockMode=mClockFlipGroup;
2484  if(clockMode<mClockStretchModeBondLength) clockMode=mClockStretchModeBondLength;
2485  if(clockMode<mClockStretchModeBondAngle) clockMode=mClockStretchModeBondAngle;
2486  if(clockMode<mClockStretchModeTorsion) clockMode=mClockStretchModeTorsion;
2487  if(clockMode<mClockStretchModeTwist) clockMode=mClockStretchModeTwist;
2488  if(clockMode<mClockMDAtomGroup) clockMode=mClockMDAtomGroup;
2489 
2490 
2491  if( (!mIsSelfOptimizing) && (clockMode<clockConf))
2492  {
2493  #if 0
2494  this->BuildRotorGroup();
2495  #endif
2496  if(mFlexModel.GetChoice()!=1)
2497  {
2498  this->BuildFlipGroup();
2499  this->BuildRingList();
2501  this->BuildStretchModeBondAngle();
2502  this->BuildStretchModeTorsion();
2503  //this->BuildStretchModeTwist();
2505  this->BuildStretchModeGroups();
2506  this->BuildMDAtomGroups();
2507  }
2508  }
2509  if(mOptimizeOrientation.GetChoice()==1)
2510  {
2511  this->GetPar(&(mQuat.Q0())).SetIsFixed(true);
2512  this->GetPar(&(mQuat.Q1())).SetIsFixed(true);
2513  this->GetPar(&(mQuat.Q2())).SetIsFixed(true);
2514  this->GetPar(&(mQuat.Q3())).SetIsFixed(true);
2515  }
2516  else
2517  {
2518  this->GetPar(&(mQuat.Q0())).SetIsFixed(false);
2519  this->GetPar(&(mQuat.Q1())).SetIsFixed(false);
2520  this->GetPar(&(mQuat.Q2())).SetIsFixed(false);
2521  this->GetPar(&(mQuat.Q3())).SetIsFixed(false);
2522  }
2523  if(1==mFlexModel.GetChoice())
2524  {// Molecule is a rigid body - fix all individual atomic parameters
2525  for(vector<MolAtom*>::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at)
2526  {
2527  this->GetPar(&((*at)->X())).SetIsFixed(true);
2528  this->GetPar(&((*at)->Y())).SetIsFixed(true);
2529  this->GetPar(&((*at)->Z())).SetIsFixed(true);
2530  }
2531  }
2532  else
2533  {// Molecule is flexible - rigid groups are handled below
2534  for(vector<MolAtom*>::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at)
2535  {
2536  this->GetPar(&((*at)->X())).SetIsFixed(false);
2537  this->GetPar(&((*at)->Y())).SetIsFixed(false);
2538  this->GetPar(&((*at)->Z())).SetIsFixed(false);
2539  }
2540  }
2541  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
2542  // Block individual refinable parameters from atoms in rigid groups
2543  // And create the index of the atoms
2544  for(vector<RigidGroup *>::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
2545  {
2546  // Init the translation & rotation parameters (ignored outside an optimization)
2547  (*pos)->mX=0;
2548  (*pos)->mY=0;
2549  (*pos)->mZ=0;
2550  (*pos)->mQuat.Q0()=1;
2551  (*pos)->mQuat.Q1()=0;
2552  (*pos)->mQuat.Q2()=0;
2553  (*pos)->mQuat.Q3()=0;
2554  (*pos)->mvIdx.clear();
2555  for(set<MolAtom *>::iterator at=(*pos)->begin();at!=(*pos)->end();++at)
2556  {
2557  this->GetPar(&((*at)->X())).SetIsFixed(true);
2558  this->GetPar(&((*at)->Y())).SetIsFixed(true);
2559  this->GetPar(&((*at)->Z())).SetIsFixed(true);
2560  for(int i = 0; i < this->GetNbComponent(); ++i)
2561  if(&(this->GetAtom(i))==*at)
2562  {
2563  (*pos)->mvIdx.insert(i);
2564  break;
2565  }
2566  }
2567  }
2568  #endif
2569 
2570  this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints);
2571  mRandomConformChangeNbTest=0;
2572  mRandomConformChangeNbAccept=0;
2573  mRandomConformChangeTemp=1.;//(REAL)this->GetNbComponent();
2574 }
2575 
2577 {
2578  /*
2579  if(mOptimizationDepth>1)
2580  {
2581  this->RefinableObj::EndOptimization();
2582  return;
2583  }
2584  */
2585  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
2586  // Un-block individual refinable parameters from atoms in rigid groups
2587  for(vector<RigidGroup *>::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
2588  {
2589  for(set<MolAtom *>::iterator at=(*pos)->begin();at!=(*pos)->end();++at)
2590  {
2591  this->GetPar(&((*at)->X())).SetIsFixed(false);
2592  this->GetPar(&((*at)->Y())).SetIsFixed(false);
2593  this->GetPar(&((*at)->Z())).SetIsFixed(false);
2594  }
2595  }
2596  // Apply the translations & rotations of the rigid group parameters, and
2597  // use this as the newly stored atomic coordinates.
2598  this->ResetRigidGroupsPar();
2599  #endif
2601 }
2602 
2604 {
2605  TAU_PROFILE("Molecule::RandomizeConfiguration()","void ()",TAU_DEFAULT);
2606  VFN_DEBUG_ENTRY("Molecule::RandomizeConfiguration()",4)
2607 
2608  if( (!mIsSelfOptimizing)
2609  &&(this->GetLogLikelihood()>(mvpRestraint.size()*500))
2610  &&(mAutoOptimizeConformation.GetChoice()==0))
2611  {// This is only done once, for a newly-created molecule with atoms not conforming to restraints
2612  (*fpObjCrystInformUser)("Optimizing initial conformation of Molecule:"+this->GetName());
2613  this->OptimizeConformation(100000,(REAL)(mvpRestraint.size()));
2614  (*fpObjCrystInformUser)("Finished optimizing initial conformation of Molecule:"+this->GetName());
2615  mAutoOptimizeConformation.SetChoice(1);
2616  }
2617 
2618  if( (!(this->IsBeingRefined()))
2619  &&( (mClockStretchModeTorsion<mClockRestraint)
2620 // ||(mClockStretchModeTwist<mClockAtomList)
2621 // ||(mClockStretchModeBondAngle<mClockScatterer)
2622 // ||(mClockStretchModeBondLength<mClockScatterer)
2623  ||(mClockMDAtomGroup<mClockRestraint)))
2624  {
2625  //This will build stretch modes & MD groups
2626  if(mFlexModel.GetChoice()!=1)
2627  {
2628  this->BuildStretchModeTorsion();
2629  //this->BuildStretchModeGroups();
2630  this->BuildMDAtomGroups();
2631  // WARNING: TuneGlobalOptimRotationAmplitude() will call RandomizeConfiguration(),
2632  // so make sure we do not enter this code again by calling first BuildStretchModeTorsion and BuildMDAtomGroups
2634  }
2635  }
2636 
2637  #if 0
2638  this->BuildRotorGroup();
2639  if((mFlexModel.GetChoice()==0)||(mFlexModel.GetChoice()==2))
2640  for(list<RotorGroup>::const_iterator pos=mvRotorGroupTorsion.begin();
2641  pos!=mvRotorGroupTorsion.end();++pos)
2642  {
2643  const REAL angle=(REAL)rand()*2.*M_PI/(REAL)RAND_MAX;
2644  this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),
2645  pos->mvRotatedAtomList,angle);
2646  }
2647  if(mFlexModel.GetChoice()==0)
2648  for(list<RotorGroup>::const_iterator pos=mvRotorGroupTorsionSingleChain.begin();
2649  pos!=mvRotorGroupTorsionSingleChain.end();++pos)
2650  {
2651  const REAL angle=(REAL)rand()*2.*M_PI/(REAL)RAND_MAX;
2652  this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),
2653  pos->mvRotatedAtomList,angle);
2654  }
2655  if(mFlexModel.GetChoice()==0)
2656  for(list<RotorGroup>::const_iterator pos=mvRotorGroupInternal.begin();
2657  pos!=mvRotorGroupInternal.end();++pos)
2658  {
2659  const REAL angle=(REAL)rand()*2.*M_PI/(REAL)RAND_MAX;
2660  this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),
2661  pos->mvRotatedAtomList,angle);
2662  }
2663  #else
2664  for(list<StretchModeTorsion>::const_iterator
2665  pos=mvStretchModeTorsion.begin();
2666  pos!=mvStretchModeTorsion.end();++pos)
2667  {
2668  const REAL amp=2*M_PI*rand()/(REAL)RAND_MAX;
2669  this->DihedralAngleRandomChange(*pos,amp,true);
2670  }
2671  // Molecular dynamics moves
2672  if((mvMDAtomGroup.size()>0)&&(mMDMoveFreq>0)&&(mMDMoveEnergy>0))
2673  {
2674  // Random initial speed for all atoms
2675  map<MolAtom*,XYZ> v0;
2676  for(vector<MolAtom*>::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at)
2677  v0[*at]=XYZ(rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5);
2678 
2679  const REAL nrj0=mMDMoveEnergy*( this->GetBondList().size()
2680  +this->GetBondAngleList().size()
2681  +this->GetDihedralAngleList().size());
2682  map<RigidGroup*,std::pair<XYZ,XYZ> > vr;
2683  this->MolecularDynamicsEvolve(v0, 5000,0.004,
2684  this->GetBondList(),
2685  this->GetBondAngleList(),
2686  this->GetDihedralAngleList(),
2687  vr,nrj0);
2688  }
2689 
2690  #endif
2691  // this will only change limited parameters i.e. translation
2693  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
2694  // Init rigid groups translation & rotation parameters to zero
2695  for(vector<RigidGroup *>::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
2696  {
2697  // Init the translation & rotation parameters (ignored outside an optimization
2698  (*pos)->mX=0;
2699  (*pos)->mY=0;
2700  (*pos)->mZ=0;
2701  (*pos)->mQuat.Q0()=1;
2702  (*pos)->mQuat.Q1()=0;
2703  (*pos)->mQuat.Q2()=0;
2704  (*pos)->mQuat.Q3()=0;
2705  }
2706  #endif
2707  if(mOptimizeOrientation.GetChoice()==0)
2708  {//Rotate around an arbitrary vector
2709  const REAL amp=M_PI/RAND_MAX;
2711  ((2.*(REAL)rand()-(REAL)RAND_MAX)*amp,
2712  (REAL)rand(),(REAL)rand(),(REAL)rand());
2713  mQuat.Normalize();
2714  mClockOrientation.Click();
2715  }
2716  VFN_DEBUG_EXIT("Molecule::RandomizeConfiguration()",4)
2717 }
2718 
2719 void Molecule::GlobalOptRandomMove(const REAL mutationAmplitude,
2720  const RefParType *type)
2721 {
2722  if(mRandomMoveIsDone) return;
2723  if(mIsSelfOptimizing)
2724  {
2725  this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,type);
2726  mQuat.Normalize();
2727  VFN_DEBUG_EXIT("Molecule::GlobalOptRandomMove()",4)
2728  return;
2729  }
2730  TAU_PROFILE("Molecule::GlobalOptRandomMove()","void (REAL,RefParType*)",TAU_DEFAULT);
2731  TAU_PROFILE_TIMER(timer1,"Molecule::GlobalOptRandomMove 1","", TAU_FIELD);
2732  TAU_PROFILE_TIMER(timer2,"Molecule::GlobalOptRandomMove 2","", TAU_FIELD);
2733  TAU_PROFILE_TIMER(timer3,"Molecule::GlobalOptRandomMove 3","", TAU_FIELD);
2734  TAU_PROFILE_TIMER(timer4,"Molecule::GlobalOptRandomMove 4","", TAU_FIELD);
2735  TAU_PROFILE_TIMER(timer5,"Molecule::GlobalOptRandomMove 5","", TAU_FIELD);
2736  VFN_DEBUG_ENTRY("Molecule::GlobalOptRandomMove()",4)
2738 
2739 
2740  #if 1
2741  // From time to time, just do one flip
2742  if( (mFlexModel.GetChoice()!=1)
2743  &&(mFlipModel.GetChoice()==0)
2744  &&(gpRefParTypeScattConform->IsDescendantFromOrSameAs(type))
2745  &&(mvFlipGroup.size()>0)
2746  &&(((rand()%100)==0)))
2747  {
2748 
2749  this->SaveParamSet(mLocalParamSet);
2750  const REAL llk0=this->GetLogLikelihood()/mLogLikelihoodScale;
2751  const unsigned long i=rand() % mvFlipGroup.size();
2752  list<FlipGroup>::iterator pos=mvFlipGroup.begin();
2753  for(unsigned long j=0;j<i;++j)++pos;
2754  this->FlipAtomGroup(*pos,true);
2755  #if 0
2756  static unsigned long ctflip1=0,ctflip2=0;
2757  if(pos->mvRotatedChainList.begin()->first==pos->mpAtom0)
2758  {
2759  cout <<"TRYING: Flip group from atom "
2760  <<pos->mpAtom0->GetName()<<",exchanging bonds with "
2761  <<pos->mpAtom1->GetName()<<" and "
2762  <<pos->mpAtom2->GetName()<<", resulting in a 180deg rotation of atoms : ";
2763  for(set<MolAtom*>::iterator pos1=pos->mvRotatedChainList.begin()->second.begin();
2764  pos1!=pos->mvRotatedChainList.begin()->second.end();++pos1)
2765  cout<<(*pos1)->GetName()<<" ";
2766  }
2767  else
2768  {
2769  cout <<"TRYING: Flip group with respect to: "
2770  <<pos->mpAtom1->GetName()<<"-"
2771  <<pos->mpAtom0->GetName()<<"-"
2772  <<pos->mpAtom2->GetName()<<" : ";
2773  for(list<pair<const MolAtom *,set<MolAtom*> > >::const_iterator
2774  chain=pos->mvRotatedChainList.begin();
2775  chain!=pos->mvRotatedChainList.end();++chain)
2776  {
2777  cout<<" -"<<chain->first->GetName()<<":";
2778  for(set<MolAtom*>::const_iterator pos1=chain->second.begin();
2779  pos1!=chain->second.end();++pos1)
2780  cout<<(*pos1)->GetName()<<" ";
2781  }
2782  }
2783  ctflip1++;
2784  if((this->GetLogLikelihood()/mLogLikelihoodScale-llk0)>.3*llk0)
2785  {
2786  cout<<" FLIP REJECTED ("<<int(float(ctflip2)/ctflip1*100)<<"% accepted): llk="<<llk0<<" -> "<<this->GetLogLikelihood()/mLogLikelihoodScale<<endl;
2787  this->RestoreParamSet(mLocalParamSet);
2788  }
2789  else
2790  {
2791  ctflip2++;
2792  cout<<" FLIP ACCEPTED ("<<float(ctflip2)/ctflip1*100<<"% accepted)"<<endl;
2793  }
2794  #else
2795  if((this->GetLogLikelihood()/mLogLikelihoodScale-llk0)>.3*llk0)
2796  this->RestoreParamSet(mLocalParamSet);
2797  #endif
2798  }
2799  else
2800  #endif
2801  {
2802  TAU_PROFILE_START(timer1);
2803  if(mOptimizeOrientation.GetChoice()==0)
2804  {//Rotate around an arbitrary vector
2805  static const REAL amp=mBaseRotationAmplitude/(REAL)RAND_MAX;
2806  REAL mult=1.0;
2807  if((1==mFlexModel.GetChoice())||(mvRotorGroupTorsion.size()<2)) mult=2.0;
2809  ((2.*(REAL)rand()-(REAL)RAND_MAX)*amp*mutationAmplitude*mult,
2810  (REAL)rand(),(REAL)rand(),(REAL)rand());
2811  mQuat.Normalize();
2812  mClockOrientation.Click();
2813  }
2814  // Occupancy
2815  if(gpRefParTypeScattOccup->IsDescendantFromOrSameAs(type))
2816  this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,gpRefParTypeScattOccup);
2817  mRandomMoveIsDone=false;
2818  //translation
2819  if(gpRefParTypeScattTransl->IsDescendantFromOrSameAs(type))
2820  this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,gpRefParTypeScattTransl);
2821  mRandomMoveIsDone=false;
2822  TAU_PROFILE_STOP(timer1);
2823  if(gpRefParTypeScattConform->IsDescendantFromOrSameAs(type))
2824  {
2825  if(mFlexModel.GetChoice()!=1)
2826  {
2827  #if 1 // Move as many atoms as possible
2828  if((mvMDFullAtomGroup.size()>3)&&(rand()<(RAND_MAX*mMDMoveFreq)))
2829  {
2830  #if 0
2831  // Use one center for the position of an impulsion, applied to all atoms with an exponential decrease
2832  // Determine extent of atom group
2833  REAL xmin=(*mvMDFullAtomGroup.begin())->GetX();
2834  REAL xmax=(*mvMDFullAtomGroup.begin())->GetX();
2835  REAL ymin=(*mvMDFullAtomGroup.begin())->GetY();
2836  REAL ymax=(*mvMDFullAtomGroup.begin())->GetY();
2837  REAL zmin=(*mvMDFullAtomGroup.begin())->GetZ();
2838  REAL zmax=(*mvMDFullAtomGroup.begin())->GetZ();
2839  for(set<MolAtom*>::iterator at=mvMDFullAtomGroup.begin();at!=mvMDFullAtomGroup.end();++at)
2840  {
2841  if((*at)->GetX()<xmin) xmin=(*at)->GetX();
2842  if((*at)->GetX()>xmax) xmax=(*at)->GetX();
2843  if((*at)->GetY()<ymin) ymin=(*at)->GetY();
2844  if((*at)->GetY()>ymax) ymax=(*at)->GetY();
2845  if((*at)->GetZ()<zmin) zmin=(*at)->GetZ();
2846  if((*at)->GetZ()>zmax) zmax=(*at)->GetZ();
2847  }
2848  // Apply a gaussian impulsion to part of the atom group (FWHM=1/3 of group size)
2849  REAL dx=(xmax-xmin)/5.,dy=(ymax-ymin)/5.,dz=(zmax-zmin)/5.;
2850  if(dx<2) dx=2;
2851  if(dy<2) dy=2;
2852  if(dz<2) dz=2;
2853  const REAL xc=xmin+rand()/(REAL)RAND_MAX*(xmax-xmin);
2854  const REAL yc=ymin+rand()/(REAL)RAND_MAX*(ymax-ymin);
2855  const REAL zc=zmin+rand()/(REAL)RAND_MAX*(zmax-zmin);
2856  map<MolAtom*,XYZ> v0;
2857  const REAL ax=-4.*log(2.)/(dx*dx);
2858  const REAL ay=-4.*log(2.)/(dy*dy);
2859  const REAL az=-4.*log(2.)/(dz*dz);
2860  for(set<MolAtom*>::iterator at=mvMDFullAtomGroup.begin();at!=mvMDFullAtomGroup.end();++at)
2861  v0[*at]=XYZ(exp(ax*((*at)->GetX()-xc)*((*at)->GetX()-xc)),
2862  exp(ay*((*at)->GetY()-yc)*((*at)->GetY()-yc)),
2863  exp(az*((*at)->GetZ()-zc)*((*at)->GetZ()-zc)));
2864  #else
2865  // Use one atom for the center of the impulsion, 'push' atoms depending on distance & connectivity table
2866  map<MolAtom*,XYZ> v0;
2867  for(set<MolAtom*>::iterator at=this->mvMDFullAtomGroup.begin();at!=this->mvMDFullAtomGroup.end();++at)
2868  v0[*at]=XYZ(0,0,0);
2869  std::map<MolAtom*,unsigned long> pushedAtoms;
2870  unsigned long idx=rand()%v0.size();
2871  set<MolAtom*>::iterator at0=this->mvMDFullAtomGroup.begin();
2872  for(unsigned int i=0;i<idx;i++) at0++;
2873  const REAL xc=(*at0)->GetX();
2874  const REAL yc=(*at0)->GetY();
2875  const REAL zc=(*at0)->GetZ();
2876  const map<MolAtom *,set<MolAtom *> > *pConnect=&(this-> GetConnectivityTable());
2877  ExpandAtomGroupRecursive(*at0,*pConnect,pushedAtoms,3);
2878  REAL ux,uy,uz,n=0;
2879  while(n<1)
2880  {
2881  ux=REAL(rand()-RAND_MAX/2);
2882  uy=REAL(rand()-RAND_MAX/2);
2883  uz=REAL(rand()-RAND_MAX/2);
2884  n=sqrt(ux*ux+uy*uy+uz*uz);
2885  }
2886  ux=ux/n;uy=uy/n;uz=uz/n;
2887  const REAL a=-4.*log(2.)/(2*2);//FWHM=2 Angstroems
2888  if(rand()%2==0)
2889  for(map<MolAtom*,unsigned long>::iterator at=pushedAtoms.begin() ;at!=pushedAtoms.end();++at)
2890  v0[at->first]=XYZ(ux*exp(a*(at->first->GetX()-xc)*(at->first->GetX()-xc)),
2891  uy*exp(a*(at->first->GetY()-yc)*(at->first->GetY()-yc)),
2892  uz*exp(a*(at->first->GetZ()-zc)*(at->first->GetZ()-zc)));
2893  else
2894  for(map<MolAtom*, unsigned long>::iterator at=pushedAtoms.begin() ;at!=pushedAtoms.end();++at)
2895  v0[at->first]=XYZ((at->first->GetX()-xc)*ux*exp(a*(at->first->GetX()-xc)*(at->first->GetX()-xc)),
2896  (at->first->GetY()-yc)*uy*exp(a*(at->first->GetY()-yc)*(at->first->GetY()-yc)),
2897  (at->first->GetZ()-zc)*uz*exp(a*(at->first->GetZ()-zc)*(at->first->GetZ()-zc)));
2898 
2899 
2900  #endif
2901  const REAL nrj0=mMDMoveEnergy*( this->GetBondList().size()
2902  +this->GetBondAngleList().size()
2903  +this->GetDihedralAngleList().size());
2904  map<RigidGroup*,std::pair<XYZ,XYZ> > vr;
2905  this->MolecularDynamicsEvolve(v0, int(100*sqrt(mutationAmplitude)),0.004,
2906  this->GetBondList(),
2907  this->GetBondAngleList(),
2908  this->GetDihedralAngleList(),
2909  vr,nrj0);
2910  }
2911  #else // Move atoms belonging to a MD group
2912  if((mvMDAtomGroup.size()>0)&&(rand()<(RAND_MAX*mMDMoveFreq)))
2913  {
2914  const unsigned int n=rand()%mvMDAtomGroup.size();
2915  list<MDAtomGroup>::iterator pos=mvMDAtomGroup.begin();
2916  for(unsigned int i=0;i<n;++i)++pos;
2917  map<MolAtom*,XYZ> v0;
2918  for(set<MolAtom*>::iterator at=pos->mvpAtom.begin();at!=pos->mvpAtom.end();++at)
2919  v0[*at]=XYZ(rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5);
2920 
2921  const REAL nrj0=mMDMoveEnergy*( pos->mvpBond.size()
2922  +pos->mvpBondAngle.size()
2923  +pos->mvpDihedralAngle.size());
2924  map<RigidGroup*,std::pair<XYZ,XYZ> > vr;
2925  float nrjMult=1.0+mutationAmplitude*0.2;
2926  if((rand()%20)==0) nrjMult=4.0;
2927  this->MolecularDynamicsEvolve(v0, int(100*sqrt(mutationAmplitude)),0.004,
2928  pos->mvpBond,
2929  pos->mvpBondAngle,
2930  pos->mvpDihedralAngle,
2931  vr,nrj0*nrjMult);
2932  }
2933  #endif
2934  else
2935  {
2936  #if 0 // For tests
2937  mLogLikelihood=0;
2938  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
2939  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
2940  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
2941  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
2942  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos)
2943  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
2944  for(list<StretchMode*>::const_iterator mode=mvpStretchModeNotFree.begin();
2945  mode!=mvpStretchModeNotFree.end();++mode)
2946  {
2947  //if((rand()%3)==0)
2948  {
2949  // 2) Get the derivative of the overall LLK for this mode
2950  (*mode)->CalcDeriv();
2951  REAL llk=0;
2952  for(map<const MolBond*,REAL>::const_iterator pos=(*mode)->mvpBrokenBond.begin();
2953  pos!=(*mode)->mvpBrokenBond.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
2954  for(map<const MolBondAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenBondAngle.begin();
2955  pos!=(*mode)->mvpBrokenBondAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
2956  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenDihedralAngle.begin();
2957  pos!=(*mode)->mvpBrokenDihedralAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
2958  // 3) Calculate MD move. base step =0.1 A (accelerated moves may go faster)
2959  REAL change=(2.*(REAL)rand()-(REAL)RAND_MAX)/(REAL)RAND_MAX;
2960  // if llk>100, change has to be in the opposite direction
2961  // For a single restraint, sqrt(llk)=dx/sigma, so do not go above 10*sigma
2962  if((*mode)->mLLKDeriv>0)
2963  {
2964  change -= 0.3*sqrt(llk);
2965  if(change<-1) change=-1;
2966  }
2967  else
2968  {
2969  change += 0.3*sqrt(llk);
2970  if(change>1) change=1;
2971  }
2972  (*mode)->Print(cout);
2973  change *= mutationAmplitude * (*mode)->mBaseAmplitude;
2974  cout <<" Change="<<change<<" (dLLK= "<<(*mode)->mLLKDeriv<<"), llk= "<<llk<<" ?->"<<llk+(*mode)->mLLKDeriv*change<<endl;
2975  //change *= mutationAmplitude * (*mode)->mBaseAmplitude;
2976  (*mode)->Stretch(change);
2977  llk=0;
2978  //(*mode)->RandomStretch(change * mutationAmplitude * (*mode)->mBaseAmplitude);
2979  for(map<const MolBond*,REAL>::const_iterator pos=(*mode)->mvpBrokenBond.begin();
2980  pos!=(*mode)->mvpBrokenBond.end();++pos)
2981  {
2982  cout<<" "<<pos->first->GetName()<<", llk= "<<pos->first->GetLogLikelihood(false,false)
2983  <<" ?->"<<pos->first->GetLogLikelihood(false,false)+pos->first->GetDeriv((*mode)->mDerivXYZ,true)*change
2984  <<"? (deriv="<<pos->first->GetDeriv((*mode)->mDerivXYZ)<<", "<<pos->first->GetDeriv((*mode)->mDerivXYZ,true);
2985  cout<<") ->" <<pos->first->GetLogLikelihood()<<endl;
2986  llk+=pos->first->GetLogLikelihood(false,false);
2987  }
2988  for(map<const MolBondAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenBondAngle.begin();
2989  pos!=(*mode)->mvpBrokenBondAngle.end();++pos)
2990  {
2991  cout<<" "<<pos->first->GetName()<<", llk= "<<pos->first->GetLogLikelihood(false,false)
2992  <<" ?->"<<pos->first->GetLogLikelihood(false,false)+pos->first->GetDeriv((*mode)->mDerivXYZ,true)*change
2993  <<"? (deriv="<<pos->first->GetDeriv((*mode)->mDerivXYZ)<<", "<<pos->first->GetDeriv((*mode)->mDerivXYZ,true);
2994  cout<<") ->" <<pos->first->GetLogLikelihood()<<endl;
2995  llk+=pos->first->GetLogLikelihood(false,false);
2996  }
2997  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenDihedralAngle.begin();
2998  pos!=(*mode)->mvpBrokenDihedralAngle.end();++pos)
2999  {
3000  cout<<" "<<pos->first->GetName()<<", llk= "<<pos->first->GetLogLikelihood(false,false)
3001  <<" ?->"<<pos->first->GetLogLikelihood(false,false)+pos->first->GetDeriv((*mode)->mDerivXYZ,true)*change
3002  <<"? (deriv="<<pos->first->GetDeriv((*mode)->mDerivXYZ)<<", "<<pos->first->GetDeriv((*mode)->mDerivXYZ,true);
3003  cout<<") ->" <<pos->first->GetLogLikelihood()<<endl;
3004  llk+=pos->first->GetLogLikelihood(false,false);
3005  }
3006  cout <<" -> "<<llk<<endl;
3007  }
3008  }
3009  #else
3010  // First move free Stretch modes
3011  TAU_PROFILE_START(timer2);
3012  for(list<StretchMode*>::iterator mode=mvpStretchModeFree.begin();
3013  mode!=mvpStretchModeFree.end();++mode)
3014  {
3015  if((rand()%2)==0) (*mode)->RandomStretch(mutationAmplitude);
3016  }
3017  TAU_PROFILE_STOP(timer2);
3018  if((rand()%3)==0)
3019  {
3020  // Now do an hybrid move for other modes, with a smaller amplitude (<=0.5)
3021  // 1) Calc LLK and derivatives for restraints
3022  mLogLikelihood=0;
3023  TAU_PROFILE_START(timer3);
3024  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
3025  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
3026  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
3027  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
3028  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos)
3029  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
3030  TAU_PROFILE_STOP(timer3);
3031 
3032  TAU_PROFILE_START(timer4);
3033  for(list<StretchMode*>::const_iterator mode=mvpStretchModeNotFree.begin();
3034  mode!=mvpStretchModeNotFree.end();++mode)
3035  {
3036  // 2) Choose Stretch modes
3037  if((rand()%3)==0)
3038  {
3039  // 2) Get the derivative of the overall LLK for this mode
3040  (*mode)->CalcDeriv();
3041  REAL llk=0;
3042  for(map<const MolBond*,REAL>::const_iterator pos=(*mode)->mvpBrokenBond.begin();
3043  pos!=(*mode)->mvpBrokenBond.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
3044  for(map<const MolBondAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenBondAngle.begin();
3045  pos!=(*mode)->mvpBrokenBondAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
3046  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenDihedralAngle.begin();
3047  pos!=(*mode)->mvpBrokenDihedralAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
3048  REAL change=(2.*(REAL)rand()-(REAL)RAND_MAX)/(REAL)RAND_MAX;
3049  // if llk>100, change has to be in the direction minimising the llk
3050  if((*mode)->mLLKDeriv>0)
3051  {
3052  change -= 0.01*llk;
3053  if(change<-1) change=-1;
3054  }
3055  else
3056  {
3057  change += 0.01*llk;
3058  if(change>1) change=1;
3059  }
3060  if(mutationAmplitude<0.5) change *= mutationAmplitude * (*mode)->mBaseAmplitude;
3061  else change *= 0.5 * (*mode)->mBaseAmplitude;
3062  (*mode)->Stretch(change);
3063  }
3064  }
3065  // Here we do not take mLogLikelihoodScale into account
3066  // :TODO: take into account cases where the lllk cannot go down to 0 because of
3067  // combined restraints.
3068  if( ((rand()%100)==0) && (mLogLikelihood>(mvpRestraint.size()*10)))
3070  TAU_PROFILE_STOP(timer4);
3071  }
3072 
3073  // Perform MD moves if there are MDAtomGroups
3074  #if 0
3075  for(list<MDAtomGroup>::iterator pos=mvMDAtomGroup.begin();pos!=mvMDAtomGroup.end();++pos)
3076  {
3077  if((rand()%100)==0)
3078  {
3079  map<MolAtom*,XYZ> v0;
3080  for(set<MolAtom*>::iterator at=pos->mvpAtom.begin();at!=pos->mvpAtom.end();++at)
3081  v0[*at]=XYZ(rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5);
3082 
3083  const REAL nrj0=20*(pos->mvpBond.size()+pos->mvpBondAngle.size()+pos->mvpDihedralAngle.size());
3084  map<RigidGroup*,std::pair<XYZ,XYZ> > vr;
3085  this->MolecularDynamicsEvolve(v0, int(100*sqrt(mutationAmplitude)),0.002,
3086  (const vector<MolBond*>) (pos->mvpBond),
3087  (const vector<MolBondAngle*>) (pos->mvpBondAngle),
3088  (const vector<MolDihedralAngle*>) (pos->mvpDihedralAngle),
3089  vr,nrj0);
3090  }
3091  }
3092  #endif
3093  }
3094  // Do a steepest descent from time to time
3095  if((rand()%100)==0) this->OptimizeConformationSteepestDescent(0.02,1);
3096 
3097  mClockLogLikelihood.Click();
3098  #endif
3099  }
3100  }
3101  }
3102  if((rand()%100)==0)
3103  {// From time to time, bring back average position to 0
3104  REAL x0=0,y0=0,z0=0;
3105  for(vector<MolAtom*>::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
3106  {
3107  x0 += (*pos)->X();
3108  y0 += (*pos)->Y();
3109  z0 += (*pos)->Z();
3110  }
3111  x0 /= mvpAtom.size();
3112  y0 /= mvpAtom.size();
3113  z0 /= mvpAtom.size();
3114  for(vector<MolAtom*>::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
3115  {
3116  (*pos)->X() -= x0;
3117  (*pos)->Y() -= y0;
3118  (*pos)->Z() -= z0;
3119  }
3120  }
3121  mRandomMoveIsDone=true;
3122  VFN_DEBUG_EXIT("Molecule::GlobalOptRandomMove()",4)
3123 }
3124 
3126 {
3127  if( (mClockLogLikelihood>mClockAtomList)
3128  &&(mClockLogLikelihood>mClockBondList)
3129  &&(mClockLogLikelihood>mClockBondAngleList)
3130  &&(mClockLogLikelihood>mClockDihedralAngleList)
3131  &&(mClockLogLikelihood>mClockAtomPosition)
3132  &&(mClockLogLikelihood>mClockScatterer)) return mLogLikelihood*mLogLikelihoodScale;
3133  TAU_PROFILE("Molecule::GetLogLikelihood()","REAL ()",TAU_DEFAULT);
3135  mClockLogLikelihood.Click();
3137 }
3138 
3139 unsigned int Molecule::GetNbLSQFunction()const
3140 {
3141  return 1;
3142 }
3143 
3144 const CrystVector_REAL& Molecule::GetLSQCalc(const unsigned int) const
3145 {
3146  mLSQCalc.resize(mvpRestraint.size());
3147  REAL *p=mLSQCalc.data();
3148  for(vector<MolBond*>::const_iterator pos=this->GetBondList().begin();pos!=this->GetBondList().end();++pos)
3149  *p++=(*pos)->GetLength();
3150  for(vector<MolBondAngle*>::const_iterator pos=this->GetBondAngleList().begin();pos!=this->GetBondAngleList().end();++pos)
3151  *p++=(*pos)->GetAngle();
3152  for(vector<MolDihedralAngle*>::const_iterator pos=this->GetDihedralAngleList().begin();pos!=this->GetDihedralAngleList().end();++pos)
3153  *p++=(*pos)->GetAngle();
3154  return mLSQCalc;
3155 }
3156 
3157 const CrystVector_REAL& Molecule::GetLSQObs(const unsigned int) const
3158 {
3159  mLSQObs.resize(mvpRestraint.size());
3160  REAL *p=mLSQObs.data();
3161  for(vector<MolBond*>::const_iterator pos=this->GetBondList().begin();pos!=this->GetBondList().end();++pos)
3162  *p++=(*pos)->GetLength0();
3163  for(vector<MolBondAngle*>::const_iterator pos=this->GetBondAngleList().begin();pos!=this->GetBondAngleList().end();++pos)
3164  *p++=(*pos)->GetAngle0();
3165  for(vector<MolDihedralAngle*>::const_iterator pos=this->GetDihedralAngleList().begin();pos!=this->GetDihedralAngleList().end();++pos)
3166  *p++=(*pos)->GetAngle0();
3167  return mLSQObs;
3168 }
3169 
3170 const CrystVector_REAL& Molecule::GetLSQWeight(const unsigned int) const
3171 {
3172  //:TODO: USe a clock to avoid re-computation
3173  mLSQWeight.resize(mvpRestraint.size());
3174  REAL *p=mLSQWeight.data();
3175  for(vector<MolBond*>::const_iterator pos=this->GetBondList().begin();pos!=this->GetBondList().end();++pos)
3176  *p++=1/((*pos)->GetLengthSigma()* (*pos)->GetLengthSigma()+1e-6);
3177  for(vector<MolBondAngle*>::const_iterator pos=this->GetBondAngleList().begin();pos!=this->GetBondAngleList().end();++pos)
3178  *p++=1/((*pos)->GetAngleSigma()* (*pos)->GetAngleSigma()+1e-6);
3179  for(vector<MolDihedralAngle*>::const_iterator pos=this->GetDihedralAngleList().begin();pos!=this->GetDihedralAngleList().end();++pos)
3180  *p++=1/((*pos)->GetAngleSigma()* (*pos)->GetAngleSigma()+1e-6);
3182  return mLSQWeight;
3183 }
3184 
3185 const CrystVector_REAL& Molecule::GetLSQDeriv(const unsigned int n, RefinablePar&par)
3186 {
3187  //:TODO: return analytical derivatives
3188  return RefinableObj::GetLSQDeriv(n,par);
3189 }
3190 
3192 {
3193  this->ResetRigidGroupsPar();
3194  #if 0
3195  cout<<"Molecule::TagNewBestConfig()"<<endl;
3196  {
3197  vector<MolBond*>::const_iterator pos;
3198  for(pos=mvpBond.begin();pos!=mvpBond.end();++pos)
3199  {
3200  cout<<"BondLength="<<(*pos)->GetLength();
3201  (*pos)->XMLOutput(cout);
3202  }
3203  }
3204  {
3205  vector<MolBondAngle*>::const_iterator pos;
3206  for(pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
3207  {
3208  cout<<"BondAngle="<<(*pos)->GetAngle();
3209  (*pos)->XMLOutput(cout);
3210  }
3211  }
3212  {
3213  vector<MolDihedralAngle*>::const_iterator pos;
3214  for(pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos)
3215  {
3216  cout<<"DihedralAngle="<<(*pos)->GetAngle();
3217  (*pos)->XMLOutput(cout);
3218  }
3219  }
3220 
3221  for(list<MDAtomGroup>::iterator pos=mvMDAtomGroup.begin();pos!=mvMDAtomGroup.end();++pos)
3222  {
3223  char buf[100];
3224  for(set<MolAtom*>::iterator at1=pos->mvpAtom.begin();at1!=pos->mvpAtom.end();++at1)
3225  {
3226  sprintf(buf,"%5s : ",(*at1)->GetName().c_str());
3227  cout<<buf;
3228  for(set<MolAtom*>::iterator at2=at1;at2!=pos->mvpAtom.end();++at2)
3229  {
3230  if(at1==at2) continue;
3231  sprintf(buf,"%5s(%6.3f),",(*at2)->GetName().c_str(),GetBondLength(**at1,**at2));
3232  cout<<buf;
3233  }
3234  cout<<endl;
3235  }
3236  }
3237  #endif
3238 }
3239 
3240 int Molecule::GetNbComponent() const { return mvpAtom.size();}
3241 
3243 {
3244  VFN_DEBUG_ENTRY("Molecule::GetScatteringComponentList()",3)
3245  this->UpdateScattCompList();
3246  VFN_DEBUG_EXIT("Molecule::GetScatteringComponentList()",3)
3247  return mScattCompList;
3248 }
3249 
3250 string Molecule::GetComponentName(const int i) const
3251 {
3252  //if(mvpAtom[i]->IsDummy()) return "Dummy";
3253  return mvpAtom[i]->GetName();
3254 }
3255 
3256 ostream& Molecule::POVRayDescription(ostream &os,const CrystalPOVRayOptions &options)const
3257 {
3258  VFN_DEBUG_ENTRY("Molecule::POVRayDescription()",3)
3259  const REAL xMin=options.mXmin; const REAL xMax=options.mXmax;
3260  const REAL yMin=options.mYmin; const REAL yMax=options.mYmax;
3261  const REAL zMin=options.mZmin; const REAL zMax=options.mZmax;
3262  if(mvpAtom.size()==0)
3263  {
3264  VFN_DEBUG_EXIT("Molecule::POVRayDescription():No atom to display !",4)
3265  return os;
3266  }
3267  this->UpdateScattCompList();
3268 
3269  const REAL aa=this->GetCrystal().GetLatticePar(0);
3270  const REAL bb=this->GetCrystal().GetLatticePar(1);
3271  const REAL cc=this->GetCrystal().GetLatticePar(2);
3272 
3273  os << "// Description of Molecule :" << this->GetName() <<endl;
3274  vector<CrystMatrix_REAL> vXYZCoords;
3275  {
3277  REAL x0,y0,z0;
3278  for(long i=0;i<mScattCompList.GetNbComponent();++i)
3279  {
3280  x0=mScattCompList(i).mX;
3281  y0=mScattCompList(i).mY;
3282  z0=mScattCompList(i).mZ;
3283  vXYZCoords.push_back(this->GetCrystal().GetSpaceGroup().
3284  GetAllSymmetrics(x0,y0,z0,false,false,false));
3285  }
3286  }
3287  CrystMatrix_int translate(27,3);
3288  translate= -1,-1,-1,
3289  -1,-1, 0,
3290  -1,-1, 1,
3291  -1, 0,-1,
3292  -1, 0, 0,
3293  -1, 0, 1,
3294  -1, 1,-1,
3295  -1, 1, 0,
3296  -1, 1, 1,
3297  0,-1,-1,
3298  0,-1, 0,
3299  0,-1, 1,
3300  0, 0,-1,
3301  0, 0, 0,
3302  0, 0, 1,
3303  0, 1,-1,
3304  0, 1, 0,
3305  0, 1, 1,
3306  1,-1,-1,
3307  1,-1, 0,
3308  1,-1, 1,
3309  1, 0,-1,
3310  1, 0, 0,
3311  1, 0, 1,
3312  1, 1,-1,
3313  1, 1, 0,
3314  1, 1, 1;
3315  REAL dx,dy,dz;
3316  CrystVector_REAL x(mvpAtom.size()),y(mvpAtom.size()),z(mvpAtom.size());
3317  CrystVector_REAL xSave,ySave,zSave;
3318  const int nbSymmetrics=vXYZCoords[0].rows();
3319  unsigned int ct=0;
3320  for(int i=0;i<nbSymmetrics;i++)
3321  {
3322  VFN_DEBUG_ENTRY("Molecule::POVRayDescription():Symmetric#"<<i,3)
3323  for(unsigned int j=0;j<mvpAtom.size();j++)
3324  {
3325  x(j)=vXYZCoords[j](i,0);
3326  y(j)=vXYZCoords[j](i,1);
3327  z(j)=vXYZCoords[j](i,2);
3328  }
3329  //Bring back central atom in unit cell; move peripheral atoms with the same amount
3330  dx=x(0);
3331  dy=y(0);
3332  dz=z(0);
3333  x(0) = fmod((float) x(0),(float)1); if(x(0)<0) x(0)+=1.;
3334  y(0) = fmod((float) y(0),(float)1); if(y(0)<0) y(0)+=1.;
3335  z(0) = fmod((float) z(0),(float)1); if(z(0)<0) z(0)+=1.;
3336  dx = x(0)-dx;
3337  dy = y(0)-dy;
3338  dz = z(0)-dz;
3339  for(unsigned int j=1;j<mvpAtom.size();j++)
3340  {
3341  x(j) += dx;
3342  y(j) += dy;
3343  z(j) += dz;
3344  }
3345  //Generate also translated atoms near the unit cell
3346  xSave=x;
3347  ySave=y;
3348  zSave=z;
3349  for(int j=0;j<translate.rows();j++)
3350  {
3351  x += translate(j,0);
3352  y += translate(j,1);
3353  z += translate(j,2);
3354  CrystVector<bool> isinside(x.numElements());
3355  CrystVector<REAL> borderdist(x.numElements());//distance to display limit
3356  CrystVector<REAL> x0,y0,z0;
3357  x0=x;y0=y;z0=z;
3358  if( ((x.min()<xMax) && (x.max()>xMin))
3359  &&((y.min()<yMax) && (y.max()>yMin))
3360  &&((z.min()<zMax) && (z.max()>zMin)))
3361  {
3362  os<<" //Symetric#"<<++ct<<endl;
3363  for(unsigned int k=0;k<mvpAtom.size();k++)
3364  {
3365  isinside(k)=((x(k)>=xMin) && (x(k)<=xMax)) && ((y(k)>=yMin) && (y(k)<=yMax)) && ((z(k)>=zMin) && (z(k)<=zMax));
3366  if(isinside(k)) borderdist(k)=0;
3367  else
3368  {
3369  borderdist(k)=0;
3370  if(xMin>x(k)) borderdist(k)+=(xMin-x(k))*aa*(xMin-x(k))*aa;
3371  if(yMin>y(k)) borderdist(k)+=(yMin-y(k))*bb*(yMin-y(k))*bb;
3372  if(zMin>z(k)) borderdist(k)+=(zMin-z(k))*cc*(zMin-z(k))*cc;
3373  if(xMax<x(k)) borderdist(k)+=(xMax-x(k))*aa*(xMax-x(k))*aa;
3374  if(yMax<y(k)) borderdist(k)+=(yMax-y(k))*bb*(yMax-y(k))*bb;
3375  if(zMax<z(k)) borderdist(k)+=(zMax-z(k))*cc*(zMax-z(k))*cc;
3376  borderdist(k)=sqrt(borderdist(k));
3377  }
3378  REAL fout=1.0;
3379  if(isinside(k)==false) fout=exp(-borderdist(k))*this->GetCrystal().GetDynPopCorr(this,k);
3380 
3381  this->GetCrystal().FractionalToOrthonormalCoords(x(k),y(k),z(k));
3382  if((mvpAtom[k]->IsDummy()) || (fout<0.001)) continue;
3383  if(options.mShowHydrogens==false && (mvpAtom[k]->GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue;
3384  // const float r=mvpAtom[k]->GetScatteringPower().GetColourRGB()[0];
3385  // const float g=mvpAtom[k]->GetScatteringPower().GetColourRGB()[1];
3386  // const float b=mvpAtom[k]->GetScatteringPower().GetColourRGB()[2];
3387  const float f=mvpAtom[k]->GetOccupancy()*this->GetOccupancy();
3388  if(options.mShowLabel)
3389  {
3390  /*
3391  const float colour0[] = {0.0f, 0.0f, 0.0f, 0.0f};
3392  GLfloat colourChar [] = {1.0, 1.0, 1.0, 1.0};
3393  if((r>0.8)&&(g>0.8)&&(b>0.8))
3394  {
3395  colourChar[0] = 0.5;
3396  colourChar[1] = 0.5;
3397  colourChar[2] = 0.5;
3398  }
3399  glMaterialfv(GL_FRONT, GL_AMBIENT, colour0);
3400  glMaterialfv(GL_FRONT, GL_DIFFUSE, colour0);
3401  glMaterialfv(GL_FRONT, GL_SPECULAR, colour0);
3402  glMaterialfv(GL_FRONT, GL_EMISSION, colourChar);
3403  glMaterialfv(GL_FRONT, GL_SHININESS,colour0);
3404  glRasterPos3f(x(k), y(k), z(k));
3405  crystGLPrint(mvpAtom[k]->GetName());
3406  */
3407  }
3408  os << " ObjCrystAtom("
3409  <<x(k)<<","
3410  <<y(k)<<","
3411  <<z(k)<<","
3412  <<mvpAtom[k]->GetScatteringPower().GetRadius()/3.0<<","
3413  <<"colour_"+mvpAtom[k]->GetScatteringPower().GetName()<<","
3414  <<f<<","<<fout
3415  <<")"<<endl;
3416  }
3417  for(unsigned int k=0;k<mvpBond.size();k++)
3418  {
3419  if( (mvpBond[k]->GetAtom1().IsDummy())
3420  ||(mvpBond[k]->GetAtom2().IsDummy()) ) continue;
3421  if(options.mShowHydrogens==false && ( (mvpBond[k]->GetAtom1().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)
3422  ||(mvpBond[k]->GetAtom2().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5))) continue;
3423  unsigned long n1,n2;
3424  //:KLUDGE: Get the atoms
3425  for(n1=0;n1<mvpAtom.size();n1++)
3426  if(mvpAtom[n1]==&(mvpBond[k]->GetAtom1())) break;
3427  for(n2=0;n2<mvpAtom.size();n2++)
3428  if(mvpAtom[n2]==&(mvpBond[k]->GetAtom2())) break;
3429  REAL fout=1.0;
3430  if((isinside(n1)==false) || (isinside(n2)==false))
3431  fout=exp(-(borderdist(n1)+borderdist(n2))/2)*(this->GetCrystal().GetDynPopCorr(this,n1)+this->GetCrystal().GetDynPopCorr(this,n2))/2;
3432  if(fout<0.001) continue;
3433  REAL x1=x(n1),y1=y(n1),z1=z(n1),
3434  x2=x(n2),y2=y(n2),z2=z(n2);
3435  REAL dx=x2-x1,dy=y2-y1,dz=z2-z1;
3436  const REAL r=sqrt(abs(dx*dx+dy*dy+dz*dz))+1e-6;
3437  const REAL r1=mvpAtom[n1]->GetScatteringPower().GetRadius()/3.0;
3438  const REAL r2=mvpAtom[n2]->GetScatteringPower().GetRadius()/3.0;
3439  x1+=dx/r*r1*sqrt(abs(1-0.1/r1));
3440  y1+=dy/r*r1*sqrt(abs(1-0.1/r1));
3441  z1+=dz/r*r1*sqrt(abs(1-0.1/r1));
3442  x2-=dx/r*r2*sqrt(abs(1-0.1/r2));
3443  y2-=dy/r*r2*sqrt(abs(1-0.1/r2));
3444  z2-=dz/r*r2*sqrt(abs(1-0.1/r2));
3445  const REAL f=this->GetOccupancy()*(mvpAtom[n1]->GetOccupancy()+mvpAtom[n2]->GetOccupancy())/2.0;
3446  os << " ObjCrystBond("
3447  <<x1<<","<<y1<<","<<z1<< ","
3448  <<x2<<","<<y2<<","<<z2<< ","
3449  << "0.1,";
3450  if(mvpBond[k]->IsFreeTorsion()) os<<"colour_freebond,";
3451  else os<<"colour_nonfreebond,";
3452  os<<f<<","<<fout<<")"<<endl;
3453  }
3454  }//if in limits
3455  x=xSave;
3456  y=ySave;
3457  z=zSave;
3458  }//for translation
3459  VFN_DEBUG_EXIT("Molecule::POVRayDescription():Symmetric#"<<i,3)
3460  }//for symmetrics
3461  VFN_DEBUG_EXIT("Molecule::POVRayDescription()",3)
3462  return os;
3463 }
3464 
3465 #ifdef OBJCRYST_GL
3466 void Molecule::GLInitDisplayList(const bool onlyIndependentAtoms,
3467  const REAL xMin,const REAL xMax,
3468  const REAL yMin,const REAL yMax,
3469  const REAL zMin,const REAL zMax,
3470  const bool displayEnantiomer,
3471  const bool displayNames,
3472  const bool hideHydrogens,
3473  const REAL fadeDistance,
3474  const bool fullMoleculeInLimits)const
3475 {
3476  VFN_DEBUG_ENTRY("Molecule::GLInitDisplayList()",3)
3477  if(mvpAtom.size()==0)
3478  {
3479  VFN_DEBUG_EXIT("Molecule::GLInitDisplayList():No atom to display !",4)
3480  return;
3481  }
3482 
3483  bool large=false;
3484  if(mvpAtom.size()>200) large=true;
3485  REAL en=1;
3486  if(displayEnantiomer==true) en=-1;
3487  this->UpdateScattCompList();
3488  //this->BuildRingList();
3489  //this->BuildStretchModeBondLength();
3490  //this->BuildStretchModeBondAngle();
3491  //this->BuildStretchModeTorsion();
3492 
3493  const REAL aa=this->GetCrystal().GetLatticePar(0);
3494  const REAL bb=this->GetCrystal().GetLatticePar(1);
3495  const REAL cc=this->GetCrystal().GetLatticePar(2);
3496 
3497  const GLfloat colour0[] = {0.0f, 0.0f, 0.0f, 0.0f};
3498  glMaterialfv(GL_FRONT, GL_SPECULAR, colour0);
3499  glMaterialfv(GL_FRONT, GL_EMISSION, colour0);
3500  glMaterialfv(GL_FRONT, GL_SHININESS, colour0);
3501  glPolygonMode(GL_FRONT, GL_FILL);
3502 
3503  GLUquadricObj* pQuadric = gluNewQuadric();
3504 
3505  if(true==onlyIndependentAtoms)//
3506  {
3507  REAL xc=mXYZ(0),yc=mXYZ(1),zc=mXYZ(2);
3508  this->GetCrystal().FractionalToOrthonormalCoords(xc,yc,zc);
3509  vector<MolAtom*>::const_iterator pos;
3510  for(pos=mvpAtom.begin();pos!=mvpAtom.end();pos++)
3511  {
3512 
3513  if((*pos)->IsDummy())continue;
3514  if(hideHydrogens && ((*pos)->GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue;
3515  const float r=(*pos)->GetScatteringPower().GetColourRGB()[0];
3516  const float g=(*pos)->GetScatteringPower().GetColourRGB()[1];
3517  const float b=(*pos)->GetScatteringPower().GetColourRGB()[2];
3518  const float f=(*pos)->GetOccupancy()*this->GetOccupancy();
3519  glPushMatrix();
3520  if(displayNames)
3521  {
3522  GLfloat colourChar [] = {1.0, 1.0, 1.0, 1.0};
3523  GLfloat colourCharRing [] = {1.0, 1.0, 0.8, 1.0};
3524  if((r>0.8)&&(g>0.8)&&(b>0.8))
3525  {
3526  colourChar[0] = 0.5;
3527  colourChar[1] = 0.5;
3528  colourChar[2] = 0.5;
3529  }
3530  if((*pos)->IsInRing())
3531  glMaterialfv(GL_FRONT, GL_EMISSION, colourCharRing);
3532  else
3533  glMaterialfv(GL_FRONT, GL_EMISSION, colourChar);
3534  glMaterialfv(GL_FRONT, GL_SHININESS, colour0);
3535  glTranslatef((*pos)->X()*en+xc, (*pos)->Y()+yc, (*pos)->Z()+zc);
3536  crystGLPrint((*pos)->GetName());
3537  }
3538  else
3539  {
3540  const GLfloat colourAtom [] = {r, g, b, f};
3541  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colourAtom);
3542  glTranslatef((*pos)->X()*en+xc, (*pos)->Y()+yc, (*pos)->Z()+zc);
3543  gluSphere(pQuadric,(*pos)->GetScatteringPower().GetRadius()/3.,20,20);
3544  }
3545  glPopMatrix();
3546  }
3547  }//Only independent atoms ?
3548  else
3549  {
3550  VFN_DEBUG_ENTRY("Molecule::GLInitDisplayList():Show all symmetrics",3)
3551  // Reverse index of atoms
3552  map<const MolAtom*,unsigned long> rix;
3553  {
3554  long i=0;
3555  for(vector<MolAtom*>::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
3556  rix[*pos]=i++;
3557  }
3558  vector<CrystMatrix_REAL> vXYZCoords;
3559  {
3561  REAL x0,y0,z0;
3562  for(long i=0;i<mScattCompList.GetNbComponent();++i)
3563  {
3564  x0=mScattCompList(i).mX;
3565  y0=mScattCompList(i).mY;
3566  z0=mScattCompList(i).mZ;
3567  vXYZCoords.push_back(this->GetCrystal().GetSpaceGroup().
3568  GetAllSymmetrics(x0,y0,z0,false,false,false));
3569  }
3570  }
3571  CrystMatrix_int translate(27,3);
3572  translate= -1,-1,-1,
3573  -1,-1, 0,
3574  -1,-1, 1,
3575  -1, 0,-1,
3576  -1, 0, 0,
3577  -1, 0, 1,
3578  -1, 1,-1,
3579  -1, 1, 0,
3580  -1, 1, 1,
3581  0,-1,-1,
3582  0,-1, 0,
3583  0,-1, 1,
3584  0, 0,-1,
3585  0, 0, 0,
3586  0, 0, 1,
3587  0, 1,-1,
3588  0, 1, 0,
3589  0, 1, 1,
3590  1,-1,-1,
3591  1,-1, 0,
3592  1,-1, 1,
3593  1, 0,-1,
3594  1, 0, 0,
3595  1, 0, 1,
3596  1, 1,-1,
3597  1, 1, 0,
3598  1, 1, 1;
3599  REAL dx,dy,dz;
3600  CrystVector_REAL x(mvpAtom.size()),y(mvpAtom.size()),z(mvpAtom.size());
3601  CrystVector_REAL xSave,ySave,zSave;
3602  const int nbSymmetrics=vXYZCoords[0].rows();
3603  for(int i=0;i<nbSymmetrics;i++)
3604  {
3605  VFN_DEBUG_ENTRY("Molecule::GLInitDisplayList():Symmetric#"<<i,3)
3606  for(unsigned int j=0;j<mvpAtom.size();j++)
3607  {
3608  x(j)=vXYZCoords[j](i,0);
3609  y(j)=vXYZCoords[j](i,1);
3610  z(j)=vXYZCoords[j](i,2);
3611  }
3612  //Bring back central atom in unit cell; move peripheral atoms with the same amount
3613  dx=x(0);
3614  dy=y(0);
3615  dz=z(0);
3616  x(0) = fmod((float) x(0),(float)1); if(x(0)<0) x(0)+=1.;
3617  y(0) = fmod((float) y(0),(float)1); if(y(0)<0) y(0)+=1.;
3618  z(0) = fmod((float) z(0),(float)1); if(z(0)<0) z(0)+=1.;
3619  dx = x(0)-dx;
3620  dy = y(0)-dy;
3621  dz = z(0)-dz;
3622  for(unsigned int j=1;j<mvpAtom.size();j++)
3623  {
3624  x(j) += dx;
3625  y(j) += dy;
3626  z(j) += dz;
3627  }
3628  //Generate also translated atoms near the unit cell
3629  xSave=x;
3630  ySave=y;// Keep untranslated, fractionnal values
3631  zSave=z;
3632  for(int j=0;j<translate.rows();j++)
3633  {
3634  x += translate(j,0);
3635  y += translate(j,1);
3636  z += translate(j,2);
3637  CrystVector<bool> isinside(x.numElements());
3638  CrystVector<REAL> borderdist(x.numElements());//distance to display limit
3639  const bool molcenter_isinside =( ((x.sum()/x.size())>=xMin) && ((x.sum()/x.size())<=xMax)
3640  && ((y.sum()/y.size())>=yMin) && ((y.sum()/y.size())<=yMax)
3641  && ((z.sum()/z.size())>=zMin) && ((z.sum()/z.size())<=zMax));
3642  if( ((x.min()<(xMax+fadeDistance/aa)) && (x.max()>(xMin-fadeDistance/aa)))
3643  &&((y.min()<(yMax+fadeDistance/bb)) && (y.max()>(yMin-fadeDistance/bb)))
3644  &&((z.min()<(zMax+fadeDistance/cc)) && (z.max()>(zMin-fadeDistance/cc))))
3645  {
3646  for(unsigned int k=0;k<mvpAtom.size();k++)
3647  {
3648  isinside(k)=((x(k)>=xMin) && (x(k)<=xMax)) && ((y(k)>=yMin) && (y(k)<=yMax)) && ((z(k)>=zMin) && (z(k)<=zMax));
3649  if(isinside(k)) borderdist(k)=0;
3650  else
3651  {
3652  borderdist(k)=0;
3653  if(xMin>x(k)) borderdist(k)+=(xMin-x(k))*aa*(xMin-x(k))*aa;
3654  if(yMin>y(k)) borderdist(k)+=(yMin-y(k))*bb*(yMin-y(k))*bb;
3655  if(zMin>z(k)) borderdist(k)+=(zMin-z(k))*cc*(zMin-z(k))*cc;
3656  if(xMax<x(k)) borderdist(k)+=(xMax-x(k))*aa*(xMax-x(k))*aa;
3657  if(yMax<y(k)) borderdist(k)+=(yMax-y(k))*bb*(yMax-y(k))*bb;
3658  if(zMax<z(k)) borderdist(k)+=(zMax-z(k))*cc*(zMax-z(k))*cc;
3659  borderdist(k)=sqrt(borderdist(k));
3660  }
3661  REAL fout=1.0;
3662  if((isinside(k)==false) && ((molcenter_isinside==false) || (fullMoleculeInLimits==false)))
3663  {
3664  if ((fadeDistance == 0) || borderdist(k)>fadeDistance) fout = 0;
3665  else fout*=(fadeDistance-borderdist(k))/fadeDistance*this->GetCrystal().GetDynPopCorr(this,k);
3666  }
3667  #ifdef __DEBUG__
3668  char ch[100];
3669  sprintf(ch,"%d %d %d %s %5.2f %5.2f %5.2f d=%5.2f fout=%5.3f",i,j,k,mvpAtom[k]->GetName().c_str(),x(k),y(k),z(k),borderdist(k),fout);
3670  VFN_DEBUG_MESSAGE(ch,4)
3671  #endif
3672  this->GetCrystal().FractionalToOrthonormalCoords(x(k),y(k),z(k));
3673  if(mvpAtom[k]->IsDummy()) continue;
3674  if(hideHydrogens && (mvpAtom[k]->GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue;
3675  if(fout<0.01) continue;
3676  glPushMatrix();
3677  const float r=mvpAtom[k]->GetScatteringPower().GetColourRGB()[0];
3678  const float g=mvpAtom[k]->GetScatteringPower().GetColourRGB()[1];
3679  const float b=mvpAtom[k]->GetScatteringPower().GetColourRGB()[2];
3680  const float f=mvpAtom[k]->GetOccupancy()*this->GetOccupancy();
3681  if(displayNames)
3682  {
3683  if((fout>0.99) || molcenter_isinside)
3684  {
3685  GLfloat colourChar [] = {1.0, 1.0, 1.0, f*fout};
3686  GLfloat colourCharRing [] = {1.0, 1.0, 0.8, f*fout};
3687  if((r>0.8)&&(g>0.8)&&(b>0.8))
3688  {
3689  colourChar[0] = 0.5;
3690  colourChar[1] = 0.5;
3691  colourChar[2] = 0.5;
3692  }
3693  if(mvpAtom[k]->IsInRing())
3694  glMaterialfv(GL_FRONT, GL_EMISSION, colourCharRing);
3695  else
3696  glMaterialfv(GL_FRONT, GL_EMISSION, colourChar);
3697  glRasterPos3f(x(k)*en, y(k), z(k));
3698  crystGLPrint(mvpAtom[k]->GetName());
3699  }
3700  }
3701  else
3702  {
3703  if(!large)
3704  {
3705  const GLfloat colourAtom [] = {r*fout, g*fout, b*fout, f*fout};
3706  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,colourAtom);
3707  glTranslatef(x(k)*en, y(k), z(k));
3708  gluSphere(pQuadric,
3709  mvpAtom[k]->GetScatteringPower().GetRadius()/3.,20,20);
3710  }
3711  else
3712  {
3713  const GLfloat colourAtom [] = {r*fout, g*fout, b*fout, f*fout};
3714  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,colourAtom);
3715  glTranslatef(x(k)*en, y(k), z(k));
3716  gluSphere(pQuadric,.15,10,10);
3717  }
3718  }
3719  glPopMatrix();
3720  }
3721  if(displayNames==false)
3722  {
3723  if(large)
3724  {
3725  for(unsigned int k=0;k<mvpBond.size();k++)
3726  {
3727  if( (mvpBond[k]->GetAtom1().IsDummy())
3728  ||(mvpBond[k]->GetAtom2().IsDummy()) ) continue;
3729  if(hideHydrogens && ( (mvpBond[k]->GetAtom1().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)
3730  ||(mvpBond[k]->GetAtom2().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5))) continue;
3731  const unsigned long n1=rix[&(mvpBond[k]->GetAtom1())],
3732  n2=rix[&(mvpBond[k]->GetAtom2())];
3733  REAL fout=1.0;
3734  if(((isinside(n1)==false) || (isinside(n2)==false)) && ((molcenter_isinside==false) || (fullMoleculeInLimits==false)))
3735  {
3736  if((fadeDistance==0) || ((borderdist(n1)+borderdist(n2))/2)>fadeDistance) fout = 0;
3737  else fout*=(fadeDistance-(borderdist(n1)+borderdist(n2))/2)/fadeDistance*
3738  (this->GetCrystal().GetDynPopCorr(this,n1)+this->GetCrystal().GetDynPopCorr(this,n2))/2;
3739  }
3740  if(fout<0.01) continue;
3741 
3742  const float r1=mvpBond[k]->GetAtom1().GetScatteringPower().GetColourRGB()[0];
3743  const float g1=mvpBond[k]->GetAtom1().GetScatteringPower().GetColourRGB()[1];
3744  const float b1=mvpBond[k]->GetAtom1().GetScatteringPower().GetColourRGB()[2];
3745  const float f1=mvpBond[k]->GetAtom1().GetOccupancy()*this->GetOccupancy();
3746  const float r2=mvpBond[k]->GetAtom2().GetScatteringPower().GetColourRGB()[0];
3747  const float g2=mvpBond[k]->GetAtom2().GetScatteringPower().GetColourRGB()[1];
3748  const float b2=mvpBond[k]->GetAtom2().GetScatteringPower().GetColourRGB()[2];
3749  const float f2=mvpBond[k]->GetAtom2().GetOccupancy()*this->GetOccupancy();
3750  const GLfloat colourAtom1 [] = {r1, g1, b1, f1*fout};
3751  const GLfloat colourAtom2 [] = {r2, g2, b2, f2*fout};
3752  #if 0
3753  glPushMatrix();
3754  glBegin(GL_LINE_STRIP);
3755  glMaterialfv(GL_FRONT, GL_SPECULAR, colourAtom1);
3756  glMaterialfv(GL_FRONT, GL_EMISSION, colourAtom1);
3757  glMaterialfv(GL_FRONT, GL_SHININESS, colourAtom1);
3758  glVertex3f(x(n1)*en,y(n1),z(n1));
3759  glVertex3f((x(n1)+x(n2))/2*en,(y(n1)+y(n2))/2,(z(n1)+z(n2))/2);
3760  glMaterialfv(GL_FRONT, GL_SPECULAR, colourAtom2);
3761  glMaterialfv(GL_FRONT, GL_EMISSION, colourAtom2);
3762  glMaterialfv(GL_FRONT, GL_SHININESS, colourAtom2);
3763  glVertex3f(x(n2)*en,y(n2),z(n2));
3764  glEnd();
3765  glPopMatrix();
3766  #else
3767  const REAL height= sqrt(abs( (x(n2)-x(n1))*(x(n2)-x(n1))
3768  +(y(n2)-y(n1))*(y(n2)-y(n1))
3769  +(z(n2)-z(n1))*(z(n2)-z(n1))));
3770  glPushMatrix();
3771  glTranslatef(x(n1)*en, y(n1), z(n1));
3772  GLUquadricObj *quadobj = gluNewQuadric();
3773  glRotatef(180,(x(n2)-x(n1))*en,y(n2)-y(n1),z(n2)-z(n1)+height);// ?!?!?!
3774 
3775  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colourAtom1);
3776  gluCylinder(quadobj,.1,.1,height/2,10,1 );
3777  gluDeleteQuadric(quadobj);
3778 
3779  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colourAtom2);
3780  GLUquadricObj *quadobj2 = gluNewQuadric();
3781  glTranslatef(0, 0, height/2);
3782  gluCylinder(quadobj2,.1,.1,height/2,10,1 );
3783  gluDeleteQuadric(quadobj2);
3784  glPopMatrix();
3785  #endif
3786  }
3787  }
3788  else
3789  {
3790  for(unsigned int k=0;k<mvpBond.size();k++)
3791  {
3792  if( (mvpBond[k]->GetAtom1().IsDummy())
3793  ||(mvpBond[k]->GetAtom2().IsDummy()) ) continue;
3794  if(hideHydrogens && ( (mvpBond[k]->GetAtom1().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)
3795  ||(mvpBond[k]->GetAtom2().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5))) continue;
3796  const unsigned long n1=rix[&(mvpBond[k]->GetAtom1())],
3797  n2=rix[&(mvpBond[k]->GetAtom2())];
3798  REAL fout=1.0;
3799  //if((isinside(n1)==false) || (isinside(n2)==false)) fout=exp(-(borderdist(n1)+borderdist(n2))/2);
3800  if(((isinside(n1)==false) || (isinside(n2)==false)) && ((molcenter_isinside==false) || (fullMoleculeInLimits==false)))
3801  {
3802  if ((fadeDistance == 0) || ((borderdist(n1) + borderdist(n2)) / 2)>fadeDistance)
3803  fout = 0;
3804  else
3805  fout=(fadeDistance-(borderdist(n1)+borderdist(n2))/2)/fadeDistance*
3806  (this->GetCrystal().GetDynPopCorr(this,n1)+this->GetCrystal().GetDynPopCorr(this,n2))/2;
3807  }
3808 
3809  if(fout<0.01) continue;
3810  // Is the bond in a rigid group ?
3811  bool isRigidGroup=false;
3812  for(vector<RigidGroup *>::const_iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
3813  {
3814  if( ((*pos)->find(&(mvpBond[k]->GetAtom1()))!=(*pos)->end())
3815  &&((*pos)->find(&(mvpBond[k]->GetAtom2()))!=(*pos)->end()) )
3816  {
3817  isRigidGroup=true;
3818  break;
3819  }
3820  }
3821  const float f=(mvpBond[k]->GetAtom1().GetOccupancy()+mvpBond[k]->GetAtom2().GetOccupancy())/2*this->GetOccupancy();
3822  const GLfloat colour_bondnonfree[]= { 0.2f*fout, .2f*fout, .2f*fout, f*fout };
3823  const GLfloat colour_bondrigid[]= { 0.5f*fout, .3f*fout, .3f*fout, f*fout };
3824  const GLfloat colour_bondfree[]= { 0.8f*fout, .8f*fout, .8f*fout, f*fout };
3825  if(isRigidGroup)
3826  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colour_bondrigid);
3827  else
3828  {
3829  if(mvpBond[k]->IsFreeTorsion())
3830  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colour_bondfree);
3831  else
3832  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colour_bondnonfree);
3833  }
3834  // Actually make the bond start/end at the surface of the spheres (matters when transparent)
3835  REAL x1=x(n1),y1=y(n1),z1=z(n1),
3836  x2=x(n2),y2=y(n2),z2=z(n2);
3837  REAL dx=x2-x1,dy=y2-y1,dz=z2-z1;
3838  const REAL r=sqrt(abs(dx*dx+dy*dy+dz*dz))+1e-6;
3839  const REAL r1=mvpAtom[n1]->GetScatteringPower().GetRadius()/3.0;
3840  const REAL r2=mvpAtom[n2]->GetScatteringPower().GetRadius()/3.0;
3841  x1+=dx/r*r1*sqrt(abs(1-0.1/r1));
3842  y1+=dy/r*r1*sqrt(abs(1-0.1/r1));
3843  z1+=dz/r*r1*sqrt(abs(1-0.1/r1));
3844  x2-=dx/r*r2*sqrt(abs(1-0.1/r2));
3845  y2-=dy/r*r2*sqrt(abs(1-0.1/r2));
3846  z2-=dz/r*r2*sqrt(abs(1-0.1/r2));
3847 
3848  glPushMatrix();
3849  glTranslatef(x1*en, y1, z1);
3850  GLUquadricObj *quadobj = gluNewQuadric();
3851  //glColor4f(1.0f,1.0f,1.0f,1.0);
3852  const REAL height= sqrt(abs( (x2-x1)*(x2-x1)
3853  +(y2-y1)*(y2-y1)
3854  +(z2-z1)*(z2-z1)));
3855  glRotatef(180,(x2-x1)*en,y2-y1,z2-z1+height);// ?!?!?!
3856  gluCylinder(quadobj,.1,.1,height,10,1 );
3857  gluDeleteQuadric(quadobj);
3858  glPopMatrix();
3859  }
3860  }
3861  }
3862  }//if in limits
3863  x=xSave;
3864  y=ySave;
3865  z=zSave;
3866  }//for translation
3867  VFN_DEBUG_EXIT("Molecule::GLInitDisplayList():Symmetric#"<<i,3)
3868  }//for symmetrics
3869  VFN_DEBUG_EXIT("Molecule::GLInitDisplayList():Show all symmetrics",3)
3870  }//else
3871  gluDeleteQuadric(pQuadric);
3872  VFN_DEBUG_EXIT("Molecule::GLInitDisplayList()",3)
3873 }
3874 #endif // OBJCRYST_GL
3875 
3876 void Molecule::AddAtom(const REAL x, const REAL y, const REAL z,
3877  const ScatteringPower *pPow, const string &name,
3878  const bool updateDisplay)
3879 {
3880  VFN_DEBUG_ENTRY("Molecule::AddAtom():"<<name,5)
3881  const bool molnameasformula= this->GetName()==this->GetFormula();
3882 
3883  string thename=name;
3884  if(thename==string(""))
3885  {// This should not be needed, the atom will reset the parameters name when its name is set
3886  char buf[100];
3887  if(pPow!=0) sprintf(buf,"%s_%s_%lu",this->GetName().c_str(),pPow->GetName().c_str(),mvpAtom.size()+1);
3888  else sprintf(buf,"%s_X_%lu",this->GetName().c_str(),mvpAtom.size()+1);
3889  thename=buf;
3890  }
3891  mvpAtom.push_back(new MolAtom(x,y,z,pPow,thename,*this));
3892  mClockAtomPosition.Click();
3893  mClockAtomScattPow.Click();
3894  ++mScattCompList;
3895  {
3896  RefinablePar tmp(thename+"_x",&(mvpAtom.back()->X()),0.,1.,
3897  gpRefParTypeScattConformX,
3898  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
3899  tmp.AssignClock(mClockAtomPosition);
3900  tmp.SetGlobalOptimStep(0.05);
3901  tmp.SetDerivStep(1e-4);
3902  this->AddPar(tmp);
3903  }
3904  {
3905  RefinablePar tmp(thename+"_y",&(mvpAtom.back()->Y()),0.,1.,
3906  gpRefParTypeScattConformY,
3907  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
3908  tmp.AssignClock(mClockAtomPosition);
3909  tmp.SetGlobalOptimStep(0.05);
3910  tmp.SetDerivStep(1e-4);
3911  this->AddPar(tmp);
3912  }
3913  {
3914  RefinablePar tmp(thename+"_z",&(mvpAtom.back()->Z()),0.,1.,
3915  gpRefParTypeScattConformZ,
3916  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
3917  tmp.AssignClock(mClockAtomPosition);
3918  tmp.SetGlobalOptimStep(0.05);
3919  tmp.SetDerivStep(1e-4);
3920  this->AddPar(tmp);
3921  }
3922 
3924 
3925  if(molnameasformula || (this->GetName().size()==0))
3926  this->SetName(this->GetFormula());
3927 
3928  if(updateDisplay) this->UpdateDisplay();
3929  VFN_DEBUG_EXIT("Molecule::AddAtom()",5)
3930 }
3931 
3932 vector<MolAtom*>::iterator Molecule::RemoveAtom(MolAtom &atom, const bool del)
3933 {
3934  VFN_DEBUG_ENTRY("Molecule::RemoveAtom():"<<atom.GetName(),6)
3935  vector<MolAtom*>::iterator pos=find(mvpAtom.begin(),mvpAtom.end(),&atom);
3936  if(pos==mvpAtom.end())
3937  {
3938  throw ObjCrystException("Molecule::RemoveAtom():"+atom.GetName()
3939  +" is not in this Molecule:"+this->GetName());
3940  }
3941  const bool molnameasformula= this->GetName()==this->GetFormula();
3942  // Delete parameters
3943  this->RemovePar(&(this->GetPar(&(atom.X()))));
3944  this->RemovePar(&(this->GetPar(&(atom.Y()))));
3945  this->RemovePar(&(this->GetPar(&(atom.Z()))));
3946  // Delete relevant bonds, bond angles, dihedral angles...
3947  for(vector<MolBond*>::iterator posb=mvpBond.begin();posb!=mvpBond.end();)
3948  {
3949  if( (&atom==&((*posb)->GetAtom1())) || (&atom==&((*posb)->GetAtom2())) )
3950  {
3951  posb=this->RemoveBond(**posb, del);
3952  }
3953  else ++posb;
3954  }
3955  for(vector<MolBondAngle*>::iterator posb=mvpBondAngle.begin();posb!=mvpBondAngle.end();)
3956  {
3957  if( (&atom==&((*posb)->GetAtom1())) || (&atom==&((*posb)->GetAtom2()))
3958  ||(&atom==&((*posb)->GetAtom3())))
3959  {
3960  posb=this->RemoveBondAngle(**posb, del);
3961  }
3962  else ++posb;
3963  }
3964  for(vector<MolDihedralAngle*>::iterator posb=mvpDihedralAngle.begin();
3965  posb!=mvpDihedralAngle.end();)
3966  {
3967  if( (&atom==&((*posb)->GetAtom1())) || (&atom==&((*posb)->GetAtom2()))
3968  ||(&atom==&((*posb)->GetAtom3())) || (&atom==&((*posb)->GetAtom4())))
3969  posb=this->RemoveDihedralAngle(**posb, del);
3970  else ++posb;
3971  }
3972  mClockAtomList.Click();
3974 
3975  if(mpCenterAtom==*pos) mpCenterAtom=0;
3976  if(del) delete *pos;
3977  pos=mvpAtom.erase(pos);
3978  --mScattCompList;
3979 
3980  if(molnameasformula || (this->GetName().size()==0))
3981  this->SetName(this->GetFormula());
3982 
3983  this->UpdateDisplay();
3984  VFN_DEBUG_EXIT("Molecule::RemoveAtom()",6)
3985  return pos;
3986 }
3987 
3988 void Molecule::AddBond(MolAtom &atom1, MolAtom &atom2,
3989  const REAL length, const REAL sigma, const REAL delta,
3990  const REAL bondOrder,
3991  const bool updateDisplay)
3992 {
3993  VFN_DEBUG_ENTRY("Molecule::AddBond()",5)
3994  mvpBond.push_back(new MolBond(atom1,atom2,length,sigma,delta,*this,bondOrder));
3995  this->AddRestraint(mvpBond.back());
3996  mClockBondList.Click();
3997  if(updateDisplay) this->UpdateDisplay();
3998  VFN_DEBUG_EXIT("Molecule::AddBond()",5)
3999 }
4000 
4001 vector<MolBond*>::iterator Molecule::RemoveBond(const MolBond &bond, const bool del)
4002 {
4003  VFN_DEBUG_ENTRY("Molecule::RemoveBond():"<<bond.GetName(),6)
4004  vector<MolBond*>::iterator pos=find(mvpBond.begin(),mvpBond.end(),&bond);
4005  if(pos==mvpBond.end())
4006  {
4007  throw ObjCrystException("Molecule::RemoveBond():"+bond.GetAtom1().GetName()
4008  +"-"+bond.GetAtom2().GetName()
4009  +" is not in this Molecule:"+this->GetName());
4010  }
4011  this->RemoveRestraint(*pos);
4012  mClockBondList.Click();
4013  if(del) delete *pos;
4014  pos= mvpBond.erase(pos);
4015  this->UpdateDisplay();
4016  VFN_DEBUG_EXIT("Molecule::RemoveBond():",6)
4017  return pos;
4018 }
4019 
4020 vector<MolBond*>::const_iterator Molecule::FindBond(const MolAtom &at1,const MolAtom &at2)const
4021 {
4022  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
4023  {
4024  if( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom2())==&at2))
4025  ||((&((*pos)->GetAtom1())==&at2)&&(&((*pos)->GetAtom2())==&at1)))
4026  return pos;
4027  }
4028  return mvpBond.end();
4029 }
4030 vector<MolBond*>::iterator Molecule::FindBond(const MolAtom &at1,const MolAtom &at2)
4031 {
4032  for(vector<MolBond*>::iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
4033  {
4034  if( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom2())==&at2))
4035  ||((&((*pos)->GetAtom1())==&at2)&&(&((*pos)->GetAtom2())==&at1)))
4036  return pos;
4037  }
4038  return mvpBond.end();
4039 }
4040 
4041 void Molecule::AddBondAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3,
4042  const REAL angle, const REAL sigma, const REAL delta,
4043  const bool updateDisplay)
4044 {
4045  VFN_DEBUG_ENTRY("Molecule::AddBondAngle()",5)
4046  mvpBondAngle.push_back(new MolBondAngle(atom1,atom2,atom3,angle,sigma,delta,*this));
4047  this->AddRestraint(mvpBondAngle.back());
4048  mClockBondAngleList.Click();
4049  if(updateDisplay) this->UpdateDisplay();
4050  VFN_DEBUG_EXIT("Molecule::AddBondAngle()",5)
4051 }
4052 
4053 vector<MolBondAngle*>::iterator Molecule::RemoveBondAngle(const MolBondAngle &angle, const bool del)
4054 {
4055  VFN_DEBUG_ENTRY("Molecule::RemoveBondAngle():"<<angle.GetName(),6)
4056  vector<MolBondAngle*>::iterator pos=find(mvpBondAngle.begin(),mvpBondAngle.end(),&angle);
4057  if(pos==mvpBondAngle.end())
4058  {
4059  throw ObjCrystException("Molecule::RemoveBondAngle():"+angle.GetAtom1().GetName()
4060  +"-"+angle.GetAtom2().GetName()+"-"+angle.GetAtom3().GetName()
4061  +" is not in this Molecule:"+this->GetName());
4062  }
4063  this->RemoveRestraint(*pos);
4064  mClockBondAngleList.Click();
4065  if(del) delete *pos;
4066  pos=mvpBondAngle.erase(pos);
4067  this->UpdateDisplay();
4068  VFN_DEBUG_EXIT("Molecule::RemoveBondAngle():",6)
4069  return pos;
4070 }
4071 
4072 vector<MolBondAngle*>::const_iterator Molecule::FindBondAngle(const MolAtom &at1,
4073  const MolAtom &at2,
4074  const MolAtom &at3)const
4075 {
4076  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();
4077  pos!=mvpBondAngle.end();++pos)
4078  {
4079  if( (&((*pos)->GetAtom2())==&at2)
4080  &&( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom3())==&at3))
4081  ||((&((*pos)->GetAtom1())==&at3)&&(&((*pos)->GetAtom3())==&at1))))
4082  return pos;
4083  }
4084  return mvpBondAngle.end();
4085 }
4086 
4088  MolAtom &atom3, MolAtom &atom4,
4089  const REAL angle, const REAL sigma, const REAL delta,
4090  const bool updateDisplay)
4091 {
4092  VFN_DEBUG_ENTRY("Molecule::AddDihedralAngle()",5)
4093  mvpDihedralAngle.push_back(new MolDihedralAngle(atom1,atom2,atom3,atom4,
4094  angle,sigma,delta,*this));
4095  this->AddRestraint(mvpDihedralAngle.back());
4096  mClockDihedralAngleList.Click();
4097  if(updateDisplay) this->UpdateDisplay();
4098  VFN_DEBUG_EXIT("Molecule::AddDihedralAngle()",5)
4099 }
4100 
4101 vector<MolDihedralAngle*>::iterator Molecule::RemoveDihedralAngle(const MolDihedralAngle &angle, const bool del)
4102 {
4103  VFN_DEBUG_ENTRY("Molecule::RemoveDihedralAngle():"<<angle.GetName(),6)
4104  vector<MolDihedralAngle*>::iterator pos=find(mvpDihedralAngle.begin(),
4105  mvpDihedralAngle.end(),&angle);
4106  if(pos==mvpDihedralAngle.end())
4107  {
4108  throw ObjCrystException("Molecule::RemoveDihedralAngle():"+angle.GetAtom1().GetName()
4109  +"-"+angle.GetAtom2().GetName()+"-"+angle.GetAtom3().GetName()
4110  +"-"+angle.GetAtom4().GetName()
4111  +" is not in this Molecule:"+this->GetName());
4112  }
4113  this->RemoveRestraint(*pos);
4114  mClockDihedralAngleList.Click();
4115  if(del) delete *pos;
4116  pos=mvpDihedralAngle.erase(pos);
4117  this->UpdateDisplay();
4118  VFN_DEBUG_ENTRY("Molecule::RemoveDihedralAngle():",6)
4119  return pos;
4120 }
4121 vector<MolDihedralAngle*>::const_iterator Molecule::FindDihedralAngle(const MolAtom &at1,
4122  const MolAtom &at2,
4123  const MolAtom &at3,
4124  const MolAtom &at4)const
4125 {
4126  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();
4127  pos!=mvpDihedralAngle.end();++pos)
4128  {
4129  if( ( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom2())==&at2))
4130  &&((&((*pos)->GetAtom3())==&at3)&&(&((*pos)->GetAtom4())==&at4)))
4131  ||( ((&((*pos)->GetAtom4())==&at1)&&(&((*pos)->GetAtom3())==&at2))
4132  &&((&((*pos)->GetAtom2())==&at3)&&(&((*pos)->GetAtom1())==&at4))))
4133  return pos;
4134  }
4135  return mvpDihedralAngle.end();
4136 }
4137 
4139  const bool updateDisplay)
4140 {
4141  mvRigidGroup.push_back(new RigidGroup(group));
4142  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
4143  char buf[50];
4144  const unsigned int i=mvRigidGroup.size();
4145  RigidGroup* p=this->GetRigidGroupList().back();
4146  p->mX=0;
4147  p->mY=0;
4148  p->mZ=0;
4149  p->mQuat.Q0()=1;
4150  p->mQuat.Q1()=0;
4151  p->mQuat.Q2()=0;
4152  p->mQuat.Q3()=0;
4153  {
4154  sprintf(buf,"RigidGroup%d_x",i);
4155  RefinablePar tmp(buf,&(p->mX),0.,1.,
4156  gpRefParTypeScattConformX,
4157  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
4158  tmp.AssignClock(mClockAtomPosition);
4159  tmp.SetGlobalOptimStep(0.05);
4160  tmp.SetDerivStep(1e-4);
4161  this->AddPar(tmp);
4162  }
4163  {
4164  sprintf(buf,"RigidGroup%d_y",i);
4165  RefinablePar tmp(buf,&(p->mY),0.,1.,
4166  gpRefParTypeScattConformY,
4167  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
4168  tmp.AssignClock(mClockAtomPosition);
4169  tmp.SetGlobalOptimStep(0.05);
4170  tmp.SetDerivStep(1e-4);
4171  this->AddPar(tmp);
4172  }
4173  {
4174  sprintf(buf,"RigidGroup%d_z",i);
4175  RefinablePar tmp(buf,&(p->mZ),0.,1.,
4176  gpRefParTypeScattConformZ,
4177  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
4178  tmp.AssignClock(mClockAtomPosition);
4179  tmp.SetGlobalOptimStep(0.05);
4180  tmp.SetDerivStep(1e-4);
4181  this->AddPar(tmp);
4182  }
4183  {
4184  sprintf(buf,"RigidGroup%d_Q1",i);
4185  RefinablePar tmp(buf,&(p->mQuat.Q1()),-1,1.,
4186  gpRefParTypeScattConform,
4187  REFPAR_DERIV_STEP_ABSOLUTE,true,false,true,false,1.,1.);
4188  tmp.AssignClock(mClockAtomPosition);
4189  tmp.SetGlobalOptimStep(0.01);
4190  tmp.SetDerivStep(1e-4);
4191  this->AddPar(tmp);
4192  }
4193  {
4194  sprintf(buf,"RigidGroup%d_Q2",i);
4195  RefinablePar tmp(buf,&(p->mQuat.Q2()),-1,1.,
4196  gpRefParTypeScattConform,
4197  REFPAR_DERIV_STEP_ABSOLUTE,true,false,true,false,1.,1.);
4198  tmp.AssignClock(mClockAtomPosition);
4199  tmp.SetGlobalOptimStep(0.01);
4200  tmp.SetDerivStep(1e-4);
4201  this->AddPar(tmp);
4202  }
4203  {
4204  sprintf(buf,"RigidGroup%d_Q3",i);
4205  RefinablePar tmp(buf,&(p->mQuat.Q3()),-1,1.,
4206  gpRefParTypeScattConform,
4207  REFPAR_DERIV_STEP_ABSOLUTE,true,false,true,false,1.,1.);
4208  tmp.AssignClock(mClockAtomPosition);
4209  tmp.SetGlobalOptimStep(0.01);
4210  tmp.SetDerivStep(1e-4);
4211  this->AddPar(tmp);
4212  }
4213  #endif
4214  mClockRigidGroup.Click();
4215  if(updateDisplay) this->UpdateDisplay();
4216 }
4217 
4218 vector<RigidGroup*>::iterator Molecule::RemoveRigidGroup(const RigidGroup &g,const bool updateDisplay, const bool del)
4219 {
4220  vector<RigidGroup*>::iterator pos=find(mvRigidGroup.begin(),mvRigidGroup.end(),&g);
4221  if(pos==mvRigidGroup.end()) return pos;
4222  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
4223  // Remove the refinable parameters (even if del==False - used for python delayed deletion)
4224  // NOTE - this should only be done outside an optimization, since rigid group translationnal
4225  // and rotationnal parameters are resetted at the end of the optimization, and the atomic
4226  // parameters are directly the correct ones (thus deletion of the rigid group does not change
4227  // the final coordinates).
4228  this->RemovePar(&(this->GetPar(&((*pos)->mX))));
4229  this->RemovePar(&(this->GetPar(&((*pos)->mY))));
4230  this->RemovePar(&(this->GetPar(&((*pos)->mZ))));
4231  this->RemovePar(&(this->GetPar(&((*pos)->mQuat.Q1()))));
4232  this->RemovePar(&(this->GetPar(&((*pos)->mQuat.Q2()))));
4233  this->RemovePar(&(this->GetPar(&((*pos)->mQuat.Q3()))));
4234  #endif
4235  if(del) delete *pos;
4236  pos=mvRigidGroup.erase(pos);
4237  if(updateDisplay) this->UpdateDisplay();
4238  return pos;
4239 }
4240 
4241 MolAtom &Molecule::GetAtom(unsigned int i){return *mvpAtom[i];}
4242 
4243 const MolAtom &Molecule::GetAtom(unsigned int i)const{return *mvpAtom[i];}
4244 
4245 MolAtom &Molecule::GetAtom(const string &name){return **(this->FindAtom(name));}
4246 
4247 const MolAtom &Molecule::GetAtom(const string &name)const{return **(this->FindAtom(name));}
4248 
4249 void Molecule::OptimizeConformation(const long nbTrial,const REAL stopCost)
4250 {
4251  VFN_DEBUG_ENTRY("Molecule::OptimizeConformation()",5)
4252  MonteCarloObj globalOptObj(true);
4253  globalOptObj.AddRefinableObj(*this);
4254  globalOptObj.SetAlgorithmParallTempering(ANNEALING_EXPONENTIAL,10000.,1.,
4255  ANNEALING_EXPONENTIAL,10,.1);
4256 
4257  long nb=nbTrial;
4258  mIsSelfOptimizing=true;
4259  globalOptObj.Optimize(nb,false,stopCost);
4260  mIsSelfOptimizing=false;
4261  // Must rebuild Flip & Rotor group, in case they were tested with an absurd conformation
4262  mClockFlipGroup.Reset();
4263  mClockRotorGroup.Reset();
4264  VFN_DEBUG_EXIT("Molecule::OptimizeConformation()",5)
4265 }
4266 
4267 void Molecule::OptimizeConformationSteepestDescent(const REAL maxStep,const unsigned nbStep)
4268 {
4269  //cout<<"LLK="<<this->GetLogLikelihood()<<endl;
4270  for(unsigned i = 0; i < nbStep; ++i)
4271  {
4272  // Calc full gradient
4273  //Calculate & display gradient
4274  map<MolAtom*,XYZ> grad;
4275  for(vector<MolAtom*>::iterator pos=this->GetAtomList().begin();
4276  pos!=this->GetAtomList().end();++pos) grad[*pos]=XYZ(0,0,0);
4277 
4278  // :TODO: remove atoms that are in rigid groups ?
4279  for(vector<MolBond*>::iterator pos=this->GetBondList().begin();
4280  pos!=this->GetBondList().end();++pos) (*pos)->CalcGradient(grad);
4281 
4282  for(vector<MolBondAngle*>::iterator pos=this->GetBondAngleList().begin();
4283  pos!=this->GetBondAngleList().end();++pos) (*pos)->CalcGradient(grad);
4284 
4285  for(vector<MolDihedralAngle*>::iterator pos=this->GetDihedralAngleList().begin();
4286  pos!=this->GetDihedralAngleList().end();++pos) (*pos)->CalcGradient(grad);
4287 
4288  #if 0
4289  // Display gradient - for tests
4290  for(map<MolAtom*,XYZ>::const_iterator pos=grad.begin();pos!=grad.end();++pos)
4291  {
4292  char buf[100];
4293  sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)",
4294  pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z);
4295  cout<<buf<<endl;
4296  }
4297  #endif
4298  // Find maximum absolute value of gradient
4299  REAL f=0;
4300  for(map<MolAtom*,XYZ>::const_iterator pos=grad.begin();pos!=grad.end();++pos)
4301  {
4302  if(abs(pos->second.x)>f) f=abs(pos->second.x);
4303  if(abs(pos->second.y)>f) f=abs(pos->second.y);
4304  if(abs(pos->second.z)>f) f=abs(pos->second.z);
4305  }
4306  if(f>1e-6) f=maxStep/f;
4307  else break;//nothing to optimize ?
4308  // Average derivatives inside rigid groups
4309  //:TODO: still allow rotations of rigid groups ?
4310  //:TODO: Handle case when one atom belongs to several rigid groups...
4311  for(vector<RigidGroup *>::const_iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
4312  {
4313  if((*pos)->size()==0) continue; // Just in case...
4314  REAL dx=0,dy=0,dz=0;
4315  for(set<MolAtom *>::const_iterator at=(*pos)->begin();at!=(*pos)->end();++at)
4316  {
4317  dx+=(*at)->GetX();
4318  dy+=(*at)->GetY();
4319  dz+=(*at)->GetZ();
4320  }
4321  dx/=(*pos)->size();
4322  dy/=(*pos)->size();
4323  dz/=(*pos)->size();
4324  for(set<MolAtom *>::const_iterator at=(*pos)->begin();at!=(*pos)->end();++at)
4325  {
4326  grad[*at].x=dx;
4327  grad[*at].y=dy;
4328  grad[*at].z=dz;
4329  }
4330  }
4331  // Move according to max step to minimize LLK
4332  for(map<MolAtom*,XYZ>::const_iterator pos=grad.begin();pos!=grad.end();++pos)
4333  {
4334  pos->first->SetX(pos->first->GetX()-pos->second.x*f);
4335  pos->first->SetY(pos->first->GetY()-pos->second.y*f);
4336  pos->first->SetZ(pos->first->GetZ()-pos->second.z*f);
4337  }
4338  //this->RestraintStatus(cout);
4339  //cout<<"LLK="<<this->GetLogLikelihood()<<endl;
4340  }
4341 }
4342 
4343 void Molecule::MolecularDynamicsEvolve(map<MolAtom*,XYZ> &v0,const unsigned nbStep,const REAL dt,
4344  const vector<MolBond*> &vb,const vector<MolBondAngle*> &va,
4345  const vector<MolDihedralAngle*> &vd,
4346  map<RigidGroup*,std::pair<XYZ,XYZ> > &vr, REAL nrj0)
4347 {
4348  const vector<MolBond*> *pvb=&vb;
4349  const vector<MolBondAngle*> *pva=&va;
4350  const vector<MolDihedralAngle*> *pvd=&vd;
4351  map<RigidGroup*,std::pair<XYZ,XYZ> > *pvr=&vr;
4352  if((pvb->size()==0)&&(pva->size()==0)&&(pvd->size()==0))
4353  {
4354  pvb=&(this->GetBondList());
4355  pva=&(this->GetBondAngleList());
4356  pvd=&(this->GetDihedralAngleList());
4357  for(vector<RigidGroup *>::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
4358  (*pvr)[*pos]=make_pair(XYZ(0,0,0),XYZ(0,0,0));
4359  }
4360  const REAL m=500;// mass
4361  const REAL im=1./m;
4362 
4363  // Try to keep total energy constant
4364  REAL e_v,e_k,v_r=1.0;
4365  for(unsigned i = 0; i < nbStep; ++i)
4366  {
4367  // Calc full gradient
4368  map<MolAtom*,XYZ> grad;
4369  for(map<MolAtom*,XYZ>::iterator pos=v0.begin();pos!=v0.end();++pos) grad[pos->first]=XYZ(0,0,0);
4370 
4371  // :TODO: handle rigid groups ?
4372  e_v=0;
4373  for(vector<MolBond*>::const_iterator pos=pvb->begin();pos!=pvb->end();++pos)
4374  {
4375  (*pos)->CalcGradient(grad);
4376  e_v+=(*pos)->GetLogLikelihood(false,false);
4377  }
4378 
4379  for(vector<MolBondAngle*>::const_iterator pos=pva->begin();pos!=pva->end();++pos)
4380  {
4381  (*pos)->CalcGradient(grad);
4382  e_v+=(*pos)->GetLogLikelihood(false,false);
4383  }
4384 
4385  for(vector<MolDihedralAngle*>::const_iterator pos=pvd->begin();pos!=pvd->end();++pos)
4386  {
4387  (*pos)->CalcGradient(grad);
4388  e_v+=(*pos)->GetLogLikelihood(false,false);
4389  }
4390 
4391  //kinetic energy
4392  e_k=0;
4393  for(map<MolAtom*,XYZ>::const_iterator pos=v0.begin();pos!=v0.end();++pos)
4394  e_k += 0.5*m*(pos->second.x*pos->second.x + pos->second.y*pos->second.y + pos->second.z*pos->second.z);
4395 
4396  if(nrj0==0) nrj0=e_k+e_v;
4397  else
4398  {
4399  // Apply a coefficient to the speed to keep the overall energy constant
4400  const REAL de=e_k+e_v-nrj0;
4401  if(de<e_k) v_r=sqrt((e_k-de)/e_k);
4402  else v_r=0.0;
4403  }
4404 
4405  #if 0
4406  char buf[100];
4407  sprintf(buf,"(i) LLK + Ek = %10.3f + %10.3f =%10.3f (nrj0=%10.3f)",e_v,e_k,e_v+e_k,nrj0);
4408  cout<<buf<<endl;
4409 
4410  // Display gradient & speed - for tests
4411  for(map<MolAtom*,XYZ>::iterator pos=v0.begin();pos!=v0.end();++pos)
4412  {
4413  sprintf(buf,"%10s xyz= (%8.3f %8.3f %8.3f) v= (%8.3f %8.3f %8.3f) m*a= (%8.3f %8.3f %8.3f)",
4414  pos->first->GetName().c_str(),
4415  pos->first->GetX(),pos->first->GetY(),pos->first->GetZ(),
4416  v0[*pos].x ,v0[*pos].y ,v0[*pos].z,
4417  -grad[*pos].x*im,-grad[*pos].y*im,-grad[*pos].z*im);
4418  //cout<<buf<<endl;
4419  }
4420  //cout<<endl<<endl;
4421  #endif
4422  // Move according to max step to minimize LLK
4423  for(map<MolAtom*,XYZ>::const_iterator pos=v0.begin();pos!=v0.end();++pos)
4424  {
4425  const XYZ *pa=&(grad[pos->first]);
4426  pos->first->SetX(pos->first->GetX()+pos->second.x*dt*v_r-0.5*im*dt*dt*pa->x);
4427  pos->first->SetY(pos->first->GetY()+pos->second.y*dt*v_r-0.5*im*dt*dt*pa->y);
4428  pos->first->SetZ(pos->first->GetZ()+pos->second.z*dt*v_r-0.5*im*dt*dt*pa->z);
4429  }
4430  // Compute new speed
4431  for(map<MolAtom*,XYZ>::iterator pos=v0.begin();pos!=v0.end();++pos)
4432  {
4433  const XYZ *pa=&(grad[pos->first]);
4434  pos->second.x = v_r*pos->second.x - pa->x*dt*im;
4435  pos->second.y = v_r*pos->second.y - pa->y*dt*im;
4436  pos->second.z = v_r*pos->second.z - pa->z*dt*im;
4437  }
4438  }
4439 }
4440 
4441 const vector<MolAtom*>& Molecule::GetAtomList()const{return mvpAtom;}
4442 const vector<MolBond*>& Molecule::GetBondList()const{return mvpBond;}
4443 const vector<MolBondAngle*>& Molecule::GetBondAngleList()const{return mvpBondAngle;}
4444 const vector<MolDihedralAngle*>& Molecule::GetDihedralAngleList()const{return mvpDihedralAngle;}
4445 
4446 vector<MolAtom*>& Molecule::GetAtomList(){return mvpAtom;}
4447 vector<MolBond*>& Molecule::GetBondList(){return mvpBond;}
4448 vector<MolBondAngle*>& Molecule::GetBondAngleList(){return mvpBondAngle;}
4449 vector<MolDihedralAngle*>& Molecule::GetDihedralAngleList(){return mvpDihedralAngle;}
4450 
4451 list<StretchModeBondLength>& Molecule::GetStretchModeBondLengthList(){return mvStretchModeBondLength;}
4452 list<StretchModeBondAngle>& Molecule::GetStretchModeBondAngleList(){return mvStretchModeBondAngle;}
4453 list<StretchModeTorsion>& Molecule::GetStretchModeTorsionList(){return mvStretchModeTorsion;}
4454 
4455 const list<StretchModeBondLength>& Molecule::GetStretchModeBondLengthList()const{return mvStretchModeBondLength;}
4456 const list<StretchModeBondAngle>& Molecule::GetStretchModeBondAngleList()const{return mvStretchModeBondAngle;}
4457 const list<StretchModeTorsion>& Molecule::GetStretchModeTorsionList()const{return mvStretchModeTorsion;}
4458 
4459 const std::vector<RigidGroup*>& Molecule::GetRigidGroupList()const{return mvRigidGroup;}
4460 std::vector<RigidGroup*>& Molecule::GetRigidGroupList() {return mvRigidGroup;}
4461 
4462 void Molecule::RotateAtomGroup(const MolAtom &at1,const MolAtom &at2,
4463  const set<MolAtom *> &atoms, const REAL angle,
4464  const bool keepCenter)
4465 {
4466  const REAL vx=at2.X()-at1.X();
4467  const REAL vy=at2.Y()-at1.Y();
4468  const REAL vz=at2.Z()-at1.Z();
4469  this->RotateAtomGroup(at1,vx,vy,vz,atoms,angle,keepCenter);
4470 }
4471 void Molecule::RotateAtomGroup(const MolAtom &at,const REAL vx,const REAL vy,const REAL vz,
4472  const set<MolAtom *> &atoms, const REAL angle,
4473  const bool keepCenter)
4474 {
4475  TAU_PROFILE("Molecule::RotateAtomGroup(MolAtom&,vx,vy,vz,...)","void (...)",TAU_DEFAULT);
4476  if(atoms.size()==0) return;
4477  const REAL x0=at.X();
4478  const REAL y0=at.Y();
4479  const REAL z0=at.Z();
4480  // :KLUDGE: ? Refuse to do anything if vector is not well defined
4481  if((fabs(vx)+fabs(vy)+fabs(vz))<1e-6) return;
4482  REAL dx=0.,dy=0.,dz=0.;
4483  bool keepc=keepCenter;
4484  if(keepc)
4485  if( (this->GetPar(mXYZ.data() ).IsFixed())
4486  ||(this->GetPar(mXYZ.data()+1).IsFixed())
4487  ||(this->GetPar(mXYZ.data()+2).IsFixed())) keepc=false;
4488  #if 0
4489  const REAL ca=cos(angle),sa=sin(angle);
4490  const REAL ca1=1-ca;
4491  const REAL vnorm=1/sqrt(vx*vx+vy*vy+vz*vz);
4492  const REAL ux=vx*vnorm,uy=vy*vnorm,uz=vz*vnorm;
4493  const REAL m00=ca+ux*ux*ca1;// See http://en.wikipedia.org/wiki/Rotation_matrix
4494  const REAL m01=ux*uy*ca1-uz*sa;
4495  const REAL m02=ux*uz*ca1+uy*sa;
4496  const REAL m10=uy*ux*ca1+uz*sa; // :TODO: Check formulas !
4497  const REAL m11=ca+uy*uy*ca1;
4498  const REAL m12=uy*uz*ca1-ux*sa;
4499  const REAL m20=uz*ux*ca1-uy*sa;
4500  const REAL m21=uz*uy*ca1+ux*sa;
4501  const REAL m22=ca+uz*uz*ca1;
4502  for(set<MolAtom *>::const_iterator pos=atoms.begin();pos!=atoms.end();++pos)
4503  {
4504  if(keepc)
4505  {
4506  dx -= (*pos)->X();
4507  dy -= (*pos)->Y();
4508  dz -= (*pos)->Z();
4509  }
4510  const REAL x=(*pos)->X() - x0;
4511  const REAL y=(*pos)->Y() - y0;
4512  const REAL z=(*pos)->Z() - z0;
4513 
4514  (*pos)->X() = m00*x+m01*y+m02*z+x0;
4515  (*pos)->Y() = m10*x+m11*y+m12*z+y0;
4516  (*pos)->Z() = m20*x+m21*y+m22*z+z0;
4517  if(keepc)
4518  {
4519  dx += (*pos)->X();
4520  dy += (*pos)->Y();
4521  dz += (*pos)->Z();
4522  }
4523  }
4524  #else
4525  const Quaternion quat=Quaternion::RotationQuaternion(angle,vx,vy,vz);
4526  for(set<MolAtom *>::const_iterator pos=atoms.begin();pos!=atoms.end();++pos)
4527  {
4528  if(keepc)
4529  {
4530  dx -= (*pos)->X();
4531  dy -= (*pos)->Y();
4532  dz -= (*pos)->Z();
4533  }
4534  (*pos)->X() -= x0;
4535  (*pos)->Y() -= y0;
4536  (*pos)->Z() -= z0;
4537  quat.RotateVector((*pos)->X(),(*pos)->Y(),(*pos)->Z());
4538  (*pos)->X() += x0;
4539  (*pos)->Y() += y0;
4540  (*pos)->Z() += z0;
4541  if(keepc)
4542  {
4543  dx += (*pos)->X();
4544  dy += (*pos)->Y();
4545  dz += (*pos)->Z();
4546  }
4547  }
4548  #endif
4549  // (dx,dy,dz) = vector of the translation of the center of the molecule due to the rotation
4550  if(keepc)
4551  {
4552  dx /= (REAL)(this->GetNbComponent());
4553  dy /= (REAL)(this->GetNbComponent());
4554  dz /= (REAL)(this->GetNbComponent());
4555  mQuat.RotateVector(dx,dy,dz);
4556  this->GetCrystal().OrthonormalToFractionalCoords(dx,dy,dz);
4557  mXYZ(0) += dx;
4558  mXYZ(1) += dy;
4559  mXYZ(2) += dz;
4560  }
4561  mClockAtomPosition.Click();
4563 }
4564 void Molecule::TranslateAtomGroup(const set<MolAtom *> &atoms,
4565  const REAL dx,const REAL dy,const REAL dz,
4566  const bool keepCenter)
4567 {
4568  for(set<MolAtom *>::const_iterator pos=atoms.begin();pos!=atoms.end();++pos)
4569  {
4570  (*pos)->X() += dx;
4571  (*pos)->Y() += dy;
4572  (*pos)->Z() += dz;
4573  }
4574  bool keepc=keepCenter;
4575  if(keepc)
4576  if( (this->GetPar(mXYZ.data() ).IsFixed())
4577  ||(this->GetPar(mXYZ.data()+1).IsFixed())
4578  ||(this->GetPar(mXYZ.data()+2).IsFixed())) keepc=false;
4579  if(keepc)
4580  {
4581  const REAL r= (REAL)(atoms.size())/(REAL)(this->GetNbComponent());
4582  REAL dxc=dx*r,dyc=dy*r,dzc=dz*r;
4583  this->GetCrystal().OrthonormalToFractionalCoords(dxc,dyc,dzc);
4584  mXYZ(0) += dxc;
4585  mXYZ(1) += dyc;
4586  mXYZ(2) += dzc;
4587  }
4588  mClockAtomPosition.Click();
4590 }
4591 void Molecule::RestraintExport(ostream &os)const
4592 {
4593  VFN_DEBUG_ENTRY("Molecule::RestraintExport()",5)
4594  os<<"BondName, IdealLength, Length, log(likelihood)"<<endl;
4595  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
4596  os <<(*pos)->GetName()
4597  <<", "<<(*pos)->GetLength0()
4598  <<", "<<(*pos)->GetLength()
4599  <<", "<<(*pos)->GetLogLikelihood()<<endl;
4600  os<<"BondAngle, IdealAngle, Angle, log(likelihood)"<<endl;
4601  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();
4602  pos!=mvpBondAngle.end();++pos)
4603  os <<(*pos)->GetName()
4604  <<", "<<(*pos)->Angle0()*180/M_PI
4605  <<", "<<(*pos)->GetAngle()*180/M_PI
4606  <<", "<<(*pos)->GetLogLikelihood()<<endl;
4607  os<<"DihedralAngle, IdealAngle, Angle, log(likelihood)"<<endl;
4608  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();
4609  pos!=mvpDihedralAngle.end();++pos)
4610  os <<(*pos)->GetName()
4611  <<", "<<(*pos)->Angle0()*180/M_PI
4612  <<", "<<(*pos)->GetAngle()*180/M_PI
4613  <<", "<<(*pos)->GetLogLikelihood()<<endl;
4614  VFN_DEBUG_EXIT("Molecule::RestraintExport()",5)
4615 }
4616 void Molecule::RestraintStatus(ostream &os)const
4617 {
4618  VFN_DEBUG_ENTRY("Molecule::RestraintStatus()",5)
4619  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
4620  cout <<"Bond "<<(*pos)->GetName()
4621  <<", IdealLength="<<(*pos)->GetLength0()
4622  <<", Length="<<(*pos)->GetLength()
4623  <<", log(likelihood)="<<(*pos)->GetLogLikelihood()<<endl;
4624  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();
4625  pos!=mvpBondAngle.end();++pos)
4626  cout <<"Bond Angle "<<(*pos)->GetName()
4627  <<", IdealAngle="<<(*pos)->Angle0()*180/M_PI
4628  <<", Angle="<<(*pos)->GetAngle()*180/M_PI
4629  <<", log(likelihood)="<<(*pos)->GetLogLikelihood()<<endl;
4630  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();
4631  pos!=mvpDihedralAngle.end();++pos)
4632  cout <<"Dihedral Angle "<<(*pos)->GetName()
4633  <<", IdealAngle="<<(*pos)->Angle0()*180/M_PI
4634  <<", Angle="<<(*pos)->GetAngle()*180/M_PI
4635  <<", log(likelihood)="<<(*pos)->GetLogLikelihood()<<endl;
4636  VFN_DEBUG_EXIT("Molecule::RestraintStatus()",5)
4637 }
4638 
4639 const map<MolAtom *,set<MolAtom *> > &Molecule::GetConnectivityTable()
4640 {
4641  this->BuildConnectivityTable();
4642  return mConnectivityTable;
4643 }
4644 
4646 const RefinableObjClock& Molecule::GetBondListClock()const{return mClockBondList;}
4647 
4649 const RefinableObjClock& Molecule::GetAtomPositionClock()const{return mClockAtomPosition;}
4650 
4651 const RefinableObjClock& Molecule::GetAtomScattPowClock()const { return mClockAtomScattPow;}
4652  RefinableObjClock& Molecule::GetAtomScattPowClock() { return mClockAtomScattPow;}
4653 
4655 const RefinableObjClock& Molecule::GetRigidGroupClock()const{return mClockRigidGroup;}
4656 
4658 {
4659  this->BuildConnectivityTable();
4660  for(vector<MolBond*>::iterator bond=mvpBond.begin();bond!=mvpBond.end();++bond)
4661  {
4662  MolAtom* at2=&((*bond)->GetAtom1());
4663  MolAtom* at3=&((*bond)->GetAtom2());
4664  for(set<MolAtom *>::const_iterator c2=mConnectivityTable[at2].begin();
4665  c2!=mConnectivityTable[at2].end();++c2)
4666  {
4667  //MolAtom* at1=mvpAtom[*c2];
4668  if(*c2==at3) continue;
4669  if(GetBondAngle(**c2,*at2,*at3)<(10 *DEG2RAD)) continue;
4670  if(GetBondAngle(**c2,*at2,*at3)>(180*DEG2RAD)) continue;
4671  for(set<MolAtom*>::const_iterator c3=mConnectivityTable[at3].begin();
4672  c3!=mConnectivityTable[at3].end();++c3)
4673  {
4674  //MolAtom* at4=mvpAtom[*c3];
4675  if((*c3==at2)||(*c3==*c2)) continue;
4676  if(GetBondAngle(*at2,*at3,**c3)<(10 *DEG2RAD)) continue;
4677  if(GetBondAngle(*at2,*at3,**c3)>(180*DEG2RAD)) continue;
4678  if(this->FindDihedralAngle(**c2,*at2,*at3,**c3)==mvpDihedralAngle.end())
4679  {
4680  const REAL dihed=GetDihedralAngle(**c2,*at2,*at3,**c3);
4681  this->AddDihedralAngle(**c2,*at2,*at3,**c3,dihed,.01,.05,false);
4682  }
4683  }
4684  }
4685  }
4686  this->UpdateDisplay();
4687 }
4688 #if 0
4692 static const REAL svGaussianIntX[51]
4693  ={0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2,
4694  1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3,
4695  2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2, 3.3, 3.4,
4696  3.5, 3.6, 3.7, 3.8, 3.9, 4. , 4.1, 4.2, 4.3, 4.4, 4.5,
4697  4.6, 4.7, 4.8, 4.9, 5. };
4701 static const REAL svGaussianIntY[51]
4702  ={0.00000000e+00, 1.00285768e-01, 2.02498389e-01, 3.08782899e-01,
4703  4.21537858e-01, 5.43577677e-01, 6.78339751e-01, 8.30161516e-01,
4704  1.00466359e+00, 1.20929269e+00, 1.45410564e+00, 1.75292008e+00,
4705  2.12502806e+00, 2.59778353e+00, 3.21056320e+00, 4.02091257e+00,
4706  5.11421527e+00, 6.61911896e+00, 8.73249677e+00, 1.17604260e+01,
4707  1.61864569e+01, 2.27870547e+01, 3.28297946e+01, 4.84189023e+01,
4708  7.31071567e+01, 1.12996748e+02, 1.78751757e+02, 2.89337246e+02,
4709  4.79080996e+02, 8.11232960e+02, 1.40443983e+03, 2.48531490e+03,
4710  4.49461494e+03, 8.30539633e+03, 1.56790580e+04, 3.02354014e+04,
4711  5.95525189e+04, 1.19793234e+05, 2.46080284e+05, 5.16182008e+05,
4712  1.10556243e+06, 2.41765307e+06, 5.39775929e+06, 1.23033271e+07,
4713  2.86288375e+07, 6.80050408e+07, 1.64899866e+08, 4.08157783e+08,
4714  1.03122228e+09, 2.65938808e+09, 7.00012860e+09};
4718 static const CubicSpline sInvGaussianInt(svGaussianIntY,svGaussianIntX,51);
4719 
4720 REAL FlatGaussianProba(const REAL x, const REAL sigma, const REAL delta)
4721 {
4722  if(abs(x)<delta) return 1.0;
4723  const REAL z=(abs(x)-delta)/sigma;
4724  return exp(-z*z);
4725 }
4726 
4727 REAL FlatGaussianIntegral(const REAL x1,const REAL x2, const REAL sigma, const REAL delta)
4728 {
4729  static const REAL SPI2=0.88622692545275794;//sqrt(pi)/2
4730  if((x1<=-delta)&&(x2<=-delta)) return SPI2*sigma*(erf((x2+delta)/sigma)-erf((x1+delta)/sigma));
4731  if((x1<=-delta)&&(x2<= delta)) return (x2+delta)-SPI2*sigma*erf((x1+delta)/sigma);
4732  if(x1<=-delta) return 2*delta+SPI2*sigma*(erf((x2-delta)/sigma)-erf((x1+delta)/sigma));
4733  if((x1<= delta)&&(x2<= delta)) return x2-x1;
4734  if(x1<= delta) return SPI2*sigma*erf((x2-delta)/sigma)+(delta-x1);
4735  return SPI2*sigma*(erf((x2-delta)/sigma)-erf((x1-delta)/sigma));
4736 }
4737 #endif
4738 REAL FlatLorentzianProba(const REAL x, const REAL sigma, const REAL delta)
4739 {
4740  if(abs(x)<delta) return 1.0;
4741  const REAL z=(abs(x)-delta)/sigma;
4742  return 1/(1+z*z);
4743 }
4744 
4745 REAL FlatLorentzianIntegral(const REAL x1,const REAL x2, const REAL sigma, const REAL delta)
4746 {
4747  if((x1<=-delta)&&(x2<=-delta)) return atan((x2+delta)/sigma)-atan((x1+delta)/sigma);
4748  if((x1<=-delta)&&(x2<= delta)) return (x2+delta)-atan((x1+delta)/sigma);
4749  if(x1<=-delta) return 2*delta+atan((x2-delta)/sigma)-atan((x1+delta)/sigma);
4750  if((x1<= delta)&&(x2<= delta)) return x2-x1;
4751  if(x1<= delta) return atan((x2-delta)/sigma)+(delta-x1);
4752  return atan((x2-delta)/sigma)-atan((x1-delta)/sigma);
4753 }
4754 
4761 REAL LorentzianBiasedRandomMove(const REAL x0,const REAL sigma,const REAL delta,const REAL amplitude)
4762 {
4763  //static const REAL SPI2=0.88622692545275794;//sqrt(pi)/2
4764  REAL r=(REAL)rand()/(REAL)RAND_MAX;
4765  if(sigma<1e-6)
4766  {
4767  REAL x=x0+amplitude*(2*r-1.0);
4768  if(x> delta)x= delta;
4769  if(x<-delta)x=-delta;
4770  return x;
4771  }
4772  // Compute xmin and xmax around x0 so that:
4773  // (x0-xmin)/(xmax-x0)=Integral[xmin->x0](P(x)dx)/Integral[x0->xmax](P(x)dx)
4774  REAL xmin;
4775  REAL xmax;
4776  #if 1
4777  {
4778  REAL Pmax,Pmin;
4779  xmin=x0-amplitude;
4780  xmax=x0+amplitude;
4781  Pmin=FlatLorentzianProba((x0+xmin)/2,sigma,delta);
4782  Pmax=FlatLorentzianProba((x0+xmax)/2,sigma,delta);
4783  //Pmin=FlatLorentzianIntegral(xmin,x0,sigma,delta);
4784  //Pmax=FlatLorentzianIntegral(x0,xmax,sigma,delta);
4785  if(Pmin>Pmax)
4786  {
4787  for(int i=0;i<5;i++)
4788  {
4789  const REAL r=Pmax/Pmin;
4790  xmax=x0+r*amplitude;
4791  Pmax=FlatLorentzianProba((x0+xmax)/2,sigma,delta);
4792  //Pmax=FlatLorentzianIntegral(x0,xmax,sigma,delta);
4793  }
4794  }
4795  else
4796  {
4797  for(int i=0;i<5;i++)
4798  {
4799  const REAL r=Pmin/Pmax;
4800  xmin=x0-r*amplitude;
4801  Pmin=FlatLorentzianProba((x0+xmin)/2,sigma,delta);
4802  //Pmin=FlatLorentzianIntegral(xmin,x0,sigma,delta);
4803  }
4804  }
4805  }
4806  #else
4807  if(abs(x0)<=delta)
4808  {
4809  xmin=x0-amplitude;
4810  xmax=x0+amplitude;
4811  }
4812  else
4813  {
4814  REAL d=(abs(x0)-delta)/sigma;
4815  d=2*d*exp(-d*d);
4816  d=(1-amplitude*d/2)/(1+amplitude*d/2);//d<1
4817  if(x0>0)
4818  {
4819  xmin=x0-amplitude*2/(1+d);
4820  xmax=x0+amplitude*2*d/(1+d);
4821  }
4822  else
4823  {
4824  xmax=x0+amplitude*2/(1+d);
4825  xmin=x0-amplitude*2*d/(1+d);
4826  }
4827  }
4828  #endif
4829  //xmin=x0-amplitude;
4830  //xmax=x0+amplitude;
4831  //Now get the biased move...
4832  if(xmax<=-delta)
4833  {
4834  REAL ymin=(abs(xmin)-delta)/sigma;
4835  ymin=atan(ymin);
4836  REAL ymax=(abs(xmax)-delta)/sigma;
4837  ymax=atan(ymax);
4838  const REAL y=ymin+(ymax-ymin)*r;
4839  return -tan(y)*sigma-delta;
4840  }
4841  if(xmin<=-delta)
4842  {
4843  if(xmax<=delta)
4844  {
4845  //probability of being in [xmin;-delta] rather than [-delta;xmax]
4846  REAL p0=atan((abs(xmin)-delta)/sigma)*sigma;
4847  REAL p1=xmax+delta;
4848  const REAL n=p0+p1;
4849  if(r<p0/n)
4850  {
4851  REAL ymin=(abs(xmin)-delta)/sigma;
4852  ymin=atan(ymin);
4853  const REAL y=ymin*(REAL)rand()/(REAL)RAND_MAX;
4854  return -delta-tan(y)*sigma;
4855  }
4856  else
4857  {
4858  return -delta+(REAL)rand()/(REAL)RAND_MAX*(xmax+delta);
4859  }
4860  }
4861  else //xmax>delta && xmin <= -delta
4862  {
4863  REAL p0=atan((abs(xmin)-delta)/sigma)*sigma;//probability of being in [xmin;-delta]
4864  REAL p1=2*delta;//probability of being in [-delta;delta]
4865  REAL p2=atan((xmax-delta)/sigma)*sigma;//probability of being in [delta;xmax]
4866  const REAL n=p0+p1+p2;
4867  if(r<(p0/n))
4868  {
4869  REAL ymin=(abs(xmin)-delta)/sigma;
4870  ymin=atan(ymin);//exp(ymin*ymin);
4871  const REAL y=ymin*(REAL)rand()/(REAL)RAND_MAX;
4872  const REAL x=-delta-tan(y)*sigma;
4873  return x;
4874  }
4875  if(r<(p0+p1)/n)
4876  {
4877  const REAL x=-delta+(REAL)rand()/(REAL)RAND_MAX*2*delta;
4878  return x;
4879  }
4880 
4881  REAL ymax=(xmax-delta)/sigma;
4882  ymax=atan(ymax);
4883  const REAL y=ymax*(REAL)rand()/(REAL)RAND_MAX;
4884  const REAL x=delta+tan(y)*sigma;
4885  return x;
4886  }
4887  }
4888  if(xmin<delta)
4889  {
4890  if(xmax<delta)
4891  {
4892  return xmin+r*(xmax-xmin);
4893  }
4894 
4895  const REAL p0=delta-xmin;//relative probability of being in [xmin;delta]
4896  const REAL p1=atan((xmax-delta)/sigma)*sigma;// proba in[delta;xmax]
4897  if(r<(p0/(p0+p1)))
4898  {
4899  return xmin+(REAL)rand()/(REAL)RAND_MAX*(delta-xmin);
4900  }
4901 
4902  REAL ymax=(xmax-delta)/sigma;
4903  ymax=atan(ymax);
4904  const REAL y=ymax*(REAL)rand()/(REAL)RAND_MAX;
4905  return delta+tan(y)*sigma;
4906  }
4907  //xmin>delta
4908  REAL ymin=(xmin-delta)/sigma;
4909  ymin=atan(ymin);
4910  REAL ymax=(xmax-delta)/sigma;
4911  ymax=atan(ymax);
4912  const REAL y=ymin+(ymax-ymin)*r;
4913  return tan(y)*sigma+delta;
4914 }
4915 
4916 void TestLorentzianBiasedRandomMove()
4917 {
4918  srand(time(NULL));
4919  REAL x=0,sigma=0.1,delta=0.5,amplitude=0.05;
4920  ofstream f;
4921  f.open("test.dat");
4922  for(long i=0;i<400000;i++)
4923  {
4924  f<<x<<endl;
4925  x=LorentzianBiasedRandomMove(x,sigma,delta,amplitude);
4926  }
4927  f.close();
4928  exit(0);
4929  //#Histogram in Python
4930  //from scipy import *
4931  //
4932  //def histogram(y,n=100):
4933  // ymin=min(y)
4934  // ymax=max(y)
4935  // step=(ymax-ymin)/n
4936  // hx=arange(ymin,ymax+step,step)
4937  // hy=arange(ymin,ymax+step,step)
4938  // for i in xrange(n-1):
4939  // hy[i]=sum((y>hx[i])*(y<(hx[i]+step)))
4940  // return hx,hy
4941  //
4942  //
4943  //f=open("test.dat",'r')
4944  //ll=f.readlines()
4945  //f.close()
4946  //y=zeros(len(ll),Float)
4947  //for i in xrange(len(ll)):
4948  // y[i]=float(ll[i])
4949  //
4950  //hx,hy=histogram(y)
4951  //gplt.plot(hx,hy)
4952 }
4953 
4954 REAL Molecule::BondLengthRandomChange(const StretchModeBondLength& mode, const REAL amplitude,
4955  const bool respectRestraint)
4956 {
4957  REAL dx=mode.mpAtom1->GetX()-mode.mpAtom0->GetX();
4958  REAL dy=mode.mpAtom1->GetY()-mode.mpAtom0->GetY();
4959  REAL dz=mode.mpAtom1->GetZ()-mode.mpAtom0->GetZ();
4960  const REAL l=sqrt(dx*dx+dy*dy+dz*dz+1e-7);
4961  REAL change=0.0;
4962  if(l<1e-6) return change;// :KLUDGE:
4963  if(respectRestraint && mode.mpBond!=0)
4964  {
4965  const REAL d0=l-mode.mpBond->GetLength0();
4966  const REAL sigma=mode.mpBond->GetLengthSigma();
4967  const REAL delta=mode.mpBond->GetLengthDelta();
4968  const REAL max=delta+sigma*5.0;
4969  if(sigma<1e-6)
4970  {
4971  REAL d1=d0+(REAL)(2*rand()-RAND_MAX)/(REAL)RAND_MAX*amplitude*0.1;
4972  if(d1> delta)d1= delta;
4973  if(d1<-delta)d1=-delta;
4974  change=d1-d0;
4975  }
4976  else change=LorentzianBiasedRandomMove(d0,sigma,delta,amplitude*0.1)-d0;
4977  if((d0+change)>max) change=max-d0;
4978  else if((d0+change)<(-max)) change=-max-d0;
4979  #if 0
4980  if(rand()%10000==0)
4981  {
4982  cout<<"BOND LENGTH change("<<change<<"):"
4983  <<mode.mpAtom0->GetName()<<"-"
4984  <<mode.mpAtom1->GetName()
4985  <<"(Restraint="<<l-d0<<"s"<<sigma<<"d"<<delta<<"):"
4986  <<l<<"->"<<l+change<<endl;
4987  }
4988  #endif
4989  }
4990  else change=(2.*(REAL)rand()-(REAL)RAND_MAX)/(REAL)RAND_MAX*amplitude*0.1;
4991  dx*=change/l;
4992  dy*=change/l;
4993  dz*=change/l;
4994  this->TranslateAtomGroup(mode.mvTranslatedAtomList,dx,dy,dz,true);
4995  return change;
4996 }
4997 
4998 REAL Molecule::BondAngleRandomChange(const StretchModeBondAngle& mode, const REAL amplitude,
4999  const bool respectRestraint)
5000 {
5001  REAL dx10=mode.mpAtom0->GetX()-mode.mpAtom1->GetX();
5002  REAL dy10=mode.mpAtom0->GetY()-mode.mpAtom1->GetY();
5003  REAL dz10=mode.mpAtom0->GetZ()-mode.mpAtom1->GetZ();
5004  REAL dx12=mode.mpAtom2->GetX()-mode.mpAtom1->GetX();
5005  REAL dy12=mode.mpAtom2->GetY()-mode.mpAtom1->GetY();
5006  REAL dz12=mode.mpAtom2->GetZ()-mode.mpAtom1->GetZ();
5007 
5008  const REAL vx=dy10*dz12-dz10*dy12;
5009  const REAL vy=dz10*dx12-dx10*dz12;
5010  const REAL vz=dx10*dy12-dy10*dx12;
5011 
5012  REAL change=0.0;
5013  if((abs(vx)+abs(vy)+abs(vz))<1e-6) return change;// :KLUDGE:
5014  REAL angle0;
5015  if(respectRestraint && mode.mpBondAngle!=0)
5016  {
5017  const REAL norm= sqrt( (dx10*dx10+dy10*dy10+dz10*dz10)*(dx12*dx12+dy12*dy12+dz12*dz12)+1e-6);
5018  angle0=(dx10*dx12+dy10*dy12+dz10*dz12)/norm;
5019  if(angle0>=1) angle0=0;
5020  else
5021  {
5022  if(angle0<=-1) angle0=M_PI;
5023  else angle0= acos(angle0);
5024  }
5025 
5026  const REAL a0=angle0-mode.mpBondAngle->GetAngle0();
5027  const REAL sigma=mode.mpBondAngle->GetAngleSigma();
5028  const REAL delta=mode.mpBondAngle->GetAngleDelta();
5029  if(sigma<1e-6)
5030  {
5031  REAL a1=a0+(REAL)(2*rand()-RAND_MAX)/(REAL)RAND_MAX*amplitude*mode.mBaseAmplitude;
5032  if(a1> delta)a1= delta;
5033  if(a1<-delta)a1=-delta;
5034  change=a1-a0;
5035  }
5036  else change=LorentzianBiasedRandomMove(a0,sigma,delta,amplitude*mode.mBaseAmplitude)-a0;
5037  if((a0+change)>(delta+sigma*5.0)) change= delta+sigma*5.0-a0;
5038  else if((a0+change)<(-delta-sigma*5.0)) change=-delta-sigma*5.0-a0;
5039  #if 0
5040  if(rand()%1==0)
5041  {
5042  cout<<"ANGLE change("<<change*RAD2DEG<<"):"
5043  <<mode.mpAtom0->GetName()<<"-"
5044  <<mode.mpAtom1->GetName()<<"-"
5045  <<mode.mpAtom2->GetName()
5046  <<"(Restraint="<<(angle0-a0)*RAD2DEG<<"s"<<sigma*RAD2DEG<<"d"<<delta*RAD2DEG<<"):"
5047  <<angle0*RAD2DEG<<"->"<<(angle0+change)*RAD2DEG<<endl;
5048  }
5049  #endif
5050  }
5051  else change=(2.*(REAL)rand()-(REAL)RAND_MAX)/(REAL)RAND_MAX*mode.mBaseAmplitude*amplitude;
5052  this->RotateAtomGroup(*(mode.mpAtom1),vx,vy,vz,mode.mvRotatedAtomList,change,true);
5053  return change;
5054 }
5055 REAL Molecule::DihedralAngleRandomChange(const StretchModeTorsion& mode, const REAL amplitude,
5056  const bool respectRestraint)
5057 {
5058  const REAL dx=mode.mpAtom2->GetX()-mode.mpAtom1->GetX();
5059  const REAL dy=mode.mpAtom2->GetY()-mode.mpAtom1->GetY();
5060  const REAL dz=mode.mpAtom2->GetZ()-mode.mpAtom1->GetZ();
5061  REAL change=0.0;
5062  if((abs(dx)+abs(dy)+abs(dz))<1e-6) return change;// :KLUDGE:
5063  if(respectRestraint && mode.mpDihedralAngle!=0)
5064  {
5065  const REAL angle0=mode.mpDihedralAngle->GetAngle();
5066  const REAL a0=angle0-mode.mpDihedralAngle->GetAngle0();
5067  const REAL sigma=mode.mpDihedralAngle->GetAngleSigma();
5068  const REAL delta=mode.mpDihedralAngle->GetAngleDelta();
5069  if(sigma<1e-6)
5070  {
5071  REAL a1=a0+(REAL)(2*rand()-RAND_MAX)/(REAL)RAND_MAX*amplitude*mode.mBaseAmplitude;
5072  if(a1> delta)a1= delta;
5073  if(a1<-delta)a1=-delta;
5074  change=a1-a0;
5075  }
5076  else change=LorentzianBiasedRandomMove(a0,sigma,delta,amplitude*mode.mBaseAmplitude)-a0;
5077  if((a0+change)>(delta+sigma*5.0)) change= delta+sigma*5.0-a0;
5078  else if((a0+change)<(-delta-sigma*5.0)) change=-delta-sigma*5.0-a0;
5079  #if 0
5080  if(rand()%1==0)
5081  {
5082  cout<<"TORSION change ("
5083  <<mode.mpAtom1->GetName()<<"-"<<mode.mpAtom2->GetName()<<"):"<<endl
5084  <<" initial angle="<<angle0*RAD2DEG
5085  <<" (Restraint("<<mode.mpDihedralAngle->GetName()<<")="
5086  <<(angle0-a0)*RAD2DEG<<"s"<<sigma*RAD2DEG<<"d"<<delta*RAD2DEG<<"):"
5087  <<endl<<" New angle:"<<(angle0+change)*RAD2DEG<<", change="<<change*RAD2DEG<<endl;
5088  }
5089  #endif
5090  }
5091  else change=(REAL)(2.*rand()-RAND_MAX)/(REAL)RAND_MAX*mode.mBaseAmplitude*amplitude;
5092  this->RotateAtomGroup(*(mode.mpAtom1),*(mode.mpAtom2),mode.mvRotatedAtomList,change,true);
5093  return change;
5094 }
5095 
5097 {
5098  return mpCenterAtom;
5099 }
5100 
5102 {
5103  mpCenterAtom=&at;
5104  mClockAtomPosition.Click();
5105  this->UpdateDisplay();
5106 }
5107 
5108 void BuildZMatrixRecursive(long &z,const long curr,
5109  const vector<MolAtom*> &vpAtom,
5110  const map<MolAtom *, set<MolAtom *> > &connT,
5111  vector<MolZAtom> &zmatrix,
5112  const map<const MolAtom*,long> &vIndex,
5113  vector<long> &vZIndex,
5114  vector<long> &vrZIndex)
5115 {
5116  zmatrix[z].mpPow=&(vpAtom[curr]->GetScatteringPower());
5117  vZIndex[curr]=z;
5118  vrZIndex[z]=curr;
5119  // Get the list of connected atoms and sort them
5120  map<MolAtom *, set<MolAtom *> >::const_iterator pConn=connT.find(vpAtom[curr]);
5121  const long nc=pConn->second.size();
5122  vector<long> conn(nc);
5123  vector<long> zconn(nc);
5124  vector<long>::iterator pos=conn.begin();
5125  vector<long>::iterator zpos=zconn.begin();
5126  for(set<MolAtom *>::const_iterator pos1=pConn->second.begin();pos1!=pConn->second.end();++pos1)
5127  {
5128  *pos = vIndex.find(*pos1)->second;
5129  *zpos = vZIndex[*pos];
5130  cout<<(*pos1)->GetName()<<"("<<*pos<<","<<*zpos<<")"<<endl;
5131  zpos++;pos++;
5132  }
5133  sort(conn.begin(),conn.end());
5134  sort(zconn.begin(),zconn.end());
5135  if(z>0)
5136  {
5137  // Use the most recent atom in the z-matrix
5138  const long b=zconn[nc-1];
5139  zmatrix[z].mBondAtom=b;
5140  zmatrix[z].mBondLength=GetBondLength(*vpAtom[vrZIndex[b]],*vpAtom[curr]);
5141  if(z>1)
5142  {
5143  const long a=zmatrix[b].mBondAtom;
5144  zmatrix[z].mBondAngleAtom=a;
5145  zmatrix[z].mBondAngle=GetBondAngle(*vpAtom[vrZIndex[a]],*vpAtom[vrZIndex[b]],*vpAtom[curr]);
5146  if(z>2)
5147  {
5148  const long d=zmatrix[b].mBondAngleAtom;
5149  zmatrix[z].mDihedralAtom=d;
5150  zmatrix[z].mDihedralAngle=fmod(GetDihedralAngle(*vpAtom[vrZIndex[d]],*vpAtom[vrZIndex[a]],
5151  *vpAtom[vrZIndex[b]],*vpAtom[curr])+2*M_PI,
5152  2*M_PI);
5153  }
5154  else
5155  {
5156  zmatrix[z].mDihedralAtom=0;
5157  zmatrix[z].mDihedralAngle=0;
5158  }
5159  }
5160  else
5161  {
5162  zmatrix[z].mBondAngleAtom=0;
5163  zmatrix[z].mBondAngle=0;
5164  }
5165  }
5166  else
5167  {
5168  zmatrix[z].mBondAtom=0;
5169  zmatrix[z].mBondLength=0;
5170  }
5171  z++;
5172  // Continue filling up the zmatrix, beginning from thz first atoms not already in the zmatrix
5173  for(pos=conn.begin();pos!=conn.end();++pos)
5174  {
5175  if(*pos!=-1)
5176  {
5177  if(vZIndex[*pos]==-1)
5178  BuildZMatrixRecursive(z,*pos,vpAtom,connT,zmatrix,vIndex,vZIndex,vrZIndex);
5179  }
5180  }
5181 }
5182 
5183 const vector<MolZAtom>& Molecule::AsZMatrix(const bool keeporder)const
5184 {
5185  this->BuildConnectivityTable();
5186  const long n=mvpAtom.size();
5187  // index of the atoms in the list
5188  map<const MolAtom*,long> vIndex;
5189  {
5190  long i=0;
5191  for(vector<MolAtom*>::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
5192  vIndex[*pos]=i++;
5193  }
5194  mAsZMatrix.resize(n);
5195  if(keeporder)
5196  {
5197  for(long i=0;i<n;++i)
5198  {
5199  mAsZMatrix[i].mpPow=&(mvpAtom[i]->GetScatteringPower());
5200  if(i>0)
5201  {
5202  const set<MolAtom *> *pConn=&(mConnectivityTable.find(mvpAtom[i])->second);
5203  // Find a connected atom already in the mAsZMatrix, prefereably the most recent
5204  long b=-1;
5205  for(set<MolAtom *>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5206  if((vIndex[*pos]<i)&&(vIndex[*pos]>b)) b=vIndex[*pos];
5207  // Did not find a connected atom already in the z-matrix ? Take the last one
5208  if(b==-1) b=i-1;
5209  mAsZMatrix[i].mBondAtom=b;
5210  mAsZMatrix[i].mBondLength=GetBondLength(*mvpAtom[b],*mvpAtom[i]);
5211  if(i>1)
5212  {
5213  const long a= (b==0)?1 : mAsZMatrix[b].mBondAtom;
5214  mAsZMatrix[i].mBondAngleAtom=a;
5215  mAsZMatrix[i].mBondAngle=GetBondAngle(*mvpAtom[a],*mvpAtom[b],*mvpAtom[i]);
5216  if(i>2)
5217  {
5218  long d= mAsZMatrix[a].mBondAtom;
5219  if(d==b)
5220  {// Dihedral atom is already bond atom, find another connected to angle atom
5221  d=-1;
5222  const set<MolAtom *> *pConn=&(mConnectivityTable.find(mvpAtom[a])->second);
5223  // Find a connected atom already in the mAsZMatrix, prefereably the most recent
5224  for(set<MolAtom *>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5225  if((vIndex[*pos]<i) && (vIndex[*pos]!=b) && (vIndex[*pos]>d)) d=vIndex[*pos];
5226  }
5227  if(d==-1)
5228  {// Can't find an angle connected to angle atom, so find another with bond atom
5229  const set<MolAtom *> *pConn=&(mConnectivityTable.find(mvpAtom[b])->second);
5230  // Find a connected atom already in the mAsZMatrix, prefereably the most recent
5231  for(set<MolAtom *>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5232  if((vIndex[*pos]<i) && (vIndex[*pos]!=a) && (vIndex[*pos]>d)) d=vIndex[*pos];
5233  }
5234  if(d==-1)
5235  {// Maybe another connected to this atom ??
5236  const set<MolAtom *> *pConn=&(mConnectivityTable.find(mvpAtom[i])->second);
5237  // Find a connected atom already in the mAsZMatrix, prefereably the most recent
5238  for(set<MolAtom *>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5239  if( (vIndex[*pos]<i) && (vIndex[*pos]!=a)
5240  &&(vIndex[*pos]!=b) && (vIndex[*pos]>d)) d=vIndex[*pos];
5241  }
5242  if(d==-1)
5243  {// OK, pick *any* (can this happen ? Really ?)
5244  for(long j=0;j<i;++j)
5245  if((j!=a) &&(j!=b) && (j>d)) d=j;
5246  }
5247  mAsZMatrix[i].mDihedralAtom=d;
5248  mAsZMatrix[i].mDihedralAngle=fmod(GetDihedralAngle(*mvpAtom[d],
5249  *mvpAtom[a],
5250  *mvpAtom[b],
5251  *mvpAtom[i])+2*M_PI,
5252  2*M_PI);
5253  }
5254  }
5255  }
5256  }
5257  }
5258  else
5259  {
5260  // vZIndex[i] tells where mvpAtom[i] is in the z-matrix
5261  vector<long> vZIndex(n);
5262  // vrZIndex[i] tells where which index in vpAtom is ZAtom #i
5263  vector<long> vrZIndex(n);
5264  for(long i=0;i<n;++i)
5265  {
5266  vZIndex [i]=-1;
5267  vrZIndex[i]=-1;
5268  }
5269  long z=0;
5270  BuildZMatrixRecursive(z,0,mvpAtom,mConnectivityTable,mAsZMatrix,vIndex,vZIndex,vrZIndex);
5271  }
5272  return mAsZMatrix;
5273 }
5274 
5276 {
5277 }
5278 
5288 void BuildRingRecursive(MolAtom * currentAtom,
5289  MolAtom * previousAtom,
5290  const map<MolAtom *, set<MolAtom *> > &connect,
5291  list<MolAtom *> &atomlist,
5292  map<set<MolAtom *>,list<MolAtom *> > &ringlist)
5293 {
5294  list<MolAtom *>::const_iterator f=find(atomlist.begin(),atomlist.end(),currentAtom);
5295  if(f!=atomlist.end())
5296  {// This atom was already in the list ! We have found a ring !
5297  #ifdef __DEBUG__
5298  cout<<currentAtom->GetName()<<" was already in the list : ring found !"<<endl;
5299  for(list<MolAtom *>::const_iterator atom=atomlist.begin();atom!=atomlist.end();++atom)
5300  cout<<(*atom)->GetName()<<" ";
5301  cout<<endl;
5302  #endif
5303  set<MolAtom *> ring1;
5304  list<MolAtom *> ring2;
5305  for(list<MolAtom *>::const_iterator pos=f;pos!=atomlist.end();++pos)
5306  {
5307  ring1.insert(*pos);
5308  ring2.push_back(*pos);
5309  }
5310  ringlist.insert(make_pair(ring1,ring2));
5311  }
5312  else
5313  {
5314  atomlist.push_back(currentAtom);
5315  map<MolAtom *,set<MolAtom *> >::const_iterator c=connect.find(currentAtom);
5316  if(c != connect.end())
5317  {
5318  set<MolAtom *>::const_iterator pos;
5319  for(pos=c->second.begin();pos!=c->second.end();++pos)
5320  {
5321  if(*pos==previousAtom) continue;
5322  BuildRingRecursive(*pos,currentAtom,connect,atomlist,ringlist);
5323  }
5324  }
5325  atomlist.pop_back(); //??
5326  }
5327 }
5328 
5330 {
5331  this->BuildConnectivityTable();
5332  if(mClockRingList>mClockConnectivityTable) return;
5333  VFN_DEBUG_ENTRY("Molecule::BuildRingList()",7)
5334  for(vector<MolAtom*>::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
5335  (*pos)->SetIsInRing(false);
5336  list<MolAtom *> atomlist;
5337  // Use a map with a set for key to eliminate duplicate rings
5338  map<set<MolAtom *>,list<MolAtom *> > ringlist;
5339  for(unsigned long i=0;i<mvpAtom.size();i++)
5340  {
5341  atomlist.clear();
5342  BuildRingRecursive(mvpAtom[i],mvpAtom[i],mConnectivityTable,atomlist,ringlist);
5343  }
5344  for(map<set<MolAtom *>,list<MolAtom *> >::const_iterator pos0=ringlist.begin();pos0!=ringlist.end();pos0++)
5345  {
5346  mvRing.resize(mvRing.size()+1);
5347  std::list<MolAtom*> *pList=&(mvRing.back().GetAtomList());
5348  #if 1//def __DEBUG__
5349  cout<<"Found ring:";
5350  #endif
5351  for(list<MolAtom *>::const_iterator atom=pos0->second.begin();atom!=pos0->second.end();++atom)
5352  {
5353  pList->push_back(*atom);
5354  (*atom)->SetIsInRing(true);
5355  #if 1//def __DEBUG__
5356  cout<<(*atom)->GetName()<<" ";
5357  #endif
5358  }
5359  #if 1//def __DEBUG__
5360  cout<<endl;
5361  #endif
5362  }
5363 
5364  cout<<"Rings found :"<<ringlist.size()<<", "<<mvRing.size()<<" unique."<<endl;
5365  mClockRingList.Click();
5366  VFN_DEBUG_EXIT("Molecule::BuildRingList()",7)
5367 }
5368 
5370 {
5371  if( (mClockConnectivityTable>mClockBondList)
5372  &&(mClockConnectivityTable>mClockAtomList)) return;
5373  VFN_DEBUG_ENTRY("Molecule::BuildConnectivityTable()",5)
5374  TAU_PROFILE("Molecule::BuildConnectivityTable()","void ()",TAU_DEFAULT);
5375  mConnectivityTable.clear();
5376 
5377  // First create an entry for all atoms in the table - avoids empty pointers
5378  // in the (pathological) case where some (or all) atoms are not connected
5379  for (unsigned long i = 0; i < mvpAtom.size(); ++i)
5381 
5382  // Then build the table from existing bonds
5383  for(unsigned long i=0;i<mvpBond.size();++i)
5384  {
5385  mConnectivityTable[&(mvpBond[i]->GetAtom1())].insert(&(mvpBond[i]->GetAtom2()));
5386  mConnectivityTable[&(mvpBond[i]->GetAtom2())].insert(&(mvpBond[i]->GetAtom1()));
5387  }
5388 
5389  #ifdef __DEBUG__
5390  {
5391  map<MolAtom *,set<MolAtom *> >::const_iterator pos;
5392  for(pos=mConnectivityTable.begin();pos!=mConnectivityTable.end();++pos)
5393  {
5394  cout<<"Atom "<<pos->first->GetName()<<" is connected to atoms: ";
5395  set<MolAtom *>::const_iterator pos1;
5396  for(pos1=pos->second.begin();pos1!=pos->second.end();++pos1)
5397  {
5398  cout<<(*pos1)->GetName()<<" ";
5399  }
5400  cout<<endl;
5401  if(pos->second.size()>24)
5402  throw ObjCrystException("Molecule: one atom ("+pos->first->GetName()+") has more than 24 bonds !");
5403  }
5404  }
5405  #endif
5406  // No atom should be un-connected, so warn if that happens
5407  // In fact all atoms should be inter-connected to all others...
5408  for (unsigned long i = 0; i < mvpAtom.size(); ++i)
5409  if (mConnectivityTable[mvpAtom[i]].size() == 0)
5410  cout << "Warning: Molecule '" << this->GetName() << "' ConnectivityTable: Atom #"
5411  << i << "(" << mvpAtom[i]->GetName() << ") has no bond !" << endl;
5412 
5413  mClockConnectivityTable.Click();
5414  VFN_DEBUG_EXIT("Molecule::BuildConnectivityTable()",5)
5415 }
5416 
5418 mpAtom1(&at1),mpAtom2(&at2),mBaseRotationAmplitude(M_PI*0.04)
5419 {}
5420 
5422 {
5423  if( (mClockRotorGroup>mClockBondList)
5424  &&(mClockRotorGroup>mClockAtomList)
5425  &&(mClockRotorGroup>mClockBondAngleList)
5426  &&(mClockRotorGroup>mClockDihedralAngleList)) return;
5427  VFN_DEBUG_ENTRY("Molecule::BuildRotorGroup()",5)
5428  TAU_PROFILE("Molecule::BuildRotorGroup()","void ()",TAU_DEFAULT);
5429  this->BuildConnectivityTable();
5430  mvRotorGroupTorsion.clear();
5432  mvRotorGroupInternal.clear();
5433 
5434  // Build Rotation groups around bonds
5435  for(unsigned long i=0;i<mvpBond.size();++i)
5436  {
5437  if((mFlexModel.GetChoice()!=0)&&(false==mvpBond[i]->IsFreeTorsion())) continue;
5438  MolAtom *const atom1=&(mvpBond[i]->GetAtom1()),
5439  *const atom2=&(mvpBond[i]->GetAtom2());
5440  for(unsigned int j=1;j<=2;++j)
5441  {
5442  const set<MolAtom*> *pConn;
5443  if(j==1) pConn=&(mConnectivityTable[atom1]);
5444  else pConn=&(mConnectivityTable[atom2]);
5445 
5446  mvRotorGroupTorsion.push_back(RotorGroup(mvpBond[i]->GetAtom1(),
5447  mvpBond[i]->GetAtom2()));
5448  mvRotorGroupTorsion.back().mvRotatedAtomList.insert(atom1);
5449  mvRotorGroupTorsion.back().mvRotatedAtomList.insert(atom2);
5450 
5451  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5452  {
5453  if((j==1)&&(*pos==atom2)) continue;
5454  if((j==2)&&(*pos==atom1)) continue;
5456  mvRotorGroupTorsion.back().mvRotatedAtomList);
5457  if(pConn->size()>2)
5458  {
5459  mvRotorGroupTorsionSingleChain.push_back(RotorGroup(mvpBond[i]->GetAtom1(),
5460  mvpBond[i]->GetAtom2()));
5461  mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.insert(atom1);
5462  mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.insert(atom2);
5464  mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList);
5465  mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.erase(atom1);
5466  mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.erase(atom2);
5467 
5468  if( (mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2))
5469  ||(mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.size()==0))
5470  mvRotorGroupTorsionSingleChain.pop_back();
5471  }
5472  }
5473  mvRotorGroupTorsion.back().mvRotatedAtomList.erase(atom1);
5474  mvRotorGroupTorsion.back().mvRotatedAtomList.erase(atom2);
5475  if( (mvRotorGroupTorsion.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2))
5476  ||(mvRotorGroupTorsion.back().mvRotatedAtomList.size()==0))
5477  mvRotorGroupTorsion.pop_back();
5478  }
5479  }
5480  #if 1
5481  // Build 'internal' rotation groups between random atoms
5482  //:TODO: This should be tried for *random* configuration of free torsion angles...
5483  if(mFlexModel.GetChoice()==0)
5484  {
5485  for(vector<MolAtom*>::const_iterator atom1=this->GetAtomList().begin();
5486  atom1!=this->GetAtomList().end();++atom1)
5487  {
5488  const set<MolAtom*> *pConn=&(mConnectivityTable[*atom1]);
5489  vector<MolAtom*>::const_iterator atom2=atom1;
5490  atom2++;
5491  for(;atom2!=this->GetAtomList().end();++atom2)
5492  {
5493  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5494  {
5495  if(*pos==*atom2) continue;
5496  mvRotorGroupInternal.push_back(RotorGroup(**atom1,**atom2));
5497  mvRotorGroupInternal.back().mvRotatedAtomList.insert(*atom1);
5499  mvRotorGroupInternal.back().mvRotatedAtomList,
5500  *atom2);
5501  //Check if this chains leads to atom2
5502  set<MolAtom*>::const_iterator check
5503  =find(mvRotorGroupInternal.back().mvRotatedAtomList.begin(),
5504  mvRotorGroupInternal.back().mvRotatedAtomList.end(),*atom2);
5505  if( (check==mvRotorGroupInternal.back().mvRotatedAtomList.end())
5506  ||(mvRotorGroupInternal.back().mvRotatedAtomList.size()<3)
5507  ||(mvRotorGroupInternal.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2)))
5508  {
5509  mvRotorGroupInternal.pop_back();
5510  }
5511  else
5512  {
5513  mvRotorGroupInternal.back().mvRotatedAtomList.erase(*atom1);
5514  mvRotorGroupInternal.back().mvRotatedAtomList.erase(*atom2);
5515  }
5516  }
5517  }
5518  }
5519  }
5520  #endif
5521 
5522  // Remove identical groups
5523  for(unsigned int i=1;i<=3;++i)
5524  {
5525  list<RotorGroup> *pRotorGroup1;
5526  switch(i)
5527  {
5528  case 1: pRotorGroup1=&mvRotorGroupTorsion;break;
5529  case 2: pRotorGroup1=&mvRotorGroupTorsionSingleChain;break;
5530  case 3: pRotorGroup1=&mvRotorGroupInternal;break;
5531  }
5532  for(list<RotorGroup>::iterator pos1=pRotorGroup1->begin();
5533  pos1!=pRotorGroup1->end();++pos1)
5534  {
5535  for(unsigned int j=i;j<=3;++j)
5536  {
5537  list<RotorGroup> *pRotorGroup2;
5538  switch(j)
5539  {
5540  case 1: pRotorGroup2=&mvRotorGroupTorsion;break;
5541  case 2: pRotorGroup2=&mvRotorGroupTorsionSingleChain;break;
5542  case 3: pRotorGroup2=&mvRotorGroupInternal;break;
5543  }
5544  for(list<RotorGroup>::iterator pos2=pRotorGroup2->begin();
5545  pos2!=pRotorGroup2->end();)
5546  {
5547  if(pos2==pos1) {++pos2;continue;}
5548  if(( ((pos1->mpAtom1 == pos2->mpAtom1) && (pos1->mpAtom2 == pos2->mpAtom2))
5549  ||((pos1->mpAtom2 == pos2->mpAtom1) && (pos1->mpAtom1 == pos2->mpAtom2)))
5550  &&pos1->mvRotatedAtomList.size() == pos2->mvRotatedAtomList.size())
5551  {
5552  bool ident=true;
5553  for(set<MolAtom*>::const_iterator pos=pos1->mvRotatedAtomList.begin();
5554  pos!=pos1->mvRotatedAtomList.end();++pos)
5555  {
5556  set<MolAtom*>::const_iterator tmp=pos2->mvRotatedAtomList.find(*pos);
5557  if(tmp == pos2->mvRotatedAtomList.end())
5558  {
5559  ident=false;
5560  break;
5561  }
5562  }
5563  if(ident)
5564  {
5565  #if 0
5566  cout<<"Identical groups:"<<endl;
5567  cout<<" G1:"
5568  <<pos1->mpAtom1->GetName()<<"-"
5569  <<pos1->mpAtom2->GetName()<<" : ";
5570  for(set<MolAtom*>::iterator pos=pos1->mvRotatedAtomList.begin();
5571  pos!=pos1->mvRotatedAtomList.end();++pos)
5572  cout<<(*pos)->GetName()<<" ";
5573  cout<<endl;
5574  cout<<" G2:"
5575  <<pos2->mpAtom1->GetName()<<"-"
5576  <<pos2->mpAtom2->GetName()<<" : ";
5577  for(set<MolAtom*>::iterator pos=pos2->mvRotatedAtomList.begin();
5578  pos!=pos2->mvRotatedAtomList.end();++pos)
5579  cout<<(*pos)->GetName()<<" ";
5580  cout<<endl;
5581  #endif
5582  pos2=pRotorGroup2->erase(pos2);
5583  }
5584  else ++pos2;
5585  }
5586  else ++pos2;
5587  }
5588  }
5589  }
5590  }
5591  // Remove all rotations which break restraints and therefore are not "free torsion"
5592  this->SaveParamSet(mLocalParamSet);
5593  const REAL llk0=this->GetLogLikelihood();
5594  for(unsigned int i=1;i<=3;++i)
5595  {
5596  list<RotorGroup> *pRotorGroup1;
5597  switch(i)
5598  {
5599  case 1: pRotorGroup1=&mvRotorGroupTorsion;break;
5600  case 2: pRotorGroup1=&mvRotorGroupTorsionSingleChain;break;
5601  case 3: pRotorGroup1=&mvRotorGroupInternal;break;
5602  }
5603  for(list<RotorGroup>::iterator pos=pRotorGroup1->begin();
5604  pos!=pRotorGroup1->end();)
5605  {
5606  REAL llk=0;
5607  for(unsigned int j=0;j<36;++j)
5608  {
5609  const REAL angle=(REAL)j*M_PI/36.;
5610  this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),
5611  pos->mvRotatedAtomList,angle);
5612  // use fabs in case we are not starting from the minimum of a restraint..
5613  llk += fabs(this->GetLogLikelihood() - llk0);
5614  this->RestoreParamSet(mLocalParamSet);
5615  }
5616  #ifdef __DEBUG__
5617  switch(i)
5618  {
5619  case 1: cout<<"Rotation Group around bond :";break;
5620  case 2: cout<<"Rotation Group (single chain) around bond :";break;
5621  case 3: cout<<"Rotation Group (internal) between :";break;
5622  }
5623  cout <<pos->mpAtom1->GetName()<<"-"
5624  <<pos->mpAtom2->GetName()<<" : ";
5625  for(set<MolAtom *>::iterator pos1=pos->mvRotatedAtomList.begin();
5626  pos1!=pos->mvRotatedAtomList.end();++pos1)
5627  cout<<(*pos1)->GetName()<<" ";
5628  cout<<" <d(LLK)>="<< llk/36.;
5629  #endif
5630  if((llk/50.)>100.)
5631  {
5632  pos = pRotorGroup1->erase(pos);
5633  //cout <<" -> NOT a free torsion"<<endl;
5634  }
5635  else ++pos;
5636  //else
5637  // cout <<" -> free torsion"<<endl;
5638  }
5639  }
5640  //cout<<endl;
5641 
5642  // Label free torsions
5643  for(vector<MolBond*>::iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
5644  (*pos)->SetFreeTorsion(false);
5645  for(list<RotorGroup>::iterator pos=mvRotorGroupTorsion.begin();
5646  pos!=mvRotorGroupTorsion.end();++pos)
5647  {
5648  vector<MolBond*>::iterator bd=this->FindBond((*pos->mpAtom1),(*pos->mpAtom2));
5649  if(bd!=mvpBond.end()) (*bd)->SetFreeTorsion(true);
5650  }
5651 
5652  mClockRotorGroup.Click();
5653  VFN_DEBUG_EXIT("Molecule::BuildRotorGroup()",5)
5654 }
5655 
5657 {
5658  #if 0
5659  if( (mClockStretchModeBondLength>mClockBondList)
5660  &&(mClockStretchModeBondLength>mClockAtomList)
5661  &&(mClockStretchModeBondLength>mClockBondAngleList)
5662  &&(mClockStretchModeBondLength>mClockDihedralAngleList)) return;
5663  #endif
5664  VFN_DEBUG_ENTRY("Molecule::BuildStretchModeBondLength()",7)
5665  this->BuildConnectivityTable();
5666  TAU_PROFILE("Molecule::BuildStretchModeBondLength()","void ()",TAU_DEFAULT);
5667  TAU_PROFILE_TIMER(timer1,"Molecule::BuildStretchModeBondLength 1","", TAU_FIELD);
5668  TAU_PROFILE_TIMER(timer2,"Molecule::BuildStretchModeBondLength 2","", TAU_FIELD);
5669  TAU_PROFILE_TIMER(timer3,"Molecule::BuildStretchModeBondLength 3","", TAU_FIELD);
5670  TAU_PROFILE_TIMER(timer4,"Molecule::BuildStretchModeBondLength 4","", TAU_FIELD);
5671  TAU_PROFILE_TIMER(timer5,"Molecule::BuildStretchModeBondLength 5","", TAU_FIELD);
5672  mvStretchModeBondLength.clear();
5673  // Build list of atoms moved when stretching a bond length. Only keep the group
5674  // of atoms on the smaller side.
5675  TAU_PROFILE_START(timer1);
5676  for(unsigned long i=0;i<mvpBond.size();++i)
5677  {
5678  //if((mFlexModel.GetChoice()!=0)&&(false==mvpBond[i]->IsFreeTorsion())) continue;
5679  MolAtom* const atom1=&(mvpBond[i]->GetAtom1());
5680  MolAtom* const atom2=&(mvpBond[i]->GetAtom2());
5681  for(unsigned int j=1;j<=2;++j)
5682  {
5683  const set<MolAtom*> *pConn;
5684  if(j==1) pConn=&(mConnectivityTable[atom1]);
5685  else pConn=&(mConnectivityTable[atom2]);
5686 
5687  if(j==1)
5688  mvStretchModeBondLength.push_back(StretchModeBondLength(mvpBond[i]->GetAtom2(),
5689  mvpBond[i]->GetAtom1(),
5690  mvpBond[i]));
5691  else
5692  mvStretchModeBondLength.push_back(StretchModeBondLength(mvpBond[i]->GetAtom1(),
5693  mvpBond[i]->GetAtom2(),
5694  mvpBond[i]));
5695  if(j==1) mvStretchModeBondLength.back().mvTranslatedAtomList.insert(atom1);
5696  if(j==2) mvStretchModeBondLength.back().mvTranslatedAtomList.insert(atom2);
5697 
5698  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5699  {
5700  if((j==1)&&(*pos==atom2)) continue;
5701  if((j==2)&&(*pos==atom1)) continue;
5703  mvStretchModeBondLength.back().mvTranslatedAtomList);
5704  }
5705  const unsigned long ct1=mvStretchModeBondLength.back().mvTranslatedAtomList.count(atom1),
5706  ct2=mvStretchModeBondLength.back().mvTranslatedAtomList.count(atom2);
5707  if( ((j==1)&&(ct2>0)) || ((j==2)&&(ct1>0)) )
5708  {
5709  // We have found a ring. No use looking at the other side.
5710  // :TODO: handle this properly..
5711  mvStretchModeBondLength.pop_back();
5712  break;
5713  }
5714  if( (mvStretchModeBondLength.back().mvTranslatedAtomList.size()>((mvpAtom.size()+1)/2))
5715  ||(mvStretchModeBondLength.back().mvTranslatedAtomList.size()==0))
5716  {
5717  #ifdef __DEBUG__
5718  cout<<"Rejecting StretchModeBondLength ";mvStretchModeBondLength.back().Print(cout);cout<<endl;
5719  #endif
5720  mvStretchModeBondLength.pop_back();
5721  }
5722  else if(mvStretchModeBondLength.back().mvTranslatedAtomList.size()==((mvpAtom.size()+1)/2))
5723  break;//we translate exactly half of the atoms, so skip the other half
5724  }
5725  }
5726  TAU_PROFILE_STOP(timer1);
5727 
5728  // find rigid groups broken by each mode
5729  for(list<StretchModeBondLength>::iterator pos=mvStretchModeBondLength.begin();
5730  pos!=mvStretchModeBondLength.end();)
5731  {
5732  TAU_PROFILE_START(timer5);
5733  bool keep=true;
5734  for(vector<RigidGroup*>::const_iterator group=mvRigidGroup.begin();
5735  group!=mvRigidGroup.end();++group)
5736  {
5737  unsigned long ct=0;
5738  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
5739  ct += pos->mvTranslatedAtomList.count(*at);
5740  if((ct>0)&&(ct!=(*group)->size()))
5741  {
5742  keep=false;
5743  #ifdef __DEBUG__
5744  cout<<" Breaks Rigid Group:";
5745  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
5746  cout<<(*at)->GetName()<<" ";
5747  cout<<endl;
5748  #endif
5749  break;
5750  }
5751  }
5752  if(keep) ++pos;
5753  else pos=mvStretchModeBondLength.erase(pos);
5754  TAU_PROFILE_STOP(timer5);
5755  }
5756  // Generate 5 completely random atomic positions
5757  this->SaveParamSet(mLocalParamSet);
5758  unsigned long paramSetRandom[5];
5759  for(unsigned long i=0;i<5;++i)
5760  {
5761  for(vector<MolAtom*>::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
5762  {
5763  (*pos)->SetX(100.*rand()/(REAL) RAND_MAX);
5764  (*pos)->SetY(100.*rand()/(REAL) RAND_MAX);
5765  (*pos)->SetZ(100.*rand()/(REAL) RAND_MAX);
5766  }
5767  paramSetRandom[i]=this->CreateParamSet();
5768  }
5769  // find bond lengths broken by each mode
5770  for(list<StretchModeBondLength>::iterator pos=mvStretchModeBondLength.begin();
5771  pos!=mvStretchModeBondLength.end();)
5772  {
5773  TAU_PROFILE_START(timer2);
5774  bool keep=true;
5775  pos->mvpBrokenBond.clear();
5776  for(vector<MolBond*>::const_iterator r=mvpBond.begin();r!=mvpBond.end();++r)
5777  {
5778  unsigned int ct=0;
5779  for(set<MolAtom *>::const_iterator at=pos->mvTranslatedAtomList.begin();
5780  at!=pos->mvTranslatedAtomList.end();++at)
5781  {
5782  if(*at==&((*r)->GetAtom1())) ct++;
5783  if(*at==&((*r)->GetAtom2())) ct++;
5784  }
5785  // If we moved either both or non of the bond atom, the bond length is unchanged.
5786  if((ct!=0)&&(ct !=2)) pos->mvpBrokenBond.insert(make_pair(*r,0));
5787  }
5788  if(mFlexModel.GetChoice()==2)
5789  {
5790  int nb=pos->mvpBrokenBond.size();
5791  if(pos->mpBond!=0) nb -= 1;
5792  if(nb>0) keep=false;
5793  }
5794  if(keep) ++pos;
5795  else pos=mvStretchModeBondLength.erase(pos);
5796  TAU_PROFILE_STOP(timer2);
5797  }
5798  // find bond angles broken by each mode
5799  for(list<StretchModeBondLength>::iterator pos=mvStretchModeBondLength.begin();
5800  pos!=mvStretchModeBondLength.end();)
5801  {
5802  TAU_PROFILE_START(timer3);
5803  bool keep=true;
5804  pos->mvpBrokenBondAngle.clear();
5805  for(vector<MolBondAngle*>::const_iterator r=mvpBondAngle.begin();r!=mvpBondAngle.end();++r)
5806  {
5807  unsigned int ct=0;
5808  for(set<MolAtom *>::const_iterator at=pos->mvTranslatedAtomList.begin();
5809  at!=pos->mvTranslatedAtomList.end();++at)
5810  {
5811  if(*at==&((*r)->GetAtom1())) ct++;
5812  if(*at==&((*r)->GetAtom2())) ct++;
5813  if(*at==&((*r)->GetAtom3())) ct++;
5814  }
5815  bool broken=true;
5816  if((ct==0)||(ct==3)) broken=false;
5817  if(broken)
5818  {// Make sure with derivatives
5819  REAL d=0;
5820  for(unsigned long i=0;i<5;++i)
5821  {
5822  this->RestoreParamSet(paramSetRandom[i]);
5823  pos->CalcDeriv(false);
5824  (*r)->GetLogLikelihood(true,true);
5825  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
5826  if(d>0.01) break;
5827  }
5828  if(abs(d)<=0.01) broken=false;
5829  }
5830  if(broken) pos->mvpBrokenBondAngle.insert(make_pair(*r,0));
5831  }
5832  if(mFlexModel.GetChoice()==2)
5833  {
5834  if(pos->mvpBrokenBondAngle.size()>0) keep=false;
5835  }
5836  if(keep) ++pos;
5837  else pos=mvStretchModeBondLength.erase(pos);
5838  TAU_PROFILE_STOP(timer3);
5839  }
5840  // find dihedral angles broken by each mode
5841  for(list<StretchModeBondLength>::iterator pos=mvStretchModeBondLength.begin();
5842  pos!=mvStretchModeBondLength.end();)
5843  {
5844  TAU_PROFILE_START(timer4);
5845  bool keep=true;
5846  pos->mvpBrokenDihedralAngle.clear();
5847  for(vector<MolDihedralAngle*>::const_iterator r=mvpDihedralAngle.begin();r!=mvpDihedralAngle.end();++r)
5848  {
5849  unsigned int ct=0;
5850  for(set<MolAtom *>::const_iterator at=pos->mvTranslatedAtomList.begin();
5851  at!=pos->mvTranslatedAtomList.end();++at)
5852  {
5853  if(*at==&((*r)->GetAtom1())) ct++;
5854  if(*at==&((*r)->GetAtom2())) ct++;
5855  if(*at==&((*r)->GetAtom3())) ct++;
5856  if(*at==&((*r)->GetAtom4())) ct++;
5857  }
5858  bool broken=true;
5859  if((ct==0)||(ct==4)) broken=false;
5860  if(broken)
5861  {// Make sure with derivatives
5862  REAL d=0;
5863  for(unsigned long i=0;i<5;++i)
5864  {
5865  this->RestoreParamSet(paramSetRandom[i]);
5866  pos->CalcDeriv(false);
5867  (*r)->GetLogLikelihood(true,true);
5868  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
5869  if(d>0.01) break;
5870  }
5871  if(abs(d)<=0.01) broken=false;
5872  }
5873  if(broken) pos->mvpBrokenDihedralAngle.insert(make_pair(*r,0));
5874  }
5875  if(mFlexModel.GetChoice()==2)
5876  {
5877  if(pos->mvpBrokenDihedralAngle.size()>0) keep=false;
5878  }
5879  if(keep) ++pos;
5880  else pos=mvStretchModeBondLength.erase(pos);
5881  TAU_PROFILE_STOP(timer4);
5882  }
5883  this->RestoreParamSet(mLocalParamSet);
5884  for(unsigned long i=0;i<5;++i) this->ClearParamSet(paramSetRandom[i]);
5885  #if 1//def __DEBUG__
5886  cout<<"List of Bond Length stretch modes"<<endl;
5887  for(list<StretchModeBondLength>::const_iterator pos=mvStretchModeBondLength.begin();
5888  pos!=mvStretchModeBondLength.end();++pos)
5889  {
5890  cout<<" Bond:"<<pos->mpAtom0->GetName()<<"-"<<pos->mpAtom1->GetName()<<", Translated Atoms: ";
5891  for(set<MolAtom*>::const_iterator atom=pos->mvTranslatedAtomList.begin();
5892  atom!=pos->mvTranslatedAtomList.end();++atom)
5893  {
5894  cout<<(*atom)->GetName()<<",";
5895  }
5896  if(pos->mpBond!=0) cout<< " ; restrained to length="<<pos->mpBond->GetLength0()
5897  <<", sigma="<<pos->mpBond->GetLengthSigma()
5898  <<", delta="<<pos->mpBond->GetLengthDelta();
5899  if(pos->mvpBrokenBond.size()>0)
5900  {
5901  cout<<endl<<" Broken bonds:";
5902  for(map<const MolBond*,REAL>::const_iterator bond=pos->mvpBrokenBond.begin();
5903  bond!=pos->mvpBrokenBond.end();++bond)
5904  cout<<bond->first->GetName()<<", ";
5905  }
5906  if(pos->mvpBrokenBondAngle.size()>0)
5907  {
5908  cout<<endl<<" Broken bond angles:";
5909  for(map<const MolBondAngle*,REAL>::const_iterator angle=pos->mvpBrokenBondAngle.begin();
5910  angle!=pos->mvpBrokenBondAngle.end();++angle)
5911  cout<<angle->first->GetName()<<", ";
5912  }
5913  if(pos->mvpBrokenDihedralAngle.size()>0)
5914  {
5915  cout<<endl<<" Broken dihedral angles:";
5916  for(map<const MolDihedralAngle*,REAL>::const_iterator
5917  angle=pos->mvpBrokenDihedralAngle.begin();
5918  angle!=pos->mvpBrokenDihedralAngle.end();++angle)
5919  cout<<angle->first->GetName()<<", ";
5920  }
5921  cout<<endl;
5922  }
5923  #endif
5924  mClockStretchModeBondLength.Click();
5925  VFN_DEBUG_EXIT("Molecule::BuildStretchModeBondLength()",7)
5926 }
5927 
5929 {
5930  #if 0
5931  if( (mClockStretchModeBondAngle>mClockBondList)
5932  &&(mClockStretchModeBondAngle>mClockAtomList)
5933  &&(mClockStretchModeBondAngle>mClockBondAngleList)
5934  &&(mClockStretchModeBondAngle>mClockDihedralAngleList)) return;
5935  #endif
5936  VFN_DEBUG_ENTRY("Molecule::BuildStretchModeBondAngle()",10)
5937  this->BuildConnectivityTable();
5938  TAU_PROFILE("Molecule::BuildStretchModeBondAngle()","void ()",TAU_DEFAULT);
5939  TAU_PROFILE_TIMER(timer1,"Molecule::BuildStretchModeBondAngle 1","", TAU_FIELD);
5940  TAU_PROFILE_TIMER(timer2,"Molecule::BuildStretchModeBondAngle 2","", TAU_FIELD);
5941  TAU_PROFILE_TIMER(timer3,"Molecule::BuildStretchModeBondAngle 3","", TAU_FIELD);
5942  TAU_PROFILE_TIMER(timer4,"Molecule::BuildStretchModeBondAngle 4","", TAU_FIELD);
5943  TAU_PROFILE_TIMER(timer5,"Molecule::BuildStretchModeBondAngle 5","", TAU_FIELD);
5944  mvStretchModeBondAngle.clear();
5945  // Build list of atoms moved when stretching a bond angle. Only keep the group
5946  // of atoms on the smaller side.
5947  TAU_PROFILE_START(timer1);
5948  for(unsigned long i=0;i<mvpAtom.size();++i)
5949  {
5950  //if((mFlexModel.GetChoice()!=0)&&(false==mvpBond[i]->IsFreeTorsion())) continue;
5951  set<MolAtom*> *pConn0=&(mConnectivityTable[mvpAtom[i]]);
5952  if(pConn0->size()<2) continue;
5953  for(set<MolAtom*>::const_iterator pos1=pConn0->begin();pos1!=pConn0->end();++pos1)
5954  {
5955  set<MolAtom*>::const_iterator pos2=pos1;
5956  pos2++;
5957  for(;pos2!=pConn0->end();++pos2)
5958  {
5959  VFN_DEBUG_MESSAGE("Molecule::BuildStretchModeBondAngle():"<<i<<","<<*pos1<<","<<*pos2,10)
5960  //Do we have a bond angle restraint corresponding to these atoms ?
5961  MolBondAngle *pMolBondAngle=0;
5962  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
5963  {
5964  if(&((*pos)->GetAtom2())==mvpAtom[i])
5965  {
5966  if( ((&((*pos)->GetAtom1())==*pos1)&&(&((*pos)->GetAtom3())==*pos2))
5967  ||((&((*pos)->GetAtom1())==*pos2)&&(&((*pos)->GetAtom3())==*pos1)))
5968  {
5969  pMolBondAngle=*pos;
5970  break;
5971  }
5972  }
5973  }
5974  for(unsigned int j=1;j<=2;++j)
5975  {
5976  const set<MolAtom*> *pConn;
5977  if(j==1)
5978  {
5979  pConn=&(mConnectivityTable[*pos1]);
5981  *mvpAtom[i],
5982  **pos1,
5983  pMolBondAngle));
5984  mvStretchModeBondAngle.back().mvRotatedAtomList.insert(*pos1);
5985  }
5986  else
5987  {
5988  pConn=&(mConnectivityTable[*pos2]);
5990  *mvpAtom[i],
5991  **pos2,
5992  pMolBondAngle));
5993  mvStretchModeBondAngle.back().mvRotatedAtomList.insert(*pos2);
5994  }
5995  mvStretchModeBondAngle.back().mvRotatedAtomList.insert(mvpAtom[i]);
5996 
5997  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5998  {
5999  if(*pos==mvpAtom[i]) continue;
6001  mvStretchModeBondAngle.back().mvRotatedAtomList);
6002  }
6003  //if(j==1)mvStretchModeBondAngle.back().mvRotatedAtomList.erase(*pos2);
6004  //if(j==2)mvStretchModeBondAngle.back().mvRotatedAtomList.erase(*pos1);
6005  mvStretchModeBondAngle.back().mvRotatedAtomList.erase(mvpAtom[i]);
6006 
6007  if( (mvStretchModeBondAngle.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2))
6008  ||(mvStretchModeBondAngle.back().mvRotatedAtomList.size()==0))
6009  {
6010  #ifdef __DEBUG__
6011  cout<<"Rejecting StretchModeBondAngle ";mvStretchModeBondAngle.back().Print(cout);cout<<endl;
6012  #endif
6013  mvStretchModeBondAngle.pop_back();
6014  }
6015  else
6016  {
6017  if((j==1) &&(mvStretchModeBondAngle.back().mvRotatedAtomList.find(*pos2)
6018  !=mvStretchModeBondAngle.back().mvRotatedAtomList.end()))
6019  {
6020  #if 1//def __DEBUG__
6021  cout<<"Rejecting StretchModeBondAngle (ring) ";mvStretchModeBondAngle.back().Print(cout);cout<<endl;
6022  #endif
6023  mvStretchModeBondAngle.pop_back();
6024  }
6025  if((j==2) &&(mvStretchModeBondAngle.back().mvRotatedAtomList.find(*pos1)
6026  !=mvStretchModeBondAngle.back().mvRotatedAtomList.end()))
6027  {
6028  #if 1//def __DEBUG__
6029  cout<<"Rejecting StretchModeBondAngle (ring) ";mvStretchModeBondAngle.back().Print(cout);cout<<endl;
6030  #endif
6031  mvStretchModeBondAngle.pop_back();
6032  }
6033  }
6034 
6035  }
6036  }
6037  }
6038  }
6039  TAU_PROFILE_STOP(timer1);
6040  // find rigid groups broken by each mode
6041  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
6042  pos!=mvStretchModeBondAngle.end();)
6043  {
6044  TAU_PROFILE_START(timer5);
6045  bool keep=true;
6046  for(vector<RigidGroup*>::const_iterator group=mvRigidGroup.begin();
6047  group!=mvRigidGroup.end();++group)
6048  {
6049  unsigned long ct=0;
6050  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
6051  ct += pos->mvRotatedAtomList.count(*at);
6052  if(ct>0)
6053  {
6054  // Add the origin atom, which does not move relatively to the rotated atoms
6055  ct += (*group)->count(pos->mpAtom1);
6056  if(ct!=(*group)->size())
6057  {
6058  keep=false;
6059  #ifdef __DEBUG__
6060  pos->Print(cout);
6061  cout<<" Breaks Rigid Group:";
6062  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
6063  cout<<(*at)->GetName()<<" ";
6064  cout<<endl;
6065  #endif
6066  break;
6067  }
6068  }
6069  }
6070  if(keep) ++pos;
6071  else pos=mvStretchModeBondAngle.erase(pos);
6072  TAU_PROFILE_STOP(timer5);
6073  }
6074  // Generate 5 completely random atomic positions
6075  this->SaveParamSet(mLocalParamSet);
6076  unsigned long paramSetRandom[5];
6077  for(unsigned long i=0;i<5;++i)
6078  {
6079  for(vector<MolAtom*>::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
6080  {
6081  (*pos)->SetX(100.*rand()/(REAL) RAND_MAX);
6082  (*pos)->SetY(100.*rand()/(REAL) RAND_MAX);
6083  (*pos)->SetZ(100.*rand()/(REAL) RAND_MAX);
6084  }
6085  paramSetRandom[i]=this->CreateParamSet();
6086  }
6087  // find bond lengths broken by each mode
6088  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
6089  pos!=mvStretchModeBondAngle.end();)
6090  {
6091  TAU_PROFILE_START(timer2);
6092  bool keep=true;
6093  pos->mvpBrokenBond.clear();
6094  for(vector<MolBond*>::const_iterator r=mvpBond.begin();r!=mvpBond.end();++r)
6095  {
6096  unsigned int ct=0;
6097  for(set<MolAtom *>::const_iterator at=pos->mvRotatedAtomList.begin();
6098  at!=pos->mvRotatedAtomList.end();++at)
6099  {
6100  if(*at==&((*r)->GetAtom1())) ct++;
6101  if(*at==&((*r)->GetAtom2())) ct++;
6102  }
6103  bool broken=true;
6104  // If we moved either both or non of the bond atom, the bond length is unchanged.
6105  if((ct==0)||(ct==2)) broken=false;
6106  if(broken)
6107  {// Make sure with derivatives
6108  REAL d=0;
6109  for(unsigned long i=0;i<5;++i)
6110  {
6111  this->RestoreParamSet(paramSetRandom[i]);
6112  pos->CalcDeriv(false);
6113  (*r)->GetLogLikelihood(true,true);
6114  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6115  if(d>0.01) break;
6116  }
6117  if(abs(d)<=0.01) broken=false;
6118  }
6119  if(broken) pos->mvpBrokenBond.insert(make_pair(*r,0));
6120  }
6121  if(mFlexModel.GetChoice()==2)
6122  {
6123  if(pos->mvpBrokenBond.size()>0) keep=false;
6124  }
6125  if(keep) ++pos;
6126  else pos=mvStretchModeBondAngle.erase(pos);
6127  TAU_PROFILE_STOP(timer2);
6128  }
6129  // find bond angles broken by each mode
6130  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
6131  pos!=mvStretchModeBondAngle.end();)
6132  {
6133  TAU_PROFILE_START(timer3);
6134  bool keep=true;
6135  pos->mvpBrokenBondAngle.clear();
6136  for(vector<MolBondAngle*>::const_iterator r=mvpBondAngle.begin();r!=mvpBondAngle.end();++r)
6137  {
6138  unsigned int ct=0;
6139  for(set<MolAtom *>::const_iterator at=pos->mvRotatedAtomList.begin();
6140  at!=pos->mvRotatedAtomList.end();++at)
6141  {
6142  if(*at==&((*r)->GetAtom1())) ct++;
6143  if(*at==&((*r)->GetAtom2())) ct++;
6144  if(*at==&((*r)->GetAtom3())) ct++;
6145  }
6146  bool broken=true;
6147  if(ct==0) broken=false;
6148  if(ct==3) broken=false;
6149  if(broken)
6150  {// Make sure with derivatives
6151  REAL d=0;
6152  for(unsigned long i=0;i<5;++i)
6153  {
6154  this->RestoreParamSet(paramSetRandom[i]);
6155  pos->CalcDeriv(false);
6156  (*r)->GetLogLikelihood(true,true);
6157  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6158  if(d>0.01) break;
6159  }
6160  if(abs(d)<=0.01) broken=false;
6161  }
6162  if(broken) pos->mvpBrokenBondAngle.insert(make_pair(*r,0));
6163  }
6164  if(mFlexModel.GetChoice()==2)
6165  {
6166  int nb=pos->mvpBrokenBond.size();
6167  if(pos->mpBondAngle!=0) nb -= 1;
6168  if(nb>0) keep=false;
6169  }
6170  if(keep) ++pos;
6171  else pos=mvStretchModeBondAngle.erase(pos);
6172  TAU_PROFILE_STOP(timer3);
6173  }
6174  // find dihedral angles broken by each mode
6175  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
6176  pos!=mvStretchModeBondAngle.end();)
6177  {
6178  TAU_PROFILE_START(timer4);
6179  bool keep=true;
6180  pos->mvpBrokenDihedralAngle.clear();
6181  for(vector<MolDihedralAngle*>::const_iterator r=mvpDihedralAngle.begin();r!=mvpDihedralAngle.end();++r)
6182  {
6183  unsigned int ct=0;
6184  for(set<MolAtom *>::const_iterator at=pos->mvRotatedAtomList.begin();
6185  at!=pos->mvRotatedAtomList.end();++at)
6186  {
6187  if(*at==&((*r)->GetAtom1())) ct++;
6188  if(*at==&((*r)->GetAtom2())) ct++;
6189  if(*at==&((*r)->GetAtom3())) ct++;
6190  if(*at==&((*r)->GetAtom4())) ct++;
6191  }
6192  bool broken=true;
6193  if(ct==0) broken=false;
6194  if(ct==4) broken=false;
6195  if(broken)
6196  {// Make sure with derivatives
6197  REAL d=0;
6198  for(unsigned long i=0;i<5;++i)
6199  {
6200  this->RestoreParamSet(paramSetRandom[i]);
6201  pos->CalcDeriv(false);
6202  (*r)->GetLogLikelihood(true,true);
6203  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6204  if(d>0.01) break;
6205  }
6206  if(abs(d)<=0.01) broken=false;
6207  }
6208  if(broken) pos->mvpBrokenDihedralAngle.insert(make_pair(*r,0));
6209  }
6210  if(mFlexModel.GetChoice()==2)
6211  {
6212  if(pos->mvpBrokenDihedralAngle.size()>0) keep=false;
6213  }
6214  if(keep) ++pos;
6215  else pos=mvStretchModeBondAngle.erase(pos);
6216  TAU_PROFILE_STOP(timer4);
6217  }
6218  this->RestoreParamSet(mLocalParamSet);
6219  for(unsigned long i=0;i<5;++i) this->ClearParamSet(paramSetRandom[i]);
6220  #ifdef __DEBUG__
6221  cout<<"List of Bond Angle stretch modes"<<endl;
6222  for(list<StretchModeBondAngle>::const_iterator pos=mvStretchModeBondAngle.begin();
6223  pos!=mvStretchModeBondAngle.end();++pos)
6224  {
6225  cout<<" Angle:"<<pos->mpAtom0->GetName()<<"-"
6226  <<pos->mpAtom1->GetName()<<"-"
6227  <<pos->mpAtom2->GetName()<<", Rotated Atoms: ";
6228  for(set<MolAtom*>::const_iterator atom=pos->mvRotatedAtomList.begin();
6229  atom!=pos->mvRotatedAtomList.end();++atom)
6230  {
6231  cout<<(*atom)->GetName()<<",";
6232  }
6233  if(pos->mpBondAngle!=0) cout<< " ; restrained to angle="<<pos->mpBondAngle->GetAngle0()*RAD2DEG
6234  <<"�, sigma="<<pos->mpBondAngle->GetAngleSigma()*RAD2DEG
6235  <<"�, delta="<<pos->mpBondAngle->GetAngleDelta()*RAD2DEG<<"�";
6236  if(pos->mvpBrokenBond.size()>0)
6237  {
6238  cout<<endl<<" Broken bonds:";
6239  for(map<const MolBond*,REAL>::const_iterator bond=pos->mvpBrokenBond.begin();
6240  bond!=pos->mvpBrokenBond.end();++bond)
6241  cout<<bond->first->GetName()<<", ";
6242  }
6243  if(pos->mvpBrokenBondAngle.size()>0)
6244  {
6245  cout<<endl<<" Broken bond angles:";
6246  for(map<const MolBondAngle*,REAL>::const_iterator angle=pos->mvpBrokenBondAngle.begin();
6247  angle!=pos->mvpBrokenBondAngle.end();++angle)
6248  cout<<angle->first->GetName()<<", ";
6249  }
6250  if(pos->mvpBrokenDihedralAngle.size()>0)
6251  {
6252  cout<<endl<<" Broken dihedral angles:";
6253  for(map<const MolDihedralAngle*,REAL>::const_iterator
6254  angle=pos->mvpBrokenDihedralAngle.begin();
6255  angle!=pos->mvpBrokenDihedralAngle.end();++angle)
6256  cout<<angle->first->GetName()<<", ";
6257  }
6258  cout<<endl;
6259  }
6260  #endif
6261  mClockStretchModeBondAngle.Click();
6262  VFN_DEBUG_EXIT("Molecule::BuildStretchModeBondAngle()",10)
6263 }
6264 
6266 {
6267  #if 0
6268  if( (mClockStretchModeTorsion>mClockBondList)
6269  &&(mClockStretchModeTorsion>mClockAtomList)
6270  &&(mClockStretchModeTorsion>mClockBondAngleList)
6271  &&(mClockStretchModeTorsion>mClockDihedralAngleList)) return;
6272  #endif
6273  VFN_DEBUG_ENTRY("Molecule::BuildStretchModeTorsion()",7)
6274  TAU_PROFILE("Molecule::BuildStretchModeTorsion()","void ()",TAU_DEFAULT);
6275  TAU_PROFILE_TIMER(timer1,"Molecule::BuildStretchModeTorsion 1","", TAU_FIELD);
6276  TAU_PROFILE_TIMER(timer2,"Molecule::BuildStretchModeTorsion 2","", TAU_FIELD);
6277  TAU_PROFILE_TIMER(timer3,"Molecule::BuildStretchModeTorsion 3","", TAU_FIELD);
6278  TAU_PROFILE_TIMER(timer4,"Molecule::BuildStretchModeTorsion 4","", TAU_FIELD);
6279  TAU_PROFILE_TIMER(timer5,"Molecule::BuildStretchModeTorsion 5","", TAU_FIELD);
6280  this->BuildConnectivityTable();
6281  mvStretchModeTorsion.clear();
6282  // Build list of atoms moved when changing the angle. Only keep the group
6283  // of atoms on the smaller side.
6284  for(unsigned long i=0;i<mvpBond.size();++i)
6285  {
6286  //if((mFlexModel.GetChoice()!=0)&&(false==mvpBond[i]->IsFreeTorsion())) continue;
6287  MolAtom* const atom1=&(mvpBond[i]->GetAtom1());
6288  MolAtom* const atom2=&(mvpBond[i]->GetAtom2());
6289  for(unsigned int j=1;j<=2;++j)
6290  {
6291  const set<MolAtom*> *pConn;
6292  if(j==1) pConn=&(mConnectivityTable[atom1]);
6293  else pConn=&(mConnectivityTable[atom2]);
6294  mvStretchModeTorsion.push_back(StretchModeTorsion(*atom1,*atom2,0));
6295  mvStretchModeTorsion.back().mvRotatedAtomList.insert(atom1);
6296  mvStretchModeTorsion.back().mvRotatedAtomList.insert(atom2);
6297 
6298  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
6299  {
6300  if((*pos==atom2)||(*pos==atom1)) continue;
6302  mvStretchModeTorsion.back().mvRotatedAtomList);
6303  }
6304  mvStretchModeTorsion.back().mvRotatedAtomList.erase(atom1);
6305  mvStretchModeTorsion.back().mvRotatedAtomList.erase(atom2);
6306 
6307  for(vector<MolDihedralAngle*>::const_iterator dih=mvpDihedralAngle.begin();dih!=mvpDihedralAngle.end();++dih)
6308  {
6309  // :TODO: There are some other weird cases to take into account,
6310  // for restraints with atoms *not* connected to another
6311  // More generally, should check the list of atoms rotated.
6312  if( ((&((*dih)->GetAtom2())==atom1) && (&((*dih)->GetAtom3())==atom2))
6313  ||((&((*dih)->GetAtom3())==atom1) && (&((*dih)->GetAtom2())==atom2)))
6314  {
6315  const unsigned long ct1=mvStretchModeTorsion.back().mvRotatedAtomList.count(&((*dih)->GetAtom1()));
6316  const unsigned long ct4=mvStretchModeTorsion.back().mvRotatedAtomList.count(&((*dih)->GetAtom4()));
6317 
6318  if((ct1+ct4)==1)// One of the atom is rotated, not the other
6319  {
6320  mvStretchModeTorsion.back().mpDihedralAngle=*dih;
6321  //:TODO: Check sense of rotation !
6322  if(ct4==1)
6323  {
6324  mvStretchModeTorsion.back().mpAtom1=&((*dih)->GetAtom2());
6325  mvStretchModeTorsion.back().mpAtom2=&((*dih)->GetAtom3());
6326  }
6327  else
6328  {
6329  mvStretchModeTorsion.back().mpAtom1=&((*dih)->GetAtom3());
6330  mvStretchModeTorsion.back().mpAtom2=&((*dih)->GetAtom2());
6331  }
6332  }
6333  }
6334  }
6335 
6336  if(mvStretchModeTorsion.size()>1)
6337  {//Duplicate ?
6338  // Does not work with a const_reverse_iterator ?
6339  // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729
6340  list<StretchModeTorsion>::reverse_iterator mode=mvStretchModeTorsion.rbegin();
6341  ++mode;
6342  for(;mode!=mvStretchModeTorsion.rend();++mode)
6343  {
6344  if( ( ((mode->mpAtom1==atom1)&&(mode->mpAtom2==atom2))
6345  ||((mode->mpAtom1==atom2)&&(mode->mpAtom2==atom1)))
6346  &&(mode->mvRotatedAtomList==mvStretchModeTorsion.back().mvRotatedAtomList))
6347  {
6348  #ifdef __DEBUG__
6349  cout<<"Duplicate StretchModeTorsion ";mvStretchModeTorsion.back().Print(cout);cout<<endl;
6350  #endif
6351  mvStretchModeTorsion.pop_back();
6352  }
6353  }
6354  }
6355  if( (mvStretchModeTorsion.back().mvRotatedAtomList.size()>((mvpAtom.size()+1)/2))
6356  ||(mvStretchModeTorsion.back().mvRotatedAtomList.size()==0))
6357  {
6358  #ifdef __DEBUG__
6359  cout<<"Rejecting StretchModeTorsion ";mvStretchModeTorsion.back().Print(cout);cout<<endl;
6360  #endif
6361  mvStretchModeTorsion.pop_back();
6362  }
6363  else if(mvStretchModeTorsion.back().mvRotatedAtomList.size()==((mvpAtom.size()+1)/2))
6364  break;//we translate exactly half of the atoms, so skip the other half
6365  }
6366  }
6367  for(unsigned long i=0;i<mvpBond.size();++i)
6368  {//Single chains
6369  //if((mFlexModel.GetChoice()!=0)&&(false==mvpBond[i]->IsFreeTorsion())) continue;
6370  MolAtom* const atom1=&(mvpBond[i]->GetAtom1());
6371  MolAtom* const atom2=&(mvpBond[i]->GetAtom2());
6372  for(unsigned int j=1;j<=2;++j)
6373  {
6374  const set<MolAtom*> *pConn;
6375  if(j==1) pConn=&(mConnectivityTable[atom1]);
6376  else pConn=&(mConnectivityTable[atom2]);
6377 
6378  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
6379  {
6380  if((*pos==atom2)||(*pos==atom1)) continue;
6381  mvStretchModeTorsion.push_back(StretchModeTorsion(*atom1,*atom2,0));
6382  mvStretchModeTorsion.back().mvRotatedAtomList.insert(atom1);
6383  mvStretchModeTorsion.back().mvRotatedAtomList.insert(atom2);
6385  mvStretchModeTorsion.back().mvRotatedAtomList);
6386  mvStretchModeTorsion.back().mvRotatedAtomList.erase(atom1);
6387  mvStretchModeTorsion.back().mvRotatedAtomList.erase(atom2);
6388 
6389  for(vector<MolDihedralAngle*>::const_iterator dih=mvpDihedralAngle.begin();dih!=mvpDihedralAngle.end();++dih)
6390  {
6391  // :TODO: There are some other weird cases to take into account,
6392  // for restraints with atoms *not* connected to another
6393  // More generally, should check the list of atoms rotated.
6394  if( ((&((*dih)->GetAtom2())==atom1) && (&((*dih)->GetAtom3())==atom2))
6395  ||((&((*dih)->GetAtom3())==atom1) && (&((*dih)->GetAtom2())==atom2)))
6396  {
6397  const unsigned long ct1=mvStretchModeTorsion.back().mvRotatedAtomList.count(&((*dih)->GetAtom1()));
6398  const unsigned long ct4=mvStretchModeTorsion.back().mvRotatedAtomList.count(&((*dih)->GetAtom4()));
6399 
6400  if((ct1+ct4)==1)// One of the atom is rotated, not the other
6401  {
6402  mvStretchModeTorsion.back().mpDihedralAngle=*dih;
6403  //:TODO: Check sense of rotation !
6404  if(ct4==1)
6405  {
6406  mvStretchModeTorsion.back().mpAtom1=&((*dih)->GetAtom2());
6407  mvStretchModeTorsion.back().mpAtom2=&((*dih)->GetAtom3());
6408  }
6409  else
6410  {
6411  mvStretchModeTorsion.back().mpAtom1=&((*dih)->GetAtom3());
6412  mvStretchModeTorsion.back().mpAtom2=&((*dih)->GetAtom2());
6413  }
6414  }
6415  }
6416  }
6417 
6418  if(mvStretchModeTorsion.size()>1)
6419  {//Duplicate ?
6420  // Does not work with a const_reverse_iterator ?
6421  // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729
6422  list<StretchModeTorsion>::reverse_iterator mode=mvStretchModeTorsion.rbegin();
6423  ++mode;
6424  for(;mode!=mvStretchModeTorsion.rend();++mode)
6425  {
6426  if( ( ((mode->mpAtom1==atom1)&&(mode->mpAtom2==atom2))
6427  ||((mode->mpAtom1==atom2)&&(mode->mpAtom2==atom1)))
6428  &&(mode->mvRotatedAtomList==mvStretchModeTorsion.back().mvRotatedAtomList))
6429  {
6430  #ifdef __DEBUG__
6431  cout<<"Duplicate StretchModeTorsion ";mvStretchModeTorsion.back().Print(cout);cout<<endl;
6432  #endif
6433  mvStretchModeTorsion.pop_back();
6434  break;
6435  }
6436  }
6437  }
6438  if( (mvStretchModeTorsion.back().mvRotatedAtomList.size()>((mvpAtom.size()+1)/2))
6439  ||(mvStretchModeTorsion.back().mvRotatedAtomList.size()==0))
6440  {
6441  #ifdef __DEBUG__
6442  cout<<"Rejecting StretchModeTorsion ";mvStretchModeTorsion.back().Print(cout);cout<<endl;
6443  #endif
6444  mvStretchModeTorsion.pop_back();
6445  }
6446  else if(mvStretchModeTorsion.back().mvRotatedAtomList.size()==((mvpAtom.size()+1)/2))
6447  break;//we translate exactly half of the atoms, so skip the other half
6448  }
6449  }
6450  }
6451  // find rigid groups broken by each mode
6452  for(list<StretchModeTorsion>::iterator pos=mvStretchModeTorsion.begin();
6453  pos!=mvStretchModeTorsion.end();)
6454  {
6455  TAU_PROFILE_START(timer5);
6456  bool keep=true;
6457  for(vector<RigidGroup*>::const_iterator group=mvRigidGroup.begin();
6458  group!=mvRigidGroup.end();++group)
6459  {
6460  unsigned long ct=0;
6461  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
6462  ct += pos->mvRotatedAtomList.count(*at);
6463  if(ct>0)
6464  {
6465  // Add the axis atoms, which do not move relatively to the rotated atoms
6466  ct += (*group)->count(pos->mpAtom1);
6467  ct += (*group)->count(pos->mpAtom2);
6468  if(ct!=(*group)->size())
6469  {
6470  keep=false;
6471  #ifdef __DEBUG__
6472  pos->Print(cout);
6473  cout<<" Breaks Rigid Group:";
6474  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
6475  cout<<(*at)->GetName()<<" ";
6476  cout<<endl;
6477  #endif
6478  break;
6479  }
6480  }
6481  }
6482  if(keep) ++pos;
6483  else pos=mvStretchModeTorsion.erase(pos);
6484  TAU_PROFILE_STOP(timer5);
6485  }
6486  // Generate 5 completely random atomic positions
6487  this->SaveParamSet(mLocalParamSet);
6488  unsigned long paramSetRandom[5];
6489  for(unsigned long i=0;i<5;++i)
6490  {
6491  for(vector<MolAtom*>::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
6492  {
6493  (*pos)->SetX(100.*rand()/(REAL) RAND_MAX);
6494  (*pos)->SetY(100.*rand()/(REAL) RAND_MAX);
6495  (*pos)->SetZ(100.*rand()/(REAL) RAND_MAX);
6496  }
6497  paramSetRandom[i]=this->CreateParamSet();
6498  }
6499  // find bond lengths broken by each mode
6500  for(list<StretchModeTorsion>::iterator pos=mvStretchModeTorsion.begin();
6501  pos!=mvStretchModeTorsion.end();)
6502  {
6503  TAU_PROFILE_START(timer2);
6504  bool keep=true;
6505  pos->mvpBrokenBond.clear();
6506  for(vector<MolBond*>::const_iterator r=mvpBond.begin();r!=mvpBond.end();++r)
6507  {
6508  unsigned int ct=0;
6509  for(set<MolAtom *>::const_iterator at=pos->mvRotatedAtomList.begin();
6510  at!=pos->mvRotatedAtomList.end();++at)
6511  {
6512  if(*at==&((*r)->GetAtom1())) ct++;
6513  if(*at==&((*r)->GetAtom2())) ct++;
6514  }
6515  bool broken=true;
6516  // If we moved either both or non of the bond atom, the bond length is unchanged.
6517  if((ct==0)||(ct==2)) broken=false;
6518  if(broken)
6519  {// Make sure with derivatives
6520  REAL d=0;
6521  for(unsigned long i=0;i<5;++i)
6522  {
6523  this->RestoreParamSet(paramSetRandom[i]);
6524  pos->CalcDeriv(false);
6525  (*r)->GetLogLikelihood(true,true);
6526  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6527  if(d>0.01) break;
6528  }
6529  if(abs(d)<=0.01) broken=false;
6530  }
6531  if(broken) pos->mvpBrokenBond.insert(make_pair(*r,0));
6532  }
6533  if(mFlexModel.GetChoice()==2)
6534  {
6535  if(pos->mvpBrokenBond.size()>0) keep=false;
6536  }
6537  if(keep) ++pos;
6538  else pos=mvStretchModeTorsion.erase(pos);
6539  TAU_PROFILE_STOP(timer2);
6540  }
6541  // find bond angles broken by each mode
6542  for(list<StretchModeTorsion>::iterator pos=mvStretchModeTorsion.begin();
6543  pos!=mvStretchModeTorsion.end();)
6544  {
6545  TAU_PROFILE_START(timer3);
6546  bool keep=true;
6547  pos->mvpBrokenBondAngle.clear();
6548  for(vector<MolBondAngle*>::const_iterator r=mvpBondAngle.begin();r!=mvpBondAngle.end();++r)
6549  {
6550  unsigned int ct=0;
6551  for(set<MolAtom *>::const_iterator at=pos->mvRotatedAtomList.begin();
6552  at!=pos->mvRotatedAtomList.end();++at)
6553  {
6554  if(*at==&((*r)->GetAtom1())) ct++;
6555  if(*at==&((*r)->GetAtom2())) ct++;
6556  if(*at==&((*r)->GetAtom3())) ct++;
6557  }
6558  bool broken=true;
6559  if((ct==0)||(ct==3)) broken=false;
6560  if(broken)
6561  {// Make sure with derivatives
6562  REAL d=0;
6563  for(unsigned long i=0;i<5;++i)
6564  {
6565  this->RestoreParamSet(paramSetRandom[i]);
6566  pos->CalcDeriv(false);
6567  (*r)->GetLogLikelihood(true,true);
6568  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6569  if(d>0.01) break;
6570  }
6571  if(abs(d)<=0.01) broken=false;
6572  }
6573  if(broken) pos->mvpBrokenBondAngle.insert(make_pair(*r,0));
6574  }
6575  if(mFlexModel.GetChoice()==2)
6576  {
6577  if(pos->mvpBrokenBond.size()>0) keep=false;
6578  }
6579  if(keep) ++pos;
6580  else pos=mvStretchModeTorsion.erase(pos);
6581  TAU_PROFILE_STOP(timer3);
6582  }
6583  // find dihedral angles broken by each mode
6584  for(list<StretchModeTorsion>::iterator pos=mvStretchModeTorsion.begin();
6585  pos!=mvStretchModeTorsion.end();)
6586  {
6587  TAU_PROFILE_START(timer4);
6588  bool keep=true;
6589  pos->mvpBrokenDihedralAngle.clear();
6590  for(vector<MolDihedralAngle*>::const_iterator r=mvpDihedralAngle.begin();r!=mvpDihedralAngle.end();++r)
6591  {
6592  unsigned int ct=0;
6593  for(set<MolAtom *>::const_iterator at=pos->mvRotatedAtomList.begin();
6594  at!=pos->mvRotatedAtomList.end();++at)
6595  {
6596  if(*at==&((*r)->GetAtom1())) ct++;
6597  if(*at==&((*r)->GetAtom2())) ct++;
6598  if(*at==&((*r)->GetAtom3())) ct++;
6599  if(*at==&((*r)->GetAtom4())) ct++;
6600  }
6601  bool broken=true;
6602  if((ct==0)||(ct==4)) broken=false;
6603  if(broken)
6604  {// Make sure with derivatives
6605  REAL d=0;
6606  for(unsigned long i=0;i<5;++i)
6607  {
6608  this->RestoreParamSet(paramSetRandom[i]);
6609  pos->CalcDeriv(false);
6610  (*r)->GetLogLikelihood(true,true);
6611  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6612  if(d>0.01) break;
6613  }
6614  if(abs(d)<=0.01) broken=false;
6615  }
6616  if(broken) pos->mvpBrokenDihedralAngle.insert(make_pair(*r,0));
6617  }
6618  if(mFlexModel.GetChoice()==2)
6619  {
6620  int nb=pos->mvpBrokenDihedralAngle.size();
6621  if(pos->mpDihedralAngle!=0) nb -= 1;
6622  if(nb>0) keep=false;
6623  }
6624  if(keep) ++pos;
6625  else pos=mvStretchModeTorsion.erase(pos);
6626  TAU_PROFILE_STOP(timer4);
6627  }
6628 
6629  for(unsigned long i=0;i<5;++i) this->ClearParamSet(paramSetRandom[i]);
6630  this->RestoreParamSet(mLocalParamSet);
6631 
6632  #ifdef __DEBUG__
6633  cout<<"List of Dihedral Angle stretch modes("<<mvStretchModeTorsion.size()<<")"<<endl;
6634  for(list<StretchModeTorsion>::const_iterator pos=mvStretchModeTorsion.begin();
6635  pos!=mvStretchModeTorsion.end();++pos)
6636  {
6637  cout<<" Dihedral Angle:"
6638  <<pos->mpAtom1->GetName()<<"-"
6639  <<pos->mpAtom2->GetName()<<", Rotated Atoms: ";
6640  for(set<MolAtom*>::const_iterator atom=pos->mvRotatedAtomList.begin();
6641  atom!=pos->mvRotatedAtomList.end();++atom)
6642  {
6643  cout<<(*atom)->GetName()<<",";
6644  }
6645  if(pos->mpDihedralAngle!=0)
6646  cout<<endl<< " ->restrained by dihedral angle "<<pos->mpDihedralAngle->GetName()
6647  <<"to :"<<pos->mpDihedralAngle->GetAngle0()*RAD2DEG
6648  <<"�, sigma="<<pos->mpDihedralAngle->GetAngleSigma()*RAD2DEG
6649  <<"�, delta="<<pos->mpDihedralAngle->GetAngleDelta()*RAD2DEG<<"�";
6650  if(pos->mvpBrokenBond.size()>0)
6651  {
6652  cout<<endl<<" Broken bonds:";
6653  for(map<const MolBond*,REAL>::const_iterator bond=pos->mvpBrokenBond.begin();
6654  bond!=pos->mvpBrokenBond.end();++bond)
6655  cout<<bond->first->GetName()<<", ";
6656  }
6657  if(pos->mvpBrokenBondAngle.size()>0)
6658  {
6659  cout<<endl<<" Broken bond angles:";
6660  for(map<const MolBondAngle*,REAL>::const_iterator angle=pos->mvpBrokenBondAngle.begin();
6661  angle!=pos->mvpBrokenBondAngle.end();++angle)
6662  cout<<angle->first->GetName()<<", ";
6663  }
6664  if(pos->mvpBrokenDihedralAngle.size()>0)
6665  {
6666  cout<<endl<<" Broken dihedral angles:";
6667  for(map<const MolDihedralAngle*,REAL>::const_iterator
6668  angle=pos->mvpBrokenDihedralAngle.begin();
6669  angle!=pos->mvpBrokenDihedralAngle.end();++angle)
6670  cout<<angle->first->GetName()<<", ";
6671  }
6672  cout<<endl;
6673  }
6674  #endif
6675  mClockStretchModeTorsion.Click();
6676  VFN_DEBUG_EXIT("Molecule::BuildStretchModeTorsion()",7)
6677 }
6678 
6680 {
6681  #if 0
6682  if( (mClockStretchModeTwist>mClockBondList)
6683  &&(mClockStretchModeTwist>mClockAtomList)
6684  &&(mClockStretchModeTwist>mClockBondAngleList)
6685  &&(mClockStretchModeTwist>mClockDihedralAngleList)) return;
6686  #endif
6687  VFN_DEBUG_ENTRY("Molecule::BuildStretchModeTwist()",7)
6688  this->BuildConnectivityTable();
6689  mvStretchModeTwist.clear();
6690 
6691  // For each pair of atoms, build an internal chain to twist.
6692  for(vector<MolAtom*>::const_iterator atom1=this->GetAtomList().begin();
6693  atom1!=this->GetAtomList().end();++atom1)
6694  {
6695  const set<MolAtom*> *pConn=&(mConnectivityTable[*atom1]);
6696  vector<MolAtom*>::const_iterator atom2=atom1;
6697  atom2++;
6698  for(;atom2!=this->GetAtomList().end();++atom2)
6699  {
6700  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
6701  {// Start from one atom connected to atom1
6702  if(*pos==*atom2) continue;
6703  mvStretchModeTwist.push_back(StretchModeTwist(**atom1,**atom2));
6704  mvStretchModeTwist.back().mvRotatedAtomList.insert(*atom1);
6706  mvStretchModeTwist.back().mvRotatedAtomList,
6707  *atom2);
6708  //Check if this chains actually leads to atom2
6709  set<MolAtom*>::const_iterator check
6710  =find(mvStretchModeTwist.back().mvRotatedAtomList.begin(),
6711  mvStretchModeTwist.back().mvRotatedAtomList.end(),*atom2);
6712  bool keep =true;
6713  if( (check==mvStretchModeTwist.back().mvRotatedAtomList.end())
6714  ||(mvStretchModeTwist.back().mvRotatedAtomList.size()<3)
6715  ||(mvStretchModeTwist.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2)))
6716  {
6717  keep=false;
6718  }
6719  if(keep)
6720  {
6721  mvStretchModeTwist.back().mvRotatedAtomList.erase(*atom1);
6722  mvStretchModeTwist.back().mvRotatedAtomList.erase(*atom2);
6723  if( (mvStretchModeTwist.back().mvRotatedAtomList.size()>=(mvpAtom.size()/2))
6724  ||(mvStretchModeTwist.back().mvRotatedAtomList.size()==0))
6725  {
6726  #ifdef __DEBUG__
6727  cout<<"Rejecting StretchModeTwist ";mvStretchModeTwist.back().Print(cout);cout<<endl;
6728  #endif
6729  keep=false;
6730  }
6731  }
6732  if(keep)
6733  {
6734  if(mvStretchModeTwist.size()>1)
6735  {//Duplicate ?
6736  // Does not work with a const_reverse_iterator ?
6737  // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729
6738  list<StretchModeTwist>::reverse_iterator mode=mvStretchModeTwist.rbegin();
6739  ++mode;
6740  for(;mode!=mvStretchModeTwist.rend();++mode)
6741  {
6742  if( ( ((mode->mpAtom1==*atom1)&&(mode->mpAtom2==*atom2))
6743  ||((mode->mpAtom1==*atom2)&&(mode->mpAtom2==*atom1)))
6744  &&(mode->mvRotatedAtomList==mvStretchModeTwist.back().mvRotatedAtomList))
6745  {
6746  #ifdef __DEBUG__
6747  cout<<"Duplicate StretchModeTwist ";mvStretchModeTwist.back().Print(cout);cout<<endl;
6748  #endif
6749  keep=false;
6750  }
6751  if(!keep) break;
6752  }
6753  }
6754  }
6755  if(keep)
6756  {
6757  if(mvStretchModeTorsion.size()>0) // Torsion and twist modes can be identical for cycles.
6758  {//Duplicate ?
6759  // Does not work with a const_reverse_iterator ?
6760  // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729
6761  list<StretchModeTorsion>::reverse_iterator mode;
6762  for(mode=mvStretchModeTorsion.rbegin();mode!=mvStretchModeTorsion.rend();++mode)
6763  {
6764  if( ( ((mode->mpAtom1==*atom1)&&(mode->mpAtom2==*atom2))
6765  ||((mode->mpAtom1==*atom2)&&(mode->mpAtom2==*atom1)))
6766  &&(mode->mvRotatedAtomList==mvStretchModeTwist.back().mvRotatedAtomList))
6767  {
6768  #ifdef __DEBUG__
6769  cout<<"Duplicate StretchModeTwist (with Torsion) ";mvStretchModeTwist.back().Print(cout);cout<<endl;
6770  #endif
6771  keep=false;
6772  }
6773  if(!keep) break;
6774  }
6775  }
6776  }
6777  if(!keep) mvStretchModeTwist.pop_back();
6778  }
6779  }
6780 
6781  }
6782  // Generate 5 completely random atomic positions
6783  this->SaveParamSet(mLocalParamSet);
6784  unsigned long paramSetRandom[5];
6785  for(unsigned long i=0;i<5;++i)
6786  {
6787  for(vector<MolAtom*>::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
6788  {
6789  (*pos)->SetX(100.*rand()/(REAL) RAND_MAX);
6790  (*pos)->SetY(100.*rand()/(REAL) RAND_MAX);
6791  (*pos)->SetZ(100.*rand()/(REAL) RAND_MAX);
6792  }
6793  paramSetRandom[i]=this->CreateParamSet();
6794  }
6795  // find bond, bond angles and dihedral angles broken by each mode
6796  for(list<StretchModeTwist>::iterator pos=mvStretchModeTwist.begin();
6797  pos!=mvStretchModeTwist.end();)
6798  {
6799  pos->mvpBrokenBond.clear();
6800  pos->mvpBrokenBondAngle.clear();
6801  pos->mvpBrokenDihedralAngle.clear();
6802  pos->CalcDeriv();
6803  #ifdef __DEBUG__
6804  cout<<" DerivLLK for Twist mode around:"
6805  <<pos->mpAtom1->GetName()<<"-"
6806  <<pos->mpAtom2->GetName()<<": Moving atoms:";
6807  for(set<MolAtom*>::const_iterator atom=pos->mvRotatedAtomList.begin();
6808  atom!=pos->mvRotatedAtomList.end();++atom)
6809  cout<<(*atom)->GetName()<<",";
6810  cout<<endl;
6811  #endif
6812  for(vector<MolBond*>::const_iterator r=mvpBond.begin();r!=mvpBond.end();++r)
6813  {
6814  (*r)->GetLogLikelihood(true,true);
6815  REAL d=0;
6816  for(unsigned long i=0;i<5;++i)
6817  {
6818  this->RestoreParamSet(paramSetRandom[i]);
6819  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6820  }
6821  if(abs(d)>0.1)
6822  {
6823  #ifdef __DEBUG__
6824  cout<<" Bond "<<(*r)->GetName()
6825  <<": dLength/da="<<d<<endl;
6826  #endif
6827  pos->mvpBrokenBond.insert(make_pair(*r,0.0));
6828  }
6829  }
6830  for(vector<MolBondAngle*>::const_iterator r=mvpBondAngle.begin();r!=mvpBondAngle.end();++r)
6831  {
6832  (*r)->GetLogLikelihood(true,true);
6833  REAL d=0;
6834  for(unsigned long i=0;i<5;++i)
6835  {
6836  this->RestoreParamSet(paramSetRandom[i]);
6837  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6838  }
6839  if(abs(d)>0.01)
6840  {
6841  #ifdef __DEBUG__
6842  cout<<" BondAngle:"<<(*r)->GetName()<<": dAngle/da="<<d<<endl;
6843  #endif
6844  pos->mvpBrokenBondAngle.insert(make_pair(*r,0.0));
6845  }
6846  }
6847  for(vector<MolDihedralAngle*>::const_iterator r=mvpDihedralAngle.begin();
6848  r!=mvpDihedralAngle.end();++r)
6849  {
6850  //if(*r==pos->mpDihedralAngle) continue;
6851  (*r)->GetLogLikelihood(true,true);
6852  REAL d=0;
6853  for(unsigned long i=0;i<5;++i)
6854  {
6855  this->RestoreParamSet(paramSetRandom[i]);
6856  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6857  }
6858  if(abs(d)>0.01)
6859  {
6860  #ifdef __DEBUG__
6861  cout<<" DihedralAngle:"<<(*r)->GetName()<<": dAngle/da="<<d<<endl;
6862  #endif
6863  pos->mvpBrokenDihedralAngle.insert(make_pair(*r,0.0));
6864  }
6865  }
6866  //Get rid of stretch modes that break rigid groups
6867  bool keep=true;
6868  for(vector<RigidGroup*>::const_iterator group=mvRigidGroup.begin();
6869  group!=mvRigidGroup.end();++group)
6870  {
6871  unsigned long ct=0;
6872  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
6873  ct += pos->mvRotatedAtomList.count(*at);
6874  if(ct>0)
6875  {
6876  // Add atom1 and atom2 to the count only if they are in the group
6877  // They do not move in absolute or relatively to the group.
6878  ct += (*group)->count(pos->mpAtom1);
6879  ct += (*group)->count(pos->mpAtom2);
6880  if(ct!=(*group)->size())
6881  {
6882  keep=false;
6883  #ifdef __DEBUG__
6884  cout<<" Breaks Rigid Group:"<<ct<<"!="<<(*group)->size()<<":";
6885  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
6886  cout<<(*at)->GetName()<<" ";
6887  cout<<endl;
6888  #endif
6889  break;
6890  }
6891  }
6892  }
6893  if(mFlexModel.GetChoice()==2)
6894  {
6895  if(pos->mvpBrokenBond.size()+pos->mvpBrokenBondAngle.size()+pos->mvpBrokenDihedralAngle.size()) keep=false;
6896  }
6897  if(keep) ++pos;
6898  else pos=mvStretchModeTwist.erase(pos);
6899  }
6900  for(unsigned long i=0;i<5;++i) this->ClearParamSet(paramSetRandom[i]);
6901  this->RestoreParamSet(mLocalParamSet);
6902 
6903  #ifdef __DEBUG__
6904  cout<<"List of Twist stretch modes("<<mvStretchModeTwist.size()<<")"<<endl;
6905  for(list<StretchModeTwist>::const_iterator pos=mvStretchModeTwist.begin();
6906  pos!=mvStretchModeTwist.end();++pos)
6907  {
6908  cout<<" Twist mode:"
6909  <<pos->mpAtom1->GetName()<<"-"
6910  <<pos->mpAtom2->GetName()<<", Rotated Atoms: ";
6911  for(set<MolAtom*>::const_iterator atom=pos->mvRotatedAtomList.begin();
6912  atom!=pos->mvRotatedAtomList.end();++atom)
6913  {
6914  cout<<(*atom)->GetName()<<",";
6915  }
6916  if(pos->mvpBrokenBond.size()>0)
6917  {
6918  cout<<endl<<" Broken bonds:";
6919  for(map<const MolBond*,REAL>::const_iterator bond=pos->mvpBrokenBond.begin();
6920  bond!=pos->mvpBrokenBond.end();++bond)
6921  cout<<bond->first->GetName()<<", ";
6922  }
6923  if(pos->mvpBrokenBondAngle.size()>0)
6924  {
6925  cout<<endl<<" Broken bond angles:";
6926  for(map<const MolBondAngle*,REAL>::const_iterator angle=pos->mvpBrokenBondAngle.begin();
6927  angle!=pos->mvpBrokenBondAngle.end();++angle)
6928  cout<<angle->first->GetName()<<", ";
6929  }
6930  if(pos->mvpBrokenDihedralAngle.size()>0)
6931  {
6932  cout<<endl<<" Broken dihedral angles:";
6933  for(map<const MolDihedralAngle*,REAL>::const_iterator
6934  angle=pos->mvpBrokenDihedralAngle.begin();
6935  angle!=pos->mvpBrokenDihedralAngle.end();++angle)
6936  cout<<angle->first->GetName()<<", ";
6937  }
6938  cout<<endl;
6939  }
6940  #endif
6941  mClockStretchModeTwist.Click();
6942  VFN_DEBUG_EXIT("Molecule::BuildStretchModeTwist()",7)
6943 }
6944 
6946 {
6947  VFN_DEBUG_ENTRY("Molecule::TuneGlobalOptimRotationAmplitude()",5)
6948  unsigned long initialConfig=this->CreateParamSet("Initial Configuration");
6949  const unsigned int nbTest=100;
6950 
6951  // First we store in mBaseRotationAmplitude the cumulated atomic displacement
6952  // for nbTest rotations of 0.01 rad
6953  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
6954  pos!=mvStretchModeBondAngle.end();++pos) pos->mBaseAmplitude=0;
6955  for(list<StretchModeTorsion>::iterator pos=mvStretchModeTorsion.begin();
6956  pos!=mvStretchModeTorsion.end();++pos) pos->mBaseAmplitude=0;
6957 
6958  REAL displacement=0;//For the global Molecule rotation
6959 
6960  for(unsigned int j=0;j<nbTest;j++)
6961  {
6962  this->RandomizeConfiguration();
6963  // Atomic positions, orthonormal coordinates
6964  vector<REAL> x0(this->GetNbComponent());
6965  vector<REAL> y0(this->GetNbComponent());
6966  vector<REAL> z0(this->GetNbComponent());
6967  // Center of molecule coords
6968  REAL xc=0.,yc=0.,zc=0.;
6969  for(long i=0;i<this->GetNbComponent();++i)
6970  {
6971  x0[i]=mvpAtom[i]->GetX(); xc += x0[i];
6972  y0[i]=mvpAtom[i]->GetY(); yc += y0[i];
6973  z0[i]=mvpAtom[i]->GetZ(); zc += z0[i];
6974  }
6975  xc /= (REAL)(this->GetNbComponent());
6976  yc /= (REAL)(this->GetNbComponent());
6977  zc /= (REAL)(this->GetNbComponent());
6978  // Record displacement amplitude for torsion angles
6979  REAL dx,dy,dz;
6980  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
6981  pos!=mvStretchModeBondAngle.end();++pos)
6982  {
6983  const REAL dx10=pos->mpAtom0->GetX()-pos->mpAtom1->GetX();
6984  const REAL dy10=pos->mpAtom0->GetY()-pos->mpAtom1->GetY();
6985  const REAL dz10=pos->mpAtom0->GetZ()-pos->mpAtom1->GetZ();
6986  const REAL dx12=pos->mpAtom2->GetX()-pos->mpAtom1->GetX();
6987  const REAL dy12=pos->mpAtom2->GetY()-pos->mpAtom1->GetY();
6988  const REAL dz12=pos->mpAtom2->GetZ()-pos->mpAtom1->GetZ();
6989 
6990  const REAL vx=dy10*dz12-dz10*dy12;
6991  const REAL vy=dz10*dx12-dx10*dz12;
6992  const REAL vz=dx10*dy12-dy10*dx12;
6993  this->RotateAtomGroup(*(pos->mpAtom1),vx,vy,vz,pos->mvRotatedAtomList,0.01,false);
6994  for(long i=0;i<this->GetNbComponent();++i)
6995  {
6996  dx=x0[i]-mvpAtom[i]->GetX();
6997  dy=y0[i]-mvpAtom[i]->GetY();
6998  dz=z0[i]-mvpAtom[i]->GetZ();
6999  pos->mBaseAmplitude+=sqrt(abs(dx*dx+dy*dy+dz*dz));
7000  }
7001  this->RotateAtomGroup(*(pos->mpAtom1),vx,vy,vz,pos->mvRotatedAtomList,-0.01,false);
7002  }
7003  for(list<StretchModeTorsion>::iterator pos=mvStretchModeTorsion.begin();
7004  pos!=mvStretchModeTorsion.end();++pos)
7005  {
7006  this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),pos->mvRotatedAtomList,0.01,false);
7007  for(long i=0;i<this->GetNbComponent();++i)
7008  {
7009  dx=x0[i]-mvpAtom[i]->GetX();
7010  dy=y0[i]-mvpAtom[i]->GetY();
7011  dz=z0[i]-mvpAtom[i]->GetZ();
7012  pos->mBaseAmplitude+=sqrt(abs(dx*dx+dy*dy+dz*dz));
7013  }
7014  this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),pos->mvRotatedAtomList,-0.01,false);
7015  }
7016  // Record displacement amplitude for global rotation, for 10 random rot axis
7017  for(unsigned int k=0;k<10;++k)
7018  {
7020  (mBaseRotationAmplitude,(REAL)rand(),(REAL)rand(),(REAL)rand());
7021  for(long i=0;i<this->GetNbComponent();++i)
7022  {
7023  REAL x=x0[i]-xc;
7024  REAL y=y0[i]-yc;
7025  REAL z=z0[i]-zc;
7026  quat.RotateVector(x,y,z);
7027  dx=(x0[i]-xc)-x;
7028  dy=(y0[i]-yc)-y;
7029  dz=(z0[i]-zc)-z;
7030  displacement+=sqrt(abs(dx*dx+dy*dy+dz*dz));
7031  }
7032  }
7033  }
7034  // Modify base rotation amplitudes, for an average 0.02 Angstroem displacement
7035  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
7036  pos!=mvStretchModeBondAngle.end();++pos)
7037  {
7038  pos->mBaseAmplitude/=(REAL)(nbTest*this->GetNbComponent());//(REAL)(nbTest*(0.5*pos->mvRotatedAtomList.size()+0.5*this->GetNbComponent()));
7039  pos->mBaseAmplitude=0.1*0.01/pos->mBaseAmplitude;
7040  if(pos->mBaseAmplitude>.17) pos->mBaseAmplitude=.17;
7041  bool free=true;
7042  if((pos->mvpBrokenBond.size()+pos->mvpBrokenBondAngle.size()+pos->mvpBrokenDihedralAngle.size())>0)
7043  {
7044  pos->mBaseAmplitude/=10;
7045  free=false;
7046  }
7047  #if 1// def __DEBUG__
7048  cout<<"ANGLE :"
7049  <<pos->mpAtom0->GetName()<<"-"
7050  <<pos->mpAtom1->GetName()<<"-"
7051  <<pos->mpAtom2->GetName()<<":";
7052  for(set<MolAtom*>::const_iterator atom=pos->mvRotatedAtomList.begin();
7053  atom!=pos->mvRotatedAtomList.end();++atom) cout<<(*atom)->GetName()<<",";
7054  cout <<": base rotation="<<pos->mBaseAmplitude*RAD2DEG<<" free="<<free<<endl;
7055  #endif
7056  }
7057  // Modify base rotation amplitudes, for an average 0.1 Angstroem displacement
7058  for(list<StretchModeTorsion>::iterator pos=mvStretchModeTorsion.begin();
7059  pos!=mvStretchModeTorsion.end();++pos)
7060  {
7061  pos->mBaseAmplitude/=(REAL)(nbTest*this->GetNbComponent());//(REAL)(nbTest*(0.5*pos->mvRotatedAtomList.size()+0.5*this->GetNbComponent()));
7062  pos->mBaseAmplitude=0.1*0.01/pos->mBaseAmplitude;
7063  if(pos->mBaseAmplitude>.17) pos->mBaseAmplitude=.17;
7064  bool free=true;
7065  if((pos->mvpBrokenBond.size()+pos->mvpBrokenBondAngle.size()+pos->mvpBrokenDihedralAngle.size())>0)
7066  {
7067  pos->mBaseAmplitude/=10;
7068  free=false;
7069  }
7070  #if 1// def __DEBUG__
7071  cout<<"TORSION :"
7072  <<pos->mpAtom1->GetName()<<"-"
7073  <<pos->mpAtom2->GetName()<<":";
7074  for(set<MolAtom*>::const_iterator atom=pos->mvRotatedAtomList.begin();
7075  atom!=pos->mvRotatedAtomList.end();++atom) cout<<(*atom)->GetName()<<",";
7076  cout <<": base rotation="<<pos->mBaseAmplitude*RAD2DEG<<" free="<<free<<endl;
7077  #endif
7078  }
7079  // Modify base rotation amplitudes of twist modes, for an average 0.1 Angstroem displacement
7080  for(list<StretchModeTwist>::iterator pos=mvStretchModeTwist.begin();
7081  pos!=mvStretchModeTwist.end();++pos)
7082  {
7083  pos->mBaseAmplitude/=(REAL)(nbTest*this->GetNbComponent());//(REAL)(nbTest*(0.5*pos->mvRotatedAtomList.size()+0.5*this->GetNbComponent()));
7084  pos->mBaseAmplitude=0.1*0.01/pos->mBaseAmplitude;
7085  if(pos->mBaseAmplitude>.17) pos->mBaseAmplitude=.17;
7086  bool free=true;
7087  if((pos->mvpBrokenBond.size()+pos->mvpBrokenBondAngle.size()+pos->mvpBrokenDihedralAngle.size())>0)
7088  {
7089  pos->mBaseAmplitude/=10;
7090  free=false;
7091  }
7092  #if 1// def __DEBUG__
7093  cout<<"TWIST :"
7094  <<pos->mpAtom1->GetName()<<"-"
7095  <<pos->mpAtom2->GetName()<<":";
7096  for(set<MolAtom*>::const_iterator atom=pos->mvRotatedAtomList.begin();
7097  atom!=pos->mvRotatedAtomList.end();++atom) cout<<(*atom)->GetName()<<",";
7098  cout <<": base rotation="<<pos->mBaseAmplitude*RAD2DEG<<" free="<<free<<endl;
7099  #endif
7100  }
7101  // Same for global rotation
7102  displacement/=(REAL)(10*nbTest*this->GetNbComponent());
7103  //cout<<"Overall Atomic Displacement for Global Rotation:<d>="<<displacement;
7104  if(displacement>0) mBaseRotationAmplitude*=0.1/displacement;
7105  if(mBaseRotationAmplitude<(0.02*M_PI/20.))
7106  {
7107  mBaseRotationAmplitude=0.02*M_PI/20.;
7108  //cout <<"WARNING - too low Global BaseRotationAmplitude - setting to: "
7109  // << mBaseAmplitude*RAD2DEG<< " �"<<endl;
7110  }
7111  if(mBaseRotationAmplitude>(0.02*M_PI*20.))
7112  {
7113  mBaseRotationAmplitude=0.02*M_PI*20.;
7114  //cout <<"WARNING - too high Global BaseRotationAmplitude - setting to: "
7115  // << mBaseAmplitude*RAD2DEG<< " �"<<endl;
7116  }
7117  //cout <<" -> Base rotation="<<mBaseAmplitude*RAD2DEG<<"�"<<endl;
7118 
7119  // Move back atoms to initial position
7120  this->RestoreParamSet(initialConfig);
7121  VFN_DEBUG_EXIT("Molecule::TuneGlobalOptimRotationAmplitude()",5)
7122 }
7123 
7125 {
7126  this->BuildConnectivityTable();
7127  if( (mClockFlipGroup>mClockConnectivityTable)
7128  &&(mClockFlipGroup>mClockRigidGroup)) return;
7129  VFN_DEBUG_ENTRY("Molecule::BuildFlipGroup()",5)
7130  TAU_PROFILE("Molecule::BuildFlipGroup()","void ()",TAU_DEFAULT);
7131  mvFlipGroup.clear();
7132 
7133  for(vector<MolAtom*>::const_iterator atom0=this->GetAtomList().begin();
7134  atom0!=this->GetAtomList().end();++atom0)
7135  {
7136  const set<MolAtom*> *pConn=&(mConnectivityTable[*atom0]);
7137  if(pConn->size()<3) continue;
7138  // Build all chains
7139  for(set<MolAtom*>::const_iterator pos1=pConn->begin();pos1!=pConn->end();++pos1)
7140  {
7141  for(set<MolAtom*>::const_iterator pos2=pos1;pos2!=pConn->end();++pos2)
7142  {
7143  if(*pos2==*pos1) continue;
7144  if(mFlexModel.GetChoice()==0)
7145  {
7146  mvFlipGroup.push_back(FlipGroup(**atom0,**pos1,**pos2));
7147  bool foundRing=false;
7148  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
7149  {
7150  if((pos==pos1)||(pos==pos2)) continue;
7151  mvFlipGroup.back().mvRotatedChainList.push_back(
7152  make_pair(*pos,set<MolAtom*>()));
7153  mvFlipGroup.back().mvRotatedChainList.back().second.insert(*atom0);
7155  mvFlipGroup.back().mvRotatedChainList.back().second);
7156  mvFlipGroup.back().mvRotatedChainList.back().second.erase(*atom0);
7157  set<MolAtom*>::const_iterator ringdetect1,ringdetect2;
7158  ringdetect1=find(mvFlipGroup.back().mvRotatedChainList.back().second.begin(),
7159  mvFlipGroup.back().mvRotatedChainList.back().second.end(),
7160  *pos1);
7161  ringdetect2=find(mvFlipGroup.back().mvRotatedChainList.back().second.begin(),
7162  mvFlipGroup.back().mvRotatedChainList.back().second.end(),
7163  *pos2);
7164  if( (ringdetect1!=mvFlipGroup.back().mvRotatedChainList.back().second.end())
7165  ||(ringdetect2!=mvFlipGroup.back().mvRotatedChainList.back().second.end()))
7166  foundRing=true;
7167  }
7168  unsigned long flipSize=0;
7169  for(list<pair<const MolAtom *,set<MolAtom*> > >::const_iterator
7170  chain=mvFlipGroup.back().mvRotatedChainList.begin();
7171  chain!=mvFlipGroup.back().mvRotatedChainList.end();++chain)
7172  flipSize+=chain->second.size();
7173 
7174  if(((flipSize*2)>mvpAtom.size())||foundRing) mvFlipGroup.pop_back();
7175  }
7176  // Add the entry which will exchange atom1 and atom2 (this entry can be a ring)
7177  mvFlipGroup.push_back(FlipGroup(**atom0,**pos1,**pos2));
7178  mvFlipGroup.back().mvRotatedChainList.push_back(
7179  make_pair(*atom0,set<MolAtom*>()));
7180  mvFlipGroup.back().mvRotatedChainList.back().second.insert(*atom0);
7182  mvFlipGroup.back().mvRotatedChainList.back().second);
7184  mvFlipGroup.back().mvRotatedChainList.back().second);
7185  mvFlipGroup.back().mvRotatedChainList.back().second.erase(*atom0);
7186  if((mvFlipGroup.back().mvRotatedChainList.back().second.size()*2)>mvpAtom.size())
7187  mvFlipGroup.pop_back();
7188  }
7189  }
7190  }
7191  // Exclude flip groups that include only a part of any rigid group
7192  for(list<FlipGroup>::iterator pos=mvFlipGroup.begin(); pos!=mvFlipGroup.end();)
7193  {
7194  // This should not be necessary ? Why keep one list for each chain, and not one big ?
7195  set<MolAtom*> fullset;
7196  for(list<pair<const MolAtom *,set<MolAtom *> > >::iterator chain=pos->mvRotatedChainList.begin();
7197  chain!=pos->mvRotatedChainList.end();++chain)
7198  for(set<MolAtom *>::const_iterator at=chain->second.begin();at!=chain->second.end();++at)
7199  fullset.insert(*at);
7200 
7201  bool keep=true;
7202  for(vector<RigidGroup*>::const_iterator group=mvRigidGroup.begin(); group!=mvRigidGroup.end();++group)
7203  {
7204  unsigned long ct=0;
7205  for(set<MolAtom *>::const_iterator at=fullset.begin();at!=fullset.end();++at)
7206  ct+=(*group)->count(*at);
7207 
7208  if((ct>0)&&(ct<(*group)->size())) {keep=false; break;}
7209  }
7210 
7211  if(!keep)
7212  {
7213  cout <<"EXCLUDING flip group (breaking a rigid group): "
7214  <<pos->mpAtom0->GetName()<<",exchanging bonds with "
7215  <<pos->mpAtom1->GetName()<<" and "
7216  <<pos->mpAtom2->GetName()<<", resulting in a 180deg rotation of atoms : ";
7217  for(set<MolAtom*>::iterator pos1=pos->mvRotatedChainList.begin()->second.begin();
7218  pos1!=pos->mvRotatedChainList.begin()->second.end();++pos1)
7219  cout<<(*pos1)->GetName()<<" ";
7220 
7221  cout<<endl;
7222 
7223  pos=mvFlipGroup.erase(pos);
7224  }
7225  else pos++;
7226  }
7227  //Exclude flip groups where the central atom is in the non-flip atom list
7228  for(list<FlipGroup>::iterator pos=mvFlipGroup.begin(); pos!=mvFlipGroup.end();)
7229  {
7230  if(pos->mpAtom0->IsNonFlipAtom())
7231  {
7232  cout <<"EXCLUDING flip group (central atom is in the non-flip list): "
7233  <<pos->mpAtom0->GetName()<<",exchanging bonds with "
7234  <<pos->mpAtom1->GetName()<<" and "
7235  <<pos->mpAtom2->GetName()<<", resulting in a 180deg rotation of atoms : ";
7236  for(set<MolAtom*>::iterator pos1=pos->mvRotatedChainList.begin()->second.begin();
7237  pos1!=pos->mvRotatedChainList.begin()->second.end();++pos1)
7238  cout<<(*pos1)->GetName()<<" ";
7239 
7240  cout<<endl;
7241 
7242  pos=mvFlipGroup.erase(pos);
7243  } else
7244  {
7245  pos++;
7246  }
7247  }
7248  // List them
7249  this->SaveParamSet(mLocalParamSet);
7250  #if 1//def __DEBUG__
7251  // const REAL llk0=this->GetLogLikelihood();
7252  for(list<FlipGroup>::iterator pos=mvFlipGroup.begin();
7253  pos!=mvFlipGroup.end();++pos)
7254  {
7255  if(pos->mvRotatedChainList.begin()->first==pos->mpAtom0)
7256  {
7257  cout <<"Flip group from atom "
7258  <<pos->mpAtom0->GetName()<<",exchanging bonds with "
7259  <<pos->mpAtom1->GetName()<<" and "
7260  <<pos->mpAtom2->GetName()<<", resulting in a 180� rotation of atoms : ";
7261  for(set<MolAtom*>::iterator pos1=pos->mvRotatedChainList.begin()->second.begin();
7262  pos1!=pos->mvRotatedChainList.begin()->second.end();++pos1)
7263  cout<<(*pos1)->GetName()<<" ";
7264  }
7265  else
7266  {
7267  cout <<"Flip group with respect to: "
7268  <<pos->mpAtom1->GetName()<<"-"
7269  <<pos->mpAtom0->GetName()<<"-"
7270  <<pos->mpAtom2->GetName()<<" : ";
7271  for(list<pair<const MolAtom *,set<MolAtom*> > >::const_iterator
7272  chain=pos->mvRotatedChainList.begin();
7273  chain!=pos->mvRotatedChainList.end();++chain)
7274  {
7275  cout<<" -"<<chain->first->GetName()<<":";
7276  for(set<MolAtom*>::const_iterator pos1=chain->second.begin();
7277  pos1!=chain->second.end();++pos1)
7278  cout<<(*pos1)->GetName()<<" ";
7279  }
7280  }
7281  #if 0
7282  // test if they do not break something (dihedral angle restraint) ?
7283  // We seldom try flippping, so don't test - test is done during optimization
7284  this->FlipAtomGroup(*pos);
7285  const REAL dllk=this->GetLogLikelihood()-llk0;
7286  if(dllk>1000.)
7287  {
7288  pos = mvFlipGroup.erase(pos);
7289  --pos;
7290  cout <<" -> NOT a free flip, d(llk)="<<dllk;
7291  this->RestraintStatus(cout);
7292  }
7293  else cout <<" -> free flip, d(llk)="<<dllk;
7294  this->RestoreParamSet(mLocalParamSet);
7295  #endif
7296  cout<<endl;
7297  }
7298  #endif
7299  mClockFlipGroup.Click();
7300  VFN_DEBUG_EXIT("Molecule::BuildFlipGroup()",5)
7301 }
7302 
7304 {
7305  // Assume Stretch modes have already been built
7306  map<const MolBond*, set<const StretchMode*> > vpBond;
7307  for(list<StretchModeBondLength>::const_iterator mode=mvStretchModeBondLength.begin();
7308  mode!=mvStretchModeBondLength.end();++mode)
7309  {
7310  if(mode->mpBond!=0) vpBond[mode->mpBond].insert(&(*mode));
7311  for(map<const MolBond*,REAL>::const_iterator pos=mode->mvpBrokenBond.begin();
7312  pos!=mode->mvpBrokenBond.end();++pos)
7313  vpBond[pos->first].insert(&(*mode));
7314  }
7315  for(list<StretchModeBondAngle>::const_iterator mode=mvStretchModeBondAngle.begin();
7316  mode!=mvStretchModeBondAngle.end();++mode)
7317  for(map<const MolBond*,REAL>::const_iterator pos=mode->mvpBrokenBond.begin();
7318  pos!=mode->mvpBrokenBond.end();++pos)
7319  vpBond[pos->first].insert(&(*mode));
7320 
7321  for(list<StretchModeTorsion>::const_iterator mode=mvStretchModeTorsion.begin();
7322  mode!=mvStretchModeTorsion.end();++mode)
7323  for(map<const MolBond*,REAL>::const_iterator pos=mode->mvpBrokenBond.begin();
7324  pos!=mode->mvpBrokenBond.end();++pos)
7325  vpBond[pos->first].insert(&(*mode));
7326  for(list<StretchModeTwist>::const_iterator mode=mvStretchModeTwist.begin();
7327  mode!=mvStretchModeTwist.end();++mode)
7328  for(map<const MolBond*,REAL>::const_iterator pos=mode->mvpBrokenBond.begin();
7329  pos!=mode->mvpBrokenBond.end();++pos)
7330  vpBond[pos->first].insert(&(*mode));
7331 
7332 
7333 
7334  map<const MolBondAngle*, set<const StretchMode*> > vpAngle;
7335  for(list<StretchModeBondLength>::const_iterator mode=mvStretchModeBondLength.begin();
7336  mode!=mvStretchModeBondLength.end();++mode)
7337  for(map<const MolBondAngle*,REAL>::const_iterator pos=mode->mvpBrokenBondAngle.begin();
7338  pos!=mode->mvpBrokenBondAngle.end();++pos)
7339  vpAngle[pos->first].insert(&(*mode));
7340 
7341  for(list<StretchModeBondAngle>::const_iterator mode=mvStretchModeBondAngle.begin();
7342  mode!=mvStretchModeBondAngle.end();++mode)
7343  {
7344  if(mode->mpBondAngle!=0) vpAngle[mode->mpBondAngle].insert(&(*mode));
7345  for(map<const MolBondAngle*,REAL>::const_iterator pos=mode->mvpBrokenBondAngle.begin();
7346  pos!=mode->mvpBrokenBondAngle.end();++pos)
7347  vpAngle[pos->first].insert(&(*mode));
7348  }
7349  for(list<StretchModeTorsion>::const_iterator mode=mvStretchModeTorsion.begin();
7350  mode!=mvStretchModeTorsion.end();++mode)
7351  for(map<const MolBondAngle*,REAL>::const_iterator pos=mode->mvpBrokenBondAngle.begin();
7352  pos!=mode->mvpBrokenBondAngle.end();++pos)
7353  vpAngle[pos->first].insert(&(*mode));
7354  for(list<StretchModeTwist>::const_iterator mode=mvStretchModeTwist.begin();
7355  mode!=mvStretchModeTwist.end();++mode)
7356  for(map<const MolBondAngle*,REAL>::const_iterator pos=mode->mvpBrokenBondAngle.begin();
7357  pos!=mode->mvpBrokenBondAngle.end();++pos)
7358  vpAngle[pos->first].insert(&(*mode));
7359 
7360 
7361 
7362  map<const MolDihedralAngle*,set<const StretchMode*> > vpDihed;
7363  for(list<StretchModeBondLength>::const_iterator mode=mvStretchModeBondLength.begin();
7364  mode!=mvStretchModeBondLength.end();++mode)
7365  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=mode->mvpBrokenDihedralAngle.begin();
7366  pos!=mode->mvpBrokenDihedralAngle.end();++pos)
7367  vpDihed[pos->first].insert(&(*mode));
7368 
7369  for(list<StretchModeBondAngle>::const_iterator mode=mvStretchModeBondAngle.begin();
7370  mode!=mvStretchModeBondAngle.end();++mode)
7371  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=mode->mvpBrokenDihedralAngle.begin();
7372  pos!=mode->mvpBrokenDihedralAngle.end();++pos)
7373  vpDihed[pos->first].insert(&(*mode));
7374 
7375  for(list<StretchModeTorsion>::const_iterator mode=mvStretchModeTorsion.begin();
7376  mode!=mvStretchModeTorsion.end();++mode)
7377  {
7378  if(mode->mpDihedralAngle!=0) vpDihed[mode->mpDihedralAngle].insert(&(*mode));
7379  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=mode->mvpBrokenDihedralAngle.begin();
7380  pos!=mode->mvpBrokenDihedralAngle.end();++pos)
7381  vpDihed[pos->first].insert(&(*mode));
7382  }
7383  for(list<StretchModeTwist>::const_iterator mode=mvStretchModeTwist.begin();
7384  mode!=mvStretchModeTwist.end();++mode)
7385  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=mode->mvpBrokenDihedralAngle.begin();
7386  pos!=mode->mvpBrokenDihedralAngle.end();++pos)
7387  vpDihed[pos->first].insert(&(*mode));
7388  #if 0
7389  for(map<const MolBond*,set<const StretchMode*> >::const_iterator pos=vpBond.begin();pos!=vpBond.end();++pos)
7390  {
7391  cout<<"Bond "<<pos->first->GetName()<<" is modified by the stretch modes:"<<endl;
7392  for(set<const StretchMode*>::const_iterator mode=pos->second.begin();mode!=pos->second.end();++mode)
7393  {
7394  cout<<" ";
7395  (*mode)->Print(cout);
7396  cout<<endl;
7397  }
7398  }
7399  for(map<const MolBondAngle*,set<const StretchMode*> >::const_iterator pos=vpAngle.begin();pos!=vpAngle.end();++pos)
7400  {
7401  cout<<"Bond Angle "<<pos->first->GetName()<<" is modified by the stretch modes:"<<endl;
7402  for(set<const StretchMode*>::const_iterator mode=pos->second.begin();mode!=pos->second.end();++mode)
7403  {
7404  cout<<" ";
7405  (*mode)->Print(cout);
7406  cout<<endl;
7407  }
7408  }
7409  for(map<const MolDihedralAngle*,set<const StretchMode*> >::const_iterator pos=vpDihed.begin();pos!=vpDihed.end();++pos)
7410  {
7411  cout<<"Dihedral Angle "<<pos->first->GetName()<<" is modified by the stretch modes:"<<endl;
7412  for(set<const StretchMode*>::const_iterator mode=pos->second.begin();mode!=pos->second.end();++mode)
7413  {
7414  cout<<" ";
7415  (*mode)->Print(cout);
7416  cout<<endl;
7417  }
7418  }
7419  #endif
7420  mvpStretchModeFree.clear();
7421  mvpStretchModeNotFree.clear();
7422 
7423  for(list<StretchModeBondLength>::iterator mode=mvStretchModeBondLength.begin();
7424  mode!=mvStretchModeBondLength.end();++mode)
7425  {
7426  int nb=mode->mvpBrokenDihedralAngle.size()+mode->mvpBrokenBondAngle.size()+mode->mvpBrokenBond.size();
7427  if(mode->mpBond!=0) nb -= 1;
7428  if(nb==0) mvpStretchModeFree.push_back(&(*mode));
7429  else mvpStretchModeNotFree.push_back(&(*mode));
7430  }
7431 
7432  for(list<StretchModeBondAngle>::iterator mode=mvStretchModeBondAngle.begin();
7433  mode!=mvStretchModeBondAngle.end();++mode)
7434  {
7435  int nb=mode->mvpBrokenDihedralAngle.size()+mode->mvpBrokenBondAngle.size()+mode->mvpBrokenBond.size();
7436  if(mode->mpBondAngle!=0) nb -= 1;
7437  if(nb==0) mvpStretchModeFree.push_back(&(*mode));
7438  else mvpStretchModeNotFree.push_back(&(*mode));
7439  }
7440 
7441  for(list<StretchModeTorsion>::iterator mode=mvStretchModeTorsion.begin();
7442  mode!=mvStretchModeTorsion.end();++mode)
7443  {
7444  int nb=mode->mvpBrokenDihedralAngle.size()+mode->mvpBrokenBondAngle.size()+mode->mvpBrokenBond.size();
7445  if(mode->mpDihedralAngle!=0) nb -= 1;
7446  if(nb==0) mvpStretchModeFree.push_back(&(*mode));
7447  else mvpStretchModeNotFree.push_back(&(*mode));
7448  }
7449  #if 1
7450  for(list<StretchModeTwist>::iterator mode=mvStretchModeTwist.begin();
7451  mode!=mvStretchModeTwist.end();++mode)
7452  if(mode->mvpBrokenDihedralAngle.size()+mode->mvpBrokenBondAngle.size()+mode->mvpBrokenBond.size()==0)
7453  mvpStretchModeFree.push_back(&(*mode));
7454  else mvpStretchModeNotFree.push_back(&(*mode));
7455  #endif
7456 }
7457 
7459 {
7460  // For each atom, list all atoms that are never moved relatively to it.
7461  // (not moved == distance cannot change)
7462  map<MolAtom*,set<MolAtom*> > vBoundAtoms;
7463  set<MolAtom*> set0;
7464  for(vector<MolAtom*>::iterator pos=this->GetAtomList().begin();pos!=this->GetAtomList().end();++pos)
7465  set0.insert(*pos);
7466 
7467  for(vector<MolAtom*>::iterator pat1=this->GetAtomList().begin();pat1!=this->GetAtomList().end();++pat1)
7468  {
7469  vBoundAtoms[*pat1]=set0;
7470  for(vector<MolAtom*>::iterator pat2=this->GetAtomList().begin();pat2!=this->GetAtomList().end();++pat2)
7471  {
7472  bool cont=false;
7473 
7474  for(list<StretchModeBondLength>::iterator pstretch=this->GetStretchModeBondLengthList().begin();
7475  pstretch!=this->GetStretchModeBondLengthList().end();++pstretch)
7476  {
7477  set<MolAtom *>::iterator pos1=pstretch->mvTranslatedAtomList.find(*pat1),
7478  pos2=pstretch->mvTranslatedAtomList.find(*pat2);
7479  if( ((pos1==pstretch->mvTranslatedAtomList.end())&&(pos2!=pstretch->mvTranslatedAtomList.end()))
7480  ||((pos1!=pstretch->mvTranslatedAtomList.end())&&(pos2==pstretch->mvTranslatedAtomList.end())))
7481  {
7482  vBoundAtoms[*pat1].erase(*pat2);
7483  //cout<<(*pat1)->GetName()<<" moves (b) relatively to "<<(*pat2)->GetName()<<" /";
7484  //pstretch->Print(cout);cout<<endl;
7485  cont=true;
7486  break;
7487  }
7488  }
7489  if(cont) continue;
7490 
7491  for(list<StretchModeBondAngle>::iterator pstretch=this->GetStretchModeBondAngleList().begin();
7492  pstretch!=this->GetStretchModeBondAngleList().end();++pstretch)
7493  {
7494  //pstretch->mpAtom1 does not move relatively to any atom
7495  if((*pat1==pstretch->mpAtom1)||(*pat2==pstretch->mpAtom1)) continue;
7496 
7497  set<MolAtom *>::iterator pos1=pstretch->mvRotatedAtomList.find(*pat1),
7498  pos2=pstretch->mvRotatedAtomList.find(*pat2);
7499  //:TODO: Take into account the special case of the atoms defining the bond angle
7500  if( ((pos1==pstretch->mvRotatedAtomList.end())&&(pos2!=pstretch->mvRotatedAtomList.end()))
7501  ||((pos1!=pstretch->mvRotatedAtomList.end())&&(pos2==pstretch->mvRotatedAtomList.end())))
7502  {
7503  vBoundAtoms[*pat1].erase(*pat2);
7504  //cout<<(*pat1)->GetName()<<" moves (a) relatively to "<<(*pat2)->GetName()<<" /";
7505  //pstretch->Print(cout);cout<<endl;
7506  cont=true;
7507  break;
7508  }
7509  }
7510  if(cont) continue;
7511 
7512  for(list<StretchModeTorsion>::iterator pstretch=this->GetStretchModeTorsionList().begin();
7513  pstretch!=this->GetStretchModeTorsionList().end();++pstretch)
7514  {
7515  set<MolAtom *>::iterator pos1=pstretch->mvRotatedAtomList.find(*pat1),
7516  pos2=pstretch->mvRotatedAtomList.find(*pat2);
7517 
7518  if( (pos1!=pstretch->mvRotatedAtomList.end())&&(pos2==pstretch->mvRotatedAtomList.end())
7519  &&(*pat2!=pstretch->mpAtom1) &&(*pat2!=pstretch->mpAtom2) )
7520  {
7521  vBoundAtoms[*pat1].erase(*pat2);
7522  //cout<<(*pat1)->GetName()<<" moves (d1) relatively to "<<(*pat2)->GetName()<<" /";
7523  //pstretch->Print(cout);cout<<endl;
7524  break;
7525  }
7526  if( (pos1==pstretch->mvRotatedAtomList.end())&&(pos2!=pstretch->mvRotatedAtomList.end())
7527  &&(*pat1!=pstretch->mpAtom1) && (*pat1!=pstretch->mpAtom2) )
7528  {
7529  vBoundAtoms[*pat1].erase(*pat2);
7530  //cout<<(*pat1)->GetName()<<" moves (d2) relatively to "<<(*pat2)->GetName()<<" /";
7531  //pstretch->Print(cout);cout<<endl;
7532  break;
7533  }
7534  }
7535  }
7536  }
7537 
7538  // List remaining group of atoms, take care of rigid groups
7539  set<set<MolAtom*> > vBoundGroups;
7540  for(map<MolAtom*,set<MolAtom*> >::iterator pos=vBoundAtoms.begin();pos!=vBoundAtoms.end();++pos)
7541  {
7542  #if 0
7543  cout<<"Non-flexible group from "<<pos->first->GetName()<<": ";
7544  for(set<MolAtom*>::const_iterator atom=pos->second.begin();atom!=pos->second.end();++atom)
7545  cout<<(*atom)->GetName()<<",";
7546  cout<<endl;
7547  #endif
7548  // Remove atoms belonging to a rigid group
7549  for(vector<RigidGroup *>::iterator pr=this->GetRigidGroupList().begin();pr!=this->GetRigidGroupList().end();++pr)
7550  for(set<MolAtom *>::iterator at=(*pr)->begin();at!=(*pr)->end();++at)
7551  pos->second.erase(*at);
7552  if(pos->second.size()>1) vBoundGroups.insert(pos->second);
7553  }
7554  #if 0
7555  for(set<set<MolAtom*> >::iterator pos=vBoundGroups.begin();pos!=vBoundGroups.end();++pos)
7556  {
7557  cout<<"Non-flexible group:";
7558  for(set<MolAtom*>::const_iterator atom=pos->begin();atom!=pos->end();++atom)
7559  cout<<(*atom)->GetName()<<",";
7560  cout<<endl;
7561  }
7562  #endif
7563  // Create relevant MDAtomGroup, listing associated restraints
7564  mvMDAtomGroup.clear();
7565  for(set<set<MolAtom*> >::iterator pos=vBoundGroups.begin();pos!=vBoundGroups.end();++pos)
7566  {
7567  set<MolBond*> vb;
7568  for(vector<MolBond*>::iterator pr=this->GetBondList().begin();pr!=this->GetBondList().end();++pr)
7569  if( (pos->find(&(*pr)->GetAtom1())!=pos->end())
7570  ||(pos->find(&(*pr)->GetAtom2())!=pos->end())) vb.insert(*pr);
7571 
7572  set<MolBondAngle*> va;
7573  for(vector<MolBondAngle*>::iterator pr=this->GetBondAngleList().begin();pr!=this->GetBondAngleList().end();++pr)
7574  if( (pos->find(&(*pr)->GetAtom1())!=pos->end())
7575  ||(pos->find(&(*pr)->GetAtom2())!=pos->end())
7576  ||(pos->find(&(*pr)->GetAtom3())!=pos->end())) va.insert(*pr);
7577 
7578  set<MolDihedralAngle*> vd;
7579  for(vector<MolDihedralAngle*>::iterator pr=this->GetDihedralAngleList().begin();pr!=this->GetDihedralAngleList().end();++pr)
7580  if( (pos->find(&(*pr)->GetAtom1())!=pos->end())
7581  ||(pos->find(&(*pr)->GetAtom2())!=pos->end())
7582  ||(pos->find(&(*pr)->GetAtom3())!=pos->end())
7583  ||(pos->find(&(*pr)->GetAtom4())!=pos->end())) vd.insert(*pr);
7584 
7585  set<MolAtom*> tmp= *pos;// Cannot pass *pos directly ? gcc bug evaluating const-ness?
7586  mvMDAtomGroup.push_back(MDAtomGroup(tmp,vb,va,vd));
7587  mvMDAtomGroup.back().Print(cout);
7588  }
7589 
7590  // Create mvMDFullAtomGroup
7591  mvMDFullAtomGroup.clear();
7592  #if 1
7593  // All atoms except those in rigid groups
7594  for(vector<MolAtom*>::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at)
7595  mvMDFullAtomGroup.insert(*at);
7596  for(vector<RigidGroup *>::iterator pr=this->GetRigidGroupList().begin();pr!=this->GetRigidGroupList().end();++pr)
7597  for(set<MolAtom *>::iterator at=(*pr)->begin();at!=(*pr)->end();++at)
7598  mvMDFullAtomGroup.erase(*at);
7599  cout<<"Full MD atom group:"<<endl<<" ";
7600  for(set<MolAtom*>::const_iterator pos=mvMDFullAtomGroup.begin();pos!=mvMDFullAtomGroup.end();++pos)
7601  cout<<(*pos)->GetName()<<" ";
7602  cout<<endl;
7603  #else
7604  // All atoms listed in at leat one mvMDAtomGroup
7605  mvMDFullAtomGroup.clear();
7606  for(list<MDAtomGroup>::const_iterator pos= mvMDAtomGroup.begin();pos!= mvMDAtomGroup.end();++pos)
7607  for(set<MolAtom*>::const_iterator at=pos->mvpAtom.begin();at!=pos->mvpAtom.end();++at)
7608  mvMDFullAtomGroup.insert(*at);
7609  cout<<"Full MD atom group:"<<endl<<" ";
7610  for(set<MolAtom*>::const_iterator pos=mvMDFullAtomGroup.begin();pos!=mvMDFullAtomGroup.end();++pos)
7611  cout<<(*pos)->GetName()<<" ";
7612  cout<<endl;
7613  #endif
7614  mClockMDAtomGroup.Click();
7615 }
7616 
7618 {
7619  if( (mClockAtomPosition<mClockScattCompList)
7620  &&(mClockOrientation <mClockScattCompList)
7621  &&(mClockAtomScattPow<mClockScattCompList)
7623  &&(this->GetCrystal().GetClockLatticePar()<mClockScattCompList))return;
7624  VFN_DEBUG_ENTRY("Molecule::UpdateScattCompList()",5)
7625  TAU_PROFILE("Molecule::UpdateScattCompList()","void ()",TAU_DEFAULT);
7626  const long nb=this->GetNbComponent();
7627  // Get internal coords
7628  for(long i=0;i<nb;++i)
7629  {
7630  if(mvpAtom[i]->IsDummy()) mScattCompList(i).mpScattPow=0;
7631  else mScattCompList(i).mpScattPow=&(mvpAtom[i]->GetScatteringPower());
7632  mScattCompList(i).mX=mvpAtom[i]->GetX();
7633  mScattCompList(i).mY=mvpAtom[i]->GetY();
7634  mScattCompList(i).mZ=mvpAtom[i]->GetZ();
7635  mScattCompList(i).mOccupancy=mvpAtom[i]->GetOccupancy()*mOccupancy;
7636  }
7637 
7638  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
7639  // During an optimization, apply the translations & rotations of the rigid group parameters
7640  if(true)//this->IsBeingRefined())
7641  {
7642  for(vector<RigidGroup *>::const_iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
7643  {
7644  (*pos)->mQuat.Normalize();
7645  // Center of the atom group
7646  REAL x0=0,y0=0,z0=0;
7647  for(set<unsigned int>::iterator at=(*pos)->mvIdx.begin();at!=(*pos)->mvIdx.end();++at)
7648  {
7649  x0+=mvpAtom[*at]->GetX();
7650  y0+=mvpAtom[*at]->GetY();
7651  z0+=mvpAtom[*at]->GetZ();
7652  }
7653  x0/=(*pos)->size();
7654  y0/=(*pos)->size();
7655  z0/=(*pos)->size();
7656 
7657  // Apply rotation & translation to all atoms
7658  for(set<unsigned int>::iterator at=(*pos)->mvIdx.begin();at!=(*pos)->mvIdx.end();++at)
7659  {
7660  REAL x=mvpAtom[*at]->GetX()-x0, y=mvpAtom[*at]->GetY()-y0, z=mvpAtom[*at]->GetZ()-z0;
7661  (*pos)->mQuat.RotateVector(x,y,z);
7662  mScattCompList(*at).mX=x+x0+(*pos)->mX;
7663  mScattCompList(*at).mY=y+y0+(*pos)->mY;
7664  mScattCompList(*at).mZ=z+z0+(*pos)->mZ;
7665  }
7666  }
7667  }
7668  #endif
7669  // translate center to (0,0,0)
7670  REAL x0=0,y0=0,z0=0;
7671  if((mMoleculeCenter.GetChoice()==0) || (mpCenterAtom==0))
7672  {
7673  for(long i=0;i<nb;++i)
7674  {
7675  x0 += mScattCompList(i).mX;
7676  y0 += mScattCompList(i).mY;
7677  z0 += mScattCompList(i).mZ;
7678  }
7679  x0 /= nb;
7680  y0 /= nb;
7681  z0 /= nb;
7682  }
7683  else
7684  {
7685  x0=mpCenterAtom->GetX();
7686  y0=mpCenterAtom->GetY();
7687  z0=mpCenterAtom->GetZ();
7688  }
7689  for(long i=0;i<nb;++i)
7690  {
7691  mScattCompList(i).mX -= x0;
7692  mScattCompList(i).mY -= y0;
7693  mScattCompList(i).mZ -= z0;
7694  }
7695  //VFN_DEBUG_MESSAGE("Molecule::UpdateScattCompList()",10)
7696  // rotate
7697  mQuat.Normalize();
7698  for(long i=0;i<nb;++i)
7699  {
7700  //#error the vector must not be normalized !
7702  }
7703  // Convert to fractionnal coordinates
7704  for(long i=0;i<nb;++i)
7705  {
7707  mScattCompList(i).mY,
7708  mScattCompList(i).mZ);
7709  }
7710  // translate center to position in unit cell
7711  for(long i=0;i<nb;++i)
7712  {
7713  mScattCompList(i).mX += mXYZ(0);
7714  mScattCompList(i).mY += mXYZ(1);
7715  mScattCompList(i).mZ += mXYZ(2);
7716  }
7718  VFN_DEBUG_EXIT("Molecule::UpdateScattCompList()",5)
7719 }
7720 vector<MolAtom*>::reverse_iterator Molecule::FindAtom(const string &name)
7721 {
7722  VFN_DEBUG_ENTRY("Molecule::FindAtom():"<<name,4)
7723  vector<MolAtom*>::reverse_iterator rpos;
7724  for(rpos=mvpAtom.rbegin();rpos!=mvpAtom.rend();++rpos)
7725  if(name==(*rpos)->GetName())
7726  {
7727  VFN_DEBUG_EXIT("Molecule::FindAtom():"<<name<<"...FOUND !",4)
7728  return rpos;
7729  }
7730  VFN_DEBUG_EXIT("Molecule::FindAtom():"<<name<<"...NOT FOUND !",4)
7731  return rpos;
7732 }
7733 vector<MolAtom*>::const_reverse_iterator Molecule::FindAtom(const string &name)const
7734 {
7735  vector<MolAtom*>::const_reverse_iterator rpos;
7736  rpos=mvpAtom.rbegin();
7737  for(rpos=mvpAtom.rbegin();rpos!=mvpAtom.rend();++rpos)
7738  if(name==(*rpos)->GetName()) return rpos;
7739  return rpos;
7740 }
7742 {
7743  VFN_DEBUG_ENTRY("Molecule::InitOptions",7)
7744  static string Flexname;
7745  static string Flexchoices[3];
7746 
7747  static string FlipName;
7748  static string FlipChoice[2];
7749 
7750  static string autoOptimizeConformationName;
7751  static string autoOptimizeConformationChoices[2];
7752 
7753  static string optimizeOrientationName;
7754  static string optimizeOrientationChoices[2];
7755 
7756  static string moleculeCenterName;
7757  static string moleculeCenterChoices[2];
7758 
7759  static bool needInitNames=true;
7760  if(true==needInitNames)
7761  {
7762  Flexname="Flexibility Model";
7763  Flexchoices[0]="Automatic from Restraints, relaxed - RECOMMENDED";
7764  Flexchoices[1]="Rigid Body";
7765  Flexchoices[2]="Automatic from Restraints, strict";
7766  //Flexchoices[3]="Molecular Dynamics";
7767 
7768  FlipName="Enable Flipping";
7769  FlipChoice[0]="Yes";
7770  FlipChoice[1]="No";
7771 
7772  autoOptimizeConformationName="Auto Optimize Starting Conformation";
7773  autoOptimizeConformationChoices[0]="Yes";
7774  autoOptimizeConformationChoices[1]="No";
7775 
7776  optimizeOrientationName="Optimize Orientation";
7777  optimizeOrientationChoices[0]="Yes";
7778  optimizeOrientationChoices[1]="No";
7779 
7780  moleculeCenterName="Rotation Center";
7781  moleculeCenterChoices[0]="Geometrical center (recommended)";
7782  moleculeCenterChoices[1]="User-chosen Atom";
7783 
7784  needInitNames=false;
7785  }
7786  mFlexModel.Init(3,&Flexname,Flexchoices);
7787  mFlexModel.SetChoice(0);
7788  this->AddOption(&mFlexModel);
7789 
7790  mFlipModel.Init(2, &FlipName, FlipChoice);
7791  mFlipModel.SetChoice(0);
7792  this->AddOption(&mFlipModel);
7793 
7794  mAutoOptimizeConformation.Init(2,&autoOptimizeConformationName,
7795  autoOptimizeConformationChoices);
7797 
7798  mOptimizeOrientation.Init(2,&optimizeOrientationName,optimizeOrientationChoices);
7800 
7801  mMoleculeCenter.Init(2,&moleculeCenterName,moleculeCenterChoices);
7802  this->AddOption(&mMoleculeCenter);
7803 
7804  VFN_DEBUG_EXIT("Molecule::InitOptions",7)
7805 }
7806 
7807 Molecule::FlipGroup::FlipGroup(const MolAtom &at0,const MolAtom &at1,const MolAtom &at2):
7808 mpAtom0(&at0),mpAtom1(&at1),mpAtom2(&at2),mNbTest(0),mNbAccept(0)
7809 {
7810 }
7811 
7812 void Molecule::FlipAtomGroup(const FlipGroup& group, const bool keepCenter)
7813 {
7814  TAU_PROFILE("Molecule::FlipAtomGroup(FlipGroup&)","void (...)",TAU_DEFAULT);
7815  if(group.mpAtom0==group.mvRotatedChainList.back().first)
7816  {// We are doing a 180� rotation exchanging two bonds
7817  const REAL vx=group.mpAtom0->X()-(group.mpAtom1->X()+group.mpAtom2->X())/2.;
7818  const REAL vy=group.mpAtom0->Y()-(group.mpAtom1->Y()+group.mpAtom2->Y())/2.;
7819  const REAL vz=group.mpAtom0->Z()-(group.mpAtom1->Z()+group.mpAtom2->Z())/2.;
7820  this->RotateAtomGroup(*(group.mpAtom0),vx,vy,vz,
7821  group.mvRotatedChainList.back().second,M_PI,keepCenter);
7822  }
7823  else
7824  {// we are flipping bonds with respect to a plane defined by other bonds
7825  REAL v01x=group.mpAtom1->X()-group.mpAtom0->X();
7826  REAL v01y=group.mpAtom1->Y()-group.mpAtom0->Y();
7827  REAL v01z=group.mpAtom1->Z()-group.mpAtom0->Z();
7828  const REAL norm01=sqrt(v01x*v01x+v01y*v01y+v01z*v01z+1e-7);
7829  v01x /= norm01;v01y /= norm01;v01z /= norm01;
7830 
7831  REAL v02x=group.mpAtom2->X()-group.mpAtom0->X();
7832  REAL v02y=group.mpAtom2->Y()-group.mpAtom0->Y();
7833  REAL v02z=group.mpAtom2->Z()-group.mpAtom0->Z();
7834  const REAL norm02=sqrt(v02x*v02x+v02y*v02y+v02z*v02z+1e-7);
7835  v02x /= norm02;v02y /= norm02;v02z /= norm02;
7836 
7837  REAL v12x=group.mpAtom2->X()-group.mpAtom1->X();
7838  REAL v12y=group.mpAtom2->Y()-group.mpAtom1->Y();
7839  REAL v12z=group.mpAtom2->Z()-group.mpAtom1->Z();
7840  const REAL norm12=sqrt(v12x*v12x+v12y*v12y+v12z*v12z+1e-7);
7841  v12x /= norm12;v12y /= norm12;v12z /= norm12;
7842 
7843  REAL v0mx=group.mpAtom0->X()-(group.mpAtom1->X()+group.mpAtom2->X())/2.;
7844  REAL v0my=group.mpAtom0->Y()-(group.mpAtom1->Y()+group.mpAtom2->Y())/2.;
7845  REAL v0mz=group.mpAtom0->Z()-(group.mpAtom1->Z()+group.mpAtom2->Z())/2.;
7846  const REAL norm0m=sqrt(v0mx*v0mx+v0my*v0my+v0mz*v0mz+1e-7);
7847  v0mx /= norm0m;v0my /= norm0m;v0mz /= norm0m;
7848 
7849  if(fabs(v01x*v02x+v01y*v02y+v01z*v02z)
7850  >0.05*sqrt(abs( (v01x*v01x+v01y*v01y+v01z*v01z)
7851  *(v02x*v02x+v02y*v02y+v02z*v02z))))
7852  {
7853  REAL v012x=v01y*v02z-v01z*v02y;
7854  REAL v012y=v01z*v02x-v01x*v02z;
7855  REAL v012z=v01x*v02y-v01y*v02x;
7856  const REAL norm012=sqrt(v012x*v012x+v012y*v012y+v012z*v012z+1e-7);
7857  v012x /= norm012;v012y /= norm012;v012z /= norm012;
7858 
7859 
7860  for(list<pair<const MolAtom *,set<MolAtom*> > >::const_iterator
7861  chain=group.mvRotatedChainList.begin();
7862  chain!=group.mvRotatedChainList.end();++chain)
7863  {
7864  REAL v03x=chain->first->X()-group.mpAtom0->X();
7865  REAL v03y=chain->first->Y()-group.mpAtom0->Y();
7866  REAL v03z=chain->first->Z()-group.mpAtom0->Z();
7867  const REAL norm03=sqrt( v03x*v03x + v03y*v03y + v03z*v03z +1e-7);
7868  v03x /= norm03;v03y /= norm03;v03z /= norm03;
7869 
7870  const REAL a1=v012x*v03x+v012y*v03y+v012z*v03z;
7871  const REAL a2= v0mx*v03x+ v0my*v03y+ v0mz*v03z;
7872  const REAL a3= v12x*v03x+ v12y*v03y+ v12z*v03z;
7873  REAL angle = -a1/sqrt(1-a3*a3+1e-7);
7874  if(angle>=1.)
7875  angle = M_PI/2.;
7876  else
7877  {
7878  if(angle<=-1.)
7879  {
7880  angle = -M_PI/2.;
7881  }
7882  else angle = asin(angle);
7883  }
7884  if(a2<0) angle=M_PI-angle;
7885  this->RotateAtomGroup(*(group.mpAtom0),v12x,v12y,v12z,
7886  chain->second,2*angle,keepCenter);
7887  }
7888  }
7889  }
7890 }
7891 
7894 }
7895 
7897 {
7898  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
7899  // Apply the translations & rotations of all rigid group parameters, and
7900  // use this as the newly stored atomic coordinates.
7901  for(vector<RigidGroup *>::const_iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
7902  {
7903  (*pos)->mQuat.Normalize();
7904  // Center of atom group
7905  REAL x0=0,y0=0,z0=0;
7906  for(set<MolAtom *>::iterator at=(*pos)->begin();at!=(*pos)->end();++at)
7907  {
7908  x0+=(*at)->GetX();
7909  y0+=(*at)->GetY();
7910  z0+=(*at)->GetZ();
7911  }
7912  x0/=(*pos)->size();
7913  y0/=(*pos)->size();
7914  z0/=(*pos)->size();
7915 
7916  // Apply rotation & translation to all atoms
7917  for(set<MolAtom *>::iterator at=(*pos)->begin();at!=(*pos)->end();++at)
7918  {
7919  REAL x=(*at)->GetX()-x0, y=(*at)->GetY()-y0, z=(*at)->GetZ()-z0;
7920  (*pos)->mQuat.RotateVector(x,y,z);
7921  (*at)->SetX(x+x0+(*pos)->mX);
7922  (*at)->SetY(y+y0+(*pos)->mY);
7923  (*at)->SetZ(z+z0+(*pos)->mZ);
7924  }
7925 
7926  // Reset the translation & rotation parameters, only useful during an optimization
7927  (*pos)->mX=0;
7928  (*pos)->mY=0;
7929  (*pos)->mZ=0;
7930  (*pos)->mQuat.Q0()=1;
7931  (*pos)->mQuat.Q1()=0;
7932  (*pos)->mQuat.Q2()=0;
7933  (*pos)->mQuat.Q3()=0;
7934  }
7935  #endif
7936 }
7937 
7938 #ifdef __WX__CRYST__
7939 WXCrystObjBasic* Molecule::WXCreate(wxWindow* parent)
7940 {
7941  VFN_DEBUG_ENTRY("Molecule::WXCreate()",5)
7942  mpWXCrystObj=new WXMolecule(parent,this);
7943  VFN_DEBUG_EXIT("Molecule::WXCreate()",5)
7944  return mpWXCrystObj;
7945 }
7946 #endif
7947 
7948 
7950 {
7951  VFN_DEBUG_ENTRY("ZScatterer2Molecule()",6)
7952  Molecule *mol=new Molecule(scatt->GetCrystal(),scatt->GetName());
7953  const unsigned long nb=scatt->GetZAtomRegistry().GetNb();
7954  REAL x0=0,y0=0,z0=0;
7955  for(unsigned int i=0;i<nb;++i)
7956  {
7957  const REAL x=scatt->GetZAtomX(i);
7958  const REAL y=scatt->GetZAtomY(i);
7959  const REAL z=scatt->GetZAtomZ(i);
7960  x0+=x;
7961  y0+=y;
7962  z0+=z;
7963  mol->AddAtom(x,y,z,scatt->GetZAtomRegistry().GetObj(i).GetScatteringPower(),
7964  scatt->GetZAtomRegistry().GetObj(i).GetName());
7965 
7966  #if 0
7967  if(i>0)
7968  {
7969  const RefinablePar* pLength=&(scatt->GetPar(&(scatt->GetZAtomRegistry()
7970  .GetObj(i).GetZBondLength())));
7971  if(pLength->IsFixed())
7972  mol->AddBond(mol->GetAtom(i),mol->GetAtom(scatt->GetZBondAtom(i)),
7973  pLength->GetValue(),.01,.02,false);
7974  else
7975  if(pLength->IsLimited())
7976  mol->AddBond(mol->GetAtom(i),mol->GetAtom(scatt->GetZBondAtom(i)),
7977  (pLength->GetMin()+pLength->GetMax())/2.,.01,.02,false);
7978  }
7979  if(i>1)
7980  {
7981  const RefinablePar* pAngle=&(scatt->GetPar(&(scatt->GetZAtomRegistry()
7982  .GetObj(i).GetZAngle())));
7983  if(pAngle->IsFixed())
7984  mol->AddBondAngle(mol->GetAtom(i),mol->GetAtom(scatt->GetZBondAtom(i)),
7985  mol->GetAtom(scatt->GetZAngleAtom(i)),
7986  pAngle->GetValue(),.01,.02,false);
7987  else
7988  if(pAngle->IsLimited())
7989  mol->AddBondAngle(mol->GetAtom(i),mol->GetAtom(scatt->GetZBondAtom(i)),
7990  mol->GetAtom(scatt->GetZAngleAtom(i)),
7991  (pAngle->GetMin()+pAngle->GetMax())/2.,.01,.02,false);
7992  }
7993  if(i>2)
7994  {
7995  const RefinablePar* pDihed=&(scatt->GetPar(&(scatt->GetZAtomRegistry()
7996  .GetObj(i).GetZDihedralAngle())));
7997  MolAtom *p1=&(mol->GetAtom(i));
7998  MolAtom *p2=&(mol->GetAtom(scatt->GetZBondAtom(i)));
7999  MolAtom *p3=&(mol->GetAtom(scatt->GetZAngleAtom(i)));
8000  MolAtom *p4=&(mol->GetAtom(scatt->GetZDihedralAngleAtom(i)));
8001  if( (fabs(GetBondAngle(*p1,*p2,*p3)-M_PI)>0.3)
8002  &&(fabs(GetBondAngle(*p1,*p2,*p4)-M_PI)>0.3)
8003  &&(fabs(GetBondAngle(*p1,*p3,*p4)-M_PI)>0.3)
8004  &&(fabs(GetBondAngle(*p2,*p3,*p4)-M_PI)>0.3))
8005  {
8006  if(pDihed->IsFixed())
8007  mol->AddDihedralAngle(*p1,*p2,*p3,*p4,pDihed->GetValue(),.01,.02,false);
8008  else
8009  if(((pDihed->GetMax()-pDihed->GetMax())<0.3)&&(i>2)&&(pDihed->IsLimited()))
8010  mol->AddDihedralAngle(*p1,*p2,*p3,*p4,
8011  (pDihed->GetMin()+pDihed->GetMax())/2.,.01,.02,false);
8012  }
8013  }
8014  #endif
8015  mol->GetAtom(i).SetOccupancy(scatt->GetZAtomRegistry().GetObj(i).GetOccupancy());
8016  }
8017 
8018  CrystVector_REAL x(nb),y(nb),z(nb),radius(nb);
8019  vector<pair<const ScatteringPowerAtom *,long> > scattpow(nb);
8020  for(unsigned int i=0;i<nb;++i)
8021  {
8022  x(i)=mol->GetAtom(i).GetX();
8023  y(i)=mol->GetAtom(i).GetY();
8024  z(i)=mol->GetAtom(i).GetZ();
8025  if(mol->GetAtom(i).IsDummy())
8026  {
8027  radius(i)=-1;
8028  scattpow[i].first=0;
8029  }
8030  else
8031  {
8032  radius(i)=mol->GetAtom(i).GetScatteringPower().GetRadius();
8033  scattpow[i].first=dynamic_cast<const ScatteringPowerAtom *>
8034  (&(mol->GetAtom(i).GetScatteringPower()));
8035  scattpow[i].second=scattpow[i].first->GetAtomicNumber();
8036  }
8037  }
8038  for(unsigned int i=0;i<nb;++i)
8039  {
8040  if(scattpow[i].first==0) continue;
8041  const REAL x1=x(i),y1=y(i),z1=z(i);
8042  x += -x1;
8043  y += -y1;
8044  z += -z1;
8045  for(unsigned int j=i+1;j<nb;++j)
8046  {
8047  if(scattpow[j].first==0) continue;
8048  const REAL dist=sqrt(x(j)*x(j)+y(j)*y(j)+z(j)*z(j));
8049  //cout<<" -> d="<<dist<<"("<<radius(i)<<","<<radius(j)<<"):"<<scattpow[i].second<<","<<scattpow[j].second<<endl;
8050  if(dist<(1.10*(radius(i)+radius(j))))
8051  {
8052  if((1!=scattpow[i].second)||(1!=scattpow[j].second))
8053  {
8054  mol->AddBond(mol->GetAtom(i),mol->GetAtom(j),dist,.01,.02,false);
8055  }
8056  }
8057  }
8058  x += x1;
8059  y += y1;
8060  z += z1;
8061  }
8062  mol->BuildConnectivityTable();
8063  for(map<MolAtom*,set<MolAtom*> >::const_iterator pos=mol->GetConnectivityTable().begin();
8064  pos!=mol->GetConnectivityTable().end();++pos)
8065  {
8066  for(set<MolAtom*>::const_iterator pos1=pos->second.begin();
8067  pos1!=pos->second.end();++pos1)
8068  {
8069  for(set<MolAtom*>::const_iterator pos2=pos1;
8070  pos2!=pos->second.end();++pos2)
8071  {
8072  if(pos2==pos1) continue;
8073  if(mol->FindBondAngle(**pos1,*(pos->first),**pos2)== mol->GetBondAngleList().end())
8074  mol->AddBondAngle(**pos1,*(pos->first),**pos2,
8075  GetBondAngle(**pos1,*(pos->first),**pos2),0.01,0.02,false);
8076  }
8077  }
8078  }
8079  x0 /= nb;
8080  y0 /= nb;
8081  z0 /= nb;
8082  mol->GetCrystal().OrthonormalToFractionalCoords(x0,y0,z0);
8083  mol->SetX(x0);
8084  mol->SetY(y0);
8085  mol->SetZ(z0);
8086  mol->UpdateDisplay();
8087  VFN_DEBUG_EXIT("ZScatterer2Molecule()",6)
8088  return mol;
8089 }
8090 
8091 }//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
float string2floatC(const string &s)
Function to convert a substring to a floating point value, imposing a C locale (using '.
Definition: ObjCryst/IO.cpp:59
Molecule * ZScatterer2Molecule(ZScatterer *scatt)
Converter from ZScatterer to a Molecule object.
Definition: Molecule.cpp:7949
void ExpandAtomGroupRecursive(MolAtom *atom, const map< MolAtom *, set< MolAtom * > > &connect, set< MolAtom * > &atomlist, const MolAtom *finalAtom)
Build recursively a list of atoms, starting from a one atom, and given a connectivity table.
Definition: Molecule.cpp:154
REAL LorentzianBiasedRandomMove(const REAL x0, const REAL sigma, const REAL delta, const REAL amplitude)
Random move respecting a gaussian probability distribution with a flat top.
Definition: Molecule.cpp:4761
void BuildRingRecursive(MolAtom *currentAtom, MolAtom *previousAtom, const map< MolAtom *, set< MolAtom * > > &connect, list< MolAtom * > &atomlist, map< set< MolAtom * >, list< MolAtom * > > &ringlist)
Find rings, starting from a one atom, and given a connectivity table.
Definition: Molecule.cpp:5288
REAL GetDihedralAngle(const MolAtom &at1, const MolAtom &at2, const MolAtom &at3, const MolAtom &at4)
Get The dihedral angle defined by 4 atoms.
Definition: Molecule.cpp:114
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
Crystal class: Unit cell, spacegroup, scatterers.
Definition: Crystal.h:98
ScatteringPower & GetScatteringPower(const string &name)
Find a ScatteringPower from its name. Names must be unique in a given Crystal.
Definition: Crystal.cpp:284
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
Exception class for ObjCryst++ library.
Definition: General.h:122
Class to store POV-Ray output options.
Definition: General.h:178
bool mShowHydrogens
Show hydrogens ?
Definition: General.h:184
REAL mXmin
Display limits in reduced coordinates.
Definition: General.h:180
bool mShowLabel
Show labels ?
Definition: General.h:182
Structure holding 3 coordinates, or deriviatives with respect to each of these coordinates.
Definition: Molecule.h:44
MolAtom : atom inside a Molecule.
Definition: Molecule.h:59
virtual ~MolAtom()
Destructor.
Definition: Molecule.cpp:201
const ScatteringPower * mpScattPow
ScatteringPower.
Definition: Molecule.h:137
REAL mX
Cartesian oordinates in the Molecule reference frame.
Definition: Molecule.h:133
size_t int_ptr() const
Access to the integer address of this object, for unique identification from python.
Definition: Molecule.cpp:359
bool mIsInRing
Is the atom in a ring ?
Definition: Molecule.h:141
Molecule * mpMol
Parent Molecule.
Definition: Molecule.h:139
bool IsDummy() const
Returns true if this is a dummy atom, i.e.
Definition: Molecule.cpp:252
bool mIsNonFlipAtom
Can the atom be flipped (this is used for optically active atom which should keep their absolute conf...
Definition: Molecule.h:143
void SetX(const REAL) const
Set the X,Y,Z coordinate - this is const because sometimes their coordinate must be changed even thou...
Definition: Molecule.cpp:247
string mName
Name for this atom.
Definition: Molecule.h:124
bool IsNonFlipAtom() const
Can this atom be flipped (return=false) or should its absolute configuration be kept (return=true)
Definition: Molecule.cpp:354
REAL mOccupancy
Occupancy.
Definition: Molecule.h:135
void SetNonFlipAtom(const bool nonflip)
Set a flag to prevent the atom's absolute configuration to be changed.
Definition: Molecule.cpp:347
void SetIsInRing(const bool r) const
Flag this atom as being in a ring (or not).
Definition: Molecule.cpp:344
Bond between two atoms, also a restraint on the associated bond length.
Definition: Molecule.h:165
size_t int_ptr() const
Access to the integer address of this object, for unique identification from python.
Definition: Molecule.cpp:641
virtual ~MolBond()
Destructor.
Definition: Molecule.cpp:389
REAL mLLK
Stored log(likelihood)
Definition: Molecule.h:244
REAL GetDeriv(const std::map< const MolAtom *, XYZ > &m, const bool llk=false) const
Get the derivative of the bond length, given the derivatives of the atom positions This requires that...
Definition: Molecule.cpp:557
virtual REAL GetLogLikelihood() const
Get -ln(likelihood) for this restraint.
Definition: Molecule.cpp:485
string GetName() const
Name of the bond, e.g. "C3-O4".
Definition: Molecule.cpp:399
MolBond(MolAtom &atom1, MolAtom &atom2, const REAL length, const REAL sigma, const REAL delta, Molecule &parent, const REAL bondOrder=1.)
Constructor.
Definition: Molecule.cpp:378
void CalcGradient(std::map< MolAtom *, XYZ > &m) const
Calc log(likelihood) gradient - versus all atomic coordinates.
Definition: Molecule.cpp:576
Molecule * mpMol
Parent Molecule.
Definition: Molecule.h:242
REAL mDerivLLKCoeff
The factor used to change the derivative of the length/angle, to the derivative of the log(likelihood...
Definition: Molecule.h:253
XYZ mDerivAtom1
Derivatives of the bond length with respect to the coordinates of the atoms.
Definition: Molecule.h:249
Bond angle restraint between 3 atoms.
Definition: Molecule.h:271
virtual REAL GetLogLikelihood() const
Get -ln(likelihood) for this restraint.
Definition: Molecule.cpp:779
REAL GetDeriv(const std::map< const MolAtom *, XYZ > &m, const bool llk=false) const
Get the derivative of the angle, given the derivatives of the atom positions This requires that GetLo...
Definition: Molecule.cpp:873
XYZ mDerivAtom1
Partial derivatives of the angle with respect to the coordinates of the atoms.
Definition: Molecule.h:344
void CalcGradient(std::map< MolAtom *, XYZ > &m) const
Calc log(likelihood) gradient - versus all atomic coordinates.
Definition: Molecule.cpp:897
MolBondAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3, const REAL angle, const REAL sigma, const REAL delta, Molecule &parent)
Constructor.
Definition: Molecule.cpp:660
size_t int_ptr() const
Access to the integer address of this object, for unique identification from python.
Definition: Molecule.cpp:951
REAL mLLK
Stored log(likelihood)
Definition: Molecule.h:339
Molecule * mpMol
Parent Molecule.
Definition: Molecule.h:333
vector< MolAtom * > mvpAtom
The vector of the 3 atoms involved in the bond angle.
Definition: Molecule.h:330
REAL mDerivLLKCoeff
The factor used to change the derivative of the length/angle, to the derivative of the log(likelihood...
Definition: Molecule.h:348
virtual ~MolBondAngle()
Destructor.
Definition: Molecule.cpp:673
Dihedral angle restraint between 4 atoms.
Definition: Molecule.h:366
XYZ mDerivAtom1
Partial derivatives of the angle with respect to the coordinates of the atoms.
Definition: Molecule.h:437
size_t int_ptr() const
Access to the integer address of this object, for unique identification from python.
Definition: Molecule.cpp:1314
vector< MolAtom * > mvpAtom
The vector of the 4 atoms involved in the bond angle.
Definition: Molecule.h:427
REAL mDerivLLKCoeff
The factor used to change the derivative of the length/angle, to the derivative of the log(likelihood...
Definition: Molecule.h:441
virtual ~MolDihedralAngle()
Destructor.
Definition: Molecule.cpp:991
void CalcGradient(std::map< MolAtom *, XYZ > &m) const
Calc log(likelihood) gradient - versus all atomic coordinates.
Definition: Molecule.cpp:1253
REAL mLLK
Stored log(likelihood)
Definition: Molecule.h:432
MolDihedralAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3, MolAtom &atom4, const REAL angle, const REAL sigma, const REAL delta, Molecule &parent)
Constructor.
Definition: Molecule.cpp:970
Molecule * mpMol
Parent Molecule.
Definition: Molecule.h:430
virtual REAL GetLogLikelihood() const
Get -ln(likelihood) for this restraint.
Definition: Molecule.cpp:1106
REAL GetDeriv(const std::map< const MolAtom *, XYZ > &m, const bool llk=false) const
Get the derivative of the Angle, given the derivatives of the atom positions This requires that GetLo...
Definition: Molecule.cpp:1224
size_t int_ptr() const
Access to the integer address of this object, for unique identification from python.
Definition: Molecule.cpp:1357
A quaternion class, used to represent the orientation of the molecule.
Definition: Molecule.h:475
Quaternion GetConjugate() const
Get the conjugate of this quaternion (== the inverse if unit quaternion)
Definition: Molecule.cpp:1397
Quaternion operator*(const Quaternion &q) const
Quaternion multiplication.
Definition: Molecule.cpp:1401
REAL mQ0
The components of the quaternion z=(q0,v) with v=(q1,q2,q3)
Definition: Molecule.h:512
static Quaternion RotationQuaternion(const REAL ang, const REAL v1, const REAL v2, const REAL v3)
Create a rotation quaternion around a given vector for a given angle.
Definition: Molecule.cpp:1386
void Normalize() const
Re-normalize the quaternion to unity.
Definition: Molecule.cpp:1524
Quaternion()
Default constructor, yields q=(1,0,0,0)
Definition: Molecule.cpp:1364
void RotateVector(REAL &v1, REAL &v2, REAL &v3) const
Rotate vector v=(v1,v2,v3). The rotated components are directly written.
Definition: Molecule.cpp:1501
Rigid groups of atoms inside a molecule.
Definition: Molecule.h:527
Quaternion mQuat
The unit quaternion defining the orientation - this is used during optimizations to rotate all atoms ...
Definition: Molecule.h:534
size_t int_ptr() const
Access to the integer address of this object, for unique identification from python.
Definition: Molecule.cpp:1341
REAL mX
The translation of all the atoms as a group The values will be resetted whenever entering or leaving ...
Definition: Molecule.h:537
std::map< const MolBondAngle *, REAL > mvpBrokenBondAngle
List of bond angle restraints modified by this mode The key is the restraint, the value is the deriva...
Definition: Molecule.h:571
Molecule * mpMol
The Molecule corresponding to this stretch mode.
Definition: Molecule.h:580
std::map< const MolAtom *, XYZ > mDerivXYZ
Derivative of the atomic positions versus a change of the bond length.
Definition: Molecule.h:578
std::map< const MolBond *, REAL > mvpBrokenBond
List of bond restraints affected by this mode The key is the restraint, the value is the derivative o...
Definition: Molecule.h:568
std::map< const MolDihedralAngle *, REAL > mvpBrokenDihedralAngle
List of dihedral angle restraints modified by this mode The key is the restraint, the value is the de...
Definition: Molecule.h:574
REAL mBaseAmplitude
The recommended change amplitude, for a base global optimization displacement, to obtain an average 0...
Definition: Molecule.h:588
REAL mLLKDeriv
Derivative of the Molecule's Log(likelihood) versus a change of the bond length.
Definition: Molecule.h:576
Group of atoms for random moves changing a bond length.
Definition: Molecule.h:596
virtual void RandomStretch(const REAL amplitude, const bool keepCenter=true)
Move the atoms according to this mode, randomly.
Definition: Molecule.cpp:1629
MolAtom * mpAtom0
The first atom (fixed).
Definition: Molecule.h:610
const MolBond * mpBond
The (optional) bond length which this stretch mode should respect.
Definition: Molecule.h:614
StretchModeBondLength(MolAtom &at0, MolAtom &at1, const MolBond *pBond)
Constructor If pBond!=0, the bond length restraint is respected.
Definition: Molecule.cpp:1556
virtual void Print(ostream &os, bool full=true) const
Print one-line list of atoms moved.
Definition: Molecule.cpp:1600
virtual void CalcDeriv(const bool derivllk=true) const
Calculate the derivative of the Molecule's Log(likelihood) and atomic positions versus a change of th...
Definition: Molecule.cpp:1566
set< MolAtom * > mvTranslatedAtomList
The set of atoms that are to be translated, including at1.
Definition: Molecule.h:616
MolAtom * mpAtom1
The second atom (first atom moved)
Definition: Molecule.h:612
virtual void Stretch(const REAL change, const bool keepCenter=true)
Move the atoms according to this mode.
Definition: Molecule.cpp:1614
Atoms moved when changing a bond angle.
Definition: Molecule.h:624
MolAtom * mpAtom2
The third atom.
Definition: Molecule.h:643
set< MolAtom * > mvRotatedAtomList
The set of atoms that are to be rotated around the direction going through at1 and perpendicular to t...
Definition: Molecule.h:648
virtual void Print(ostream &os, bool full=true) const
Print one-line list of atoms moved.
Definition: Molecule.cpp:1699
virtual void RandomStretch(const REAL amplitude, const bool keepCenter=true)
Move the atoms according to this mode, randomly.
Definition: Molecule.cpp:1729
MolAtom * mpAtom0
The first atom.
Definition: Molecule.h:639
virtual void CalcDeriv(const bool derivllk=true) const
Calculate the derivative of the Molecule's Log(likelihood) and atomic positions versus a change of th...
Definition: Molecule.cpp:1645
virtual void Stretch(const REAL change, const bool keepCenter=true)
Move the atoms according to this mode.
Definition: Molecule.cpp:1713
StretchModeBondAngle(MolAtom &at0, MolAtom &at1, MolAtom &at2, const MolBondAngle *pBondAngle)
Constructor If pBondAngle!=0, the bond angle length restraint is respected.
Definition: Molecule.cpp:1635
MolAtom * mpAtom1
The second atom.
Definition: Molecule.h:641
const MolBondAngle * mpBondAngle
The (optional) bond angle restraint which this stretch mode should respect.
Definition: Molecule.h:645
Atoms moved when rotated around a bond at0-at1-at2-at3.
Definition: Molecule.h:655
MolAtom * mpAtom1
The first atom.
Definition: Molecule.h:670
MolAtom * mpAtom2
The second atom.
Definition: Molecule.h:672
StretchModeTorsion(MolAtom &at1, MolAtom &at2, const MolDihedralAngle *pDihedralAngle)
Constructor If pDihedralAngle!=0, the dihedral angle length restraint is respected.
Definition: Molecule.cpp:1735
virtual void Print(ostream &os, bool full=true) const
Print one-line list of atoms moved.
Definition: Molecule.cpp:1787
const MolDihedralAngle * mpDihedralAngle
The (optional) bond angle restraint which this stretch mode should respect.
Definition: Molecule.h:675
virtual void RandomStretch(const REAL amplitude, const bool keepCenter=true)
Move the atoms according to this mode, randomly.
Definition: Molecule.cpp:1806
set< MolAtom * > mvRotatedAtomList
The set of atoms that are to be rotated around at1-at2.
Definition: Molecule.h:677
virtual void Stretch(const REAL change, const bool keepCenter=true)
Move the atoms according to this mode.
Definition: Molecule.cpp:1801
virtual void CalcDeriv(const bool derivllk=true) const
Calculate the derivative of the Molecule's Log(likelihood) and atomic positions versus a change of th...
Definition: Molecule.cpp:1745
Atoms moved between two other atoms, using a "twist" of their positions - only small twists of their ...
Definition: Molecule.h:687
MolAtom * mpAtom2
The second atom.
Definition: Molecule.h:703
virtual void Print(ostream &os, bool full=true) const
Print one-line list of atoms moved.
Definition: Molecule.cpp:1868
set< MolAtom * > mvRotatedAtomList
The set of atoms that are to be rotated around at1-at2.
Definition: Molecule.h:705
StretchModeTwist(MolAtom &at1, MolAtom &at2)
Constructor If pDihedralAngle!=0, the dihedral angle length restraint is respected.
Definition: Molecule.cpp:1818
virtual void Stretch(const REAL change, const bool keepCenter=true)
Move the atoms according to this mode.
Definition: Molecule.cpp:1882
MolAtom * mpAtom1
The first atom.
Definition: Molecule.h:701
virtual void RandomStretch(const REAL amplitude, const bool keepCenter=true)
Move the atoms according to this mode, randomly.
Definition: Molecule.cpp:1887
virtual void CalcDeriv(const bool derivllk=true) const
Calculate the derivative of the Molecule's Log(likelihood) and atomic positions versus a change of th...
Definition: Molecule.cpp:1827
Groups of atoms that can be moved using molecular dynamics principles, taking a list of restraints as...
Definition: Molecule.h:714
MDAtomGroup()
Default constructor.
Definition: Molecule.cpp:1903
void Print(ostream &os, bool full=true) const
Print one-line list of atoms moved.
Definition: Molecule.cpp:1921
Molecule : class for complex scatterer descriptions using cartesian coordinates with bond length/angl...
Definition: Molecule.h:760
virtual const ScatteringComponentList & GetScatteringComponentList() const
Get the list of all scattering components for this scatterer.
Definition: Molecule.cpp:3242
vector< MolBondAngle * >::iterator RemoveBondAngle(const MolBondAngle &, const bool del=true)
Remove a BondAngle.
Definition: Molecule.cpp:4053
void BuildMDAtomGroups()
Find groups of atoms that cannot be moved relatively to each other using the free or non-free stretch...
Definition: Molecule.cpp:7458
void TranslateAtomGroup(const set< MolAtom * > &atoms, const REAL dx, const REAL dy, const REAL dz, const bool keepCenter=true)
Translate a group of atoms in a given direction.
Definition: Molecule.cpp:4564
map< MolAtom *, set< MolAtom * > > mConnectivityTable
Connectivity table: for each atom, keep the list of atoms bonded to it.
Definition: Molecule.h:1266
void InitOptions()
Build options for this object.
Definition: Molecule.cpp:7741
void BuildStretchModeTorsion()
Build the groups of atoms moved when changing a dihedral angle, while respecting the Molecule restrai...
Definition: Molecule.cpp:6265
void SetDeleteSubObjInDestructor(const bool b)
Set whether to delete the MolAtoms, MolBonds, MolBondAngles and MolDihedralAngles in the destructor.
Definition: Molecule.cpp:7892
vector< MolDihedralAngle * > mvpDihedralAngle
The list of dihedral angles.
Definition: Molecule.h:1173
std::list< StretchMode * > mvpStretchModeFree
Groups of StretchMode not breaking any restraint (unless the one they are associated to)
Definition: Molecule.h:1365
list< RotorGroup > mvRotorGroupTorsionSingleChain
List of RotorGroups corresponding to free torsion bonds, but with only one chain of atoms listed.
Definition: Molecule.h:1306
void SetCenterAtom(const MolAtom &at)
Get the atom defining the origin of the Molecule Equal to 0 if no atom as been set.
Definition: Molecule.cpp:5101
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
const MolAtom * GetCenterAtom() const
Get the atom defining the origin of the Molecule Equal to 0 if no atom as been set.
Definition: Molecule.cpp:5096
virtual ostream & POVRayDescription(ostream &os, const CrystalPOVRayOptions &options) const
Definition: Molecule.cpp:3256
virtual void EndOptimization()
This should be called by any optimization class at the end of an optimization.
Definition: Molecule.cpp:2576
RefObjOpt mFlexModel
OPtion for the different types of flexibility possible for this molecule: rigid body,...
Definition: Molecule.h:1237
list< MolRing > mvRing
The list of rings.
Definition: Molecule.h:1188
virtual void SetName(const string &name)
Name of the object.
Definition: Molecule.cpp:2171
void BuildRotorGroup()
Build the groups of atoms that will be rotated during global optimization.
Definition: Molecule.cpp:5421
void BuildStretchModeBondAngle()
Build the groups of atoms moved when changing a bond angle, while respecting the Molecule restraints.
Definition: Molecule.cpp:5928
virtual unsigned int GetNbLSQFunction() const
Number of LSQ functions.
Definition: Molecule.cpp:3139
std::vector< RigidGroup * > mvRigidGroup
Rigid groups of atoms.
Definition: Molecule.h:1183
std::vector< MolZAtom > mAsZMatrix
The Molecule, as a lightweight ZMatrix, for export purposes.
Definition: Molecule.h:1392
void BuildConnectivityTable() const
Build the Connectivity table.
Definition: Molecule.cpp:5369
list< MDAtomGroup > mvMDAtomGroup
Groups of atoms that should be moved according to molecular dynamics principles.
Definition: Molecule.h:1380
RefObjOpt mMoleculeCenter
Option to choose the center of rotation of the Molecule for the global orientation either as the geom...
Definition: Molecule.h:1257
void FlipAtomGroup(const FlipGroup &, const bool keepCenter=true)
Flip a group of atom. See Molecule::FlipGroup.
Definition: Molecule.cpp:7812
list< StretchModeTwist > mvStretchModeTwist
List of StretchModeTwist.
Definition: Molecule.h:1362
void UpdateScattCompList() const
Update the Molecule::mScattCompList from the cartesian coordinates of all atoms, and the orientation ...
Definition: Molecule.cpp:7617
vector< MolDihedralAngle * >::iterator RemoveDihedralAngle(const MolDihedralAngle &, const bool del=true)
Remove a dihedral angle.
Definition: Molecule.cpp:4101
void RigidifyWithDihedralAngles()
Add dihedral angles so as to rigidify the Molecule.
Definition: Molecule.cpp:4657
list< StretchModeBondAngle > mvStretchModeBondAngle
List of StretchModeBondLength.
Definition: Molecule.h:1358
const std::vector< RigidGroup * > & GetRigidGroupList() const
List of rigid group of atoms.
Definition: Molecule.cpp:4459
virtual void InitRefParList()
Definition: Molecule.cpp:5275
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
bool mDeleteSubObjInDestructor
Base Rotation amplitude (in radians) for the Molecule, so that the average atomic displacement is equ...
Definition: Molecule.h:1201
REAL mMDMoveEnergy
Relative energy of molecule during molecular dynamics move Default: 40, 10 (slow conformation change)...
Definition: Molecule.h:1389
Quaternion mQuat
The unit quaternion defining the orientation.
Definition: Molecule.h:1192
CrystVector_REAL mLSQObs
Current LSQ Calc - one value for each restraint (bond distance, angle or dihedral angle ideal values)
Definition: Molecule.h:1406
virtual void XMLInput(istream &is, const XMLCrystTag &tag)
Input From stream.
Definition: Molecule.cpp:2331
vector< MolAtom * >::iterator RemoveAtom(MolAtom &, const bool del=true)
Remove an atom.
Definition: Molecule.cpp:3932
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: Molecule.cpp:2449
vector< MolDihedralAngle * >::const_iterator FindDihedralAngle(const MolAtom &at1, const MolAtom &at2, const MolAtom &at3, const MolAtom &at4) const
Searches whether a dihedral between four atoms already exists, searching for either (at1,...
Definition: Molecule.cpp:4121
RefinableObjClock & GetRigidGroupClock()
Get the clock associated to the list of rigid groups (clicked also whenever a rigid group is modified...
Definition: Molecule.cpp:4654
virtual void TagNewBestConfig() const
During a global optimization, tells the object that the current config is the latest "best" config.
Definition: Molecule.cpp:3191
CrystVector_REAL mLSQWeight
Current LSQ Calc - one value for each restraint(bond distance, angle or dihedral angle sigmas)
Definition: Molecule.h:1408
virtual void XMLOutput(ostream &os, int indent=0) const
Output to stream in well-formed XML.
Definition: Molecule.cpp:2227
vector< MolBond * >::const_iterator FindBond(const MolAtom &, const MolAtom &) const
Searches whether a bond between two atoms already exists.
Definition: Molecule.cpp:4020
list< FlipGroup > mvFlipGroup
The list of FlipGroups.
Definition: Molecule.h:1352
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 Molecule * CreateCopy() const
Definition: Molecule.cpp:2159
vector< MolAtom * >::reverse_iterator FindAtom(const string &name)
Search a MolAtom from its name.
Definition: Molecule.cpp:7720
REAL mLogLikelihoodScale
Scale (multiplier) for the log(likelihood)
Definition: Molecule.h:1402
void BuildStretchModeTwist()
Build the groups of atoms used to twist internally the Molecule, e.g.
Definition: Molecule.cpp:6679
virtual const CrystVector_REAL & GetLSQObs(const unsigned int) const
Get the observed values for the LSQ function.
Definition: Molecule.cpp:3157
virtual int GetNbComponent() const
Number of components in the scatterer (eg number of point scatterers)
Definition: Molecule.cpp:3240
void BuildStretchModeGroups()
Separate StretchMode that break more than their assigned restraint from others.
Definition: Molecule.cpp:7303
const RefinableObjClock & GetAtomScattPowClock() const
Get the clock associated to the scattering powers.
Definition: Molecule.cpp:4651
const std::vector< MolZAtom > & AsZMatrix(const bool keeporder) const
Molecule as Z-matrix.
Definition: Molecule.cpp:5183
list< StretchModeTorsion > mvStretchModeTorsion
List of StretchModeBondLength.
Definition: Molecule.h:1360
RefinableObjClock mClockRestraint
This clock is the parent of mClockAtomList, mClockBondList, mClockBondAngleList, mClockDihedralAngleL...
Definition: Molecule.h:1212
void AddRigidGroup(const RigidGroup &, const bool updateDisplay=true)
Add a rigid group of atoms.
Definition: Molecule.cpp:4138
RefObjOpt mOptimizeOrientation
Option to optimize the Molecule's orientation.
Definition: Molecule.h:1252
void OptimizeConformation(const long nbTrial=10000, const REAL stopCost=0.)
Minimize configuration from internal restraints (bond lengths, angles and dihedral angles).
Definition: Molecule.cpp:4249
const MolAtom * mpCenterAtom
Atom chosen as center of rotation, if mRotationCenter is set to use an atom rather than the geometric...
Definition: Molecule.h:1262
virtual void RandomizeConfiguration()
Randomize Configuration (before a global optimization).
Definition: Molecule.cpp:2603
void BuildRingList()
Build the list of rings in the molecule.
Definition: Molecule.cpp:5329
virtual REAL GetLogLikelihood() const
Get -log(likelihood) of the current configuration for the object.
Definition: Molecule.cpp:3125
void MolecularDynamicsEvolve(std::map< MolAtom *, XYZ > &v0, const unsigned nbStep, const REAL dt, const std::vector< MolBond * > &vb, const std::vector< MolBondAngle * > &va, const std::vector< MolDihedralAngle * > &vd, std::map< RigidGroup *, std::pair< XYZ, XYZ > > &vr, REAL nrj0=0)
Change the conformation of the molecule using molecular dynamics principles.
Definition: Molecule.cpp:4343
std::string GetFormula() const
Formula with atoms in alphabetic order.
Definition: Molecule.cpp:2193
void RestraintStatus(ostream &os) const
Print the status of all restraints (bond length, angles...)
Definition: Molecule.cpp:4616
void RotateAtomGroup(const MolAtom &at1, const MolAtom &at2, const set< MolAtom * > &atoms, const REAL angle, const bool keepCenter=true)
Rotate a group of atoms around an axis defined by two atoms.
Definition: Molecule.cpp:4462
vector< MolBondAngle * > mvpBondAngle
The list of bond angles.
Definition: Molecule.h:1169
void RestraintExport(ostream &os) const
Print the restraints (bond length, angles...) as whole labels and number in column text format which ...
Definition: Molecule.cpp:4591
void TuneGlobalOptimRotationAmplitude()
Tune the rotation amplitude for free torsions and for the overall Molecule Rotation.
Definition: Molecule.cpp:6945
CrystVector_REAL mLSQCalc
Current LSQ Calc - one value for each restraint (bond distance, angle or dihedral angle)
Definition: Molecule.h:1404
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
list< StretchModeBondLength > mvStretchModeBondLength
List of StretchModeBondLength.
Definition: Molecule.h:1356
virtual string GetComponentName(const int i) const
Name for the i-th component of this scatterer.
Definition: Molecule.cpp:3250
virtual void UpdateDisplay() const
If there is an interface, this should be automatically be called each time there is a 'new,...
Definition: Molecule.cpp:2443
vector< MolBond * > mvpBond
The list of bonds.
Definition: Molecule.h:1165
void ResetRigidGroupsPar() const
Set the orientation & translation parameters of all rigid groups to 0, after correcting the atomic po...
Definition: Molecule.cpp:7896
void AddDihedralAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3, MolAtom &atom4, const REAL angle, const REAL sigma, const REAL delta, const bool updateDisplay=true)
Add a dihedral angle restraint.
Definition: Molecule.cpp:4087
virtual void Print() const
Print some info about the scatterer (ideally this should be one line...).
Definition: Molecule.cpp:2221
std::vector< RigidGroup * >::iterator RemoveRigidGroup(const RigidGroup &group, const bool updateDisplay=true, const bool del=true)
Remove a rigid group of atoms.
Definition: Molecule.cpp:4218
const map< MolAtom *, set< MolAtom * > > & GetConnectivityTable()
Get the connectivity table.
Definition: Molecule.cpp:4639
void BuildStretchModeBondLength()
Build the groups of atoms moved when stretching a bond length, while respecting the Molecule restrain...
Definition: Molecule.cpp:5656
void OptimizeConformationSteepestDescent(const REAL maxStep=0.1, const unsigned nbStep=1)
Optimize the conformation from internal restraints (bond lengths, angles and dihedral angles),...
Definition: Molecule.cpp:4267
list< RotorGroup > mvRotorGroupInternal
List of RotorGroups for internal rotations.
Definition: Molecule.h:1312
void BuildFlipGroup()
Build the groups of atoms that can be flipped.
Definition: Molecule.cpp:7124
REAL mLogLikelihood
The current log(likelihood)
Definition: Molecule.h:1395
virtual const CrystVector_REAL & GetLSQDeriv(const unsigned int n, RefinablePar &par)
Get the first derivative values for the LSQ function, for a given parameter.
Definition: Molecule.cpp:3185
Molecule(Crystal &cryst, const string &name="")
Constructor.
Definition: Molecule.cpp:1946
vector< MolAtom * > mvpAtom
The list of atoms.
Definition: Molecule.h:1161
REAL BondAngleRandomChange(const StretchModeBondAngle &mode, const REAL amplitude, const bool respectRestraint=true)
change a bond angle, while respecting the Restraint (if any).
Definition: Molecule.cpp:4998
REAL BondLengthRandomChange(const StretchModeBondLength &mode, const REAL amplitude, const bool respectRestraint=true)
Stretch a bond, while respecting the Restraint (if any).
Definition: Molecule.cpp:4954
RefinableObjClock & GetBondListClock()
get the clock associated to the list of bonds
Definition: Molecule.cpp:4645
virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type)
Make a random move of the current configuration.
Definition: Molecule.cpp:2719
RefinableObjClock & GetAtomPositionClock()
Get the clock associated to the atomic positions.
Definition: Molecule.cpp:4648
~Molecule()
Destructor.
Definition: Molecule.cpp:2134
ScatteringComponentList mScattCompList
The list of scattering components.
Definition: Molecule.h:1157
RefObjOpt mAutoOptimizeConformation
Option to automatically optimize the starting conformation, if the total restraint cost is too high.
Definition: Molecule.h:1247
std::list< StretchMode * > mvpStretchModeNotFree
Groups of StretchMode breaking restraints (beyond the one they are associated to)
Definition: Molecule.h:1367
REAL mMDMoveFreq
Frequency of using molecular dynamics move during GlobalOptRandomMove()
Definition: Molecule.h:1386
virtual const CrystVector_REAL & GetLSQCalc(const unsigned int) const
Get the current calculated value for the LSQ function.
Definition: Molecule.cpp:3144
std::set< MolAtom * > mvMDFullAtomGroup
Full list of atoms that can be moved using molecular dynamics This excludes any atom part of a rigid ...
Definition: Molecule.h:1383
virtual const CrystVector_REAL & GetLSQWeight(const unsigned int) const
Get the weight values for the LSQ function.
Definition: Molecule.cpp:3170
virtual const string & GetClassName() const
Name for this class ("RefinableObj", "Crystal",...).
Definition: Molecule.cpp:2165
list< RotorGroup > mvRotorGroupTorsion
List of RotorGroups corresponding to free torsion bonds.
Definition: Molecule.h:1297
REAL DihedralAngleRandomChange(const StretchModeTorsion &mode, const REAL amplitude, const bool respectRestraint=true)
Change a dihedral angle, while respecting the Restraint (if any).
Definition: Molecule.cpp:5055
Defines a group of atoms which can be rotated around an axis defined by two other atoms.
Definition: Molecule.h:1271
RotorGroup(const MolAtom &at1, const MolAtom &at2)
Constructor, with the two atoms around which the rotation shall be made.
Definition: Molecule.cpp:5417
When 3(A1..1n) or more atoms are connected to a same atom A, it defines a 'flip' group,...
Definition: Molecule.h:1324
list< pair< const MolAtom *, set< MolAtom * > > > mvRotatedChainList
The set of atoms that are to be rotated during the flip.
Definition: Molecule.h:1340
const MolAtom * mpAtom2
The second atom defining the rotation axis.
Definition: Molecule.h:1333
const MolAtom * mpAtom0
The atom which is an asymmetric center.
Definition: Molecule.h:1329
FlipGroup(const MolAtom &at0, const MolAtom &at1, const MolAtom &at2)
Constructor, with the central atom.
Definition: Molecule.cpp:7807
const MolAtom * mpAtom1
The first atom defining the rotation axis.
Definition: Molecule.h:1331
Crystal * mpCryst
The crystal in which the Scatterer is This is needed so that we can know which scattering powers are ...
Definition: Scatterer.h:304
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
REAL GetOccupancy() const
Get the occupancy of the scatterer (0.
Definition: Scatterer.cpp:106
const Crystal & GetCrystal() const
In which crystal is this Scatterer included ?
Definition: Scatterer.cpp:137
RefinableObjClock mClockScattCompList
Definition: Scatterer.h:297
CrystVector_REAL mXYZ
coordinates of the scatterer (or of its center..)
Definition: Scatterer.h:283
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
RefinableObjClock mClockScatterer
Last time anything (number of atoms, positions, scattering power) was changed.
Definition: Scatterer.h:295
REAL mOccupancy
Occupancy : 0 <= occ <= 1 For a multi-atom scatterer (polyhedron,..), this is the overall occupancy o...
Definition: Scatterer.h:289
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 REAL GetRadius() const =0
Return the physical radius of this type of scatterer (for 3D display purposes).
The Scattering Power for an Atom.
int GetAtomicNumber() const
Atomic number for this atom.
list of scattering positions in a crystal, associated with the corresponding occupancy and a pointer ...
long GetNbComponent() const
Number of components.
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
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
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
ZScatterer: the basic type of complex scatterers, where atom positions are defined using a standard "...
Definition: ZScatterer.h:191
REAL GetZAtomX(const int i) const
Get the X fractionnal coordinate of atom i.
Definition: ZScatterer.cpp:438
const ObjRegistry< ZAtom > & GetZAtomRegistry() const
Access to the registry of ZAtoms.
Definition: ZScatterer.cpp:466
long GetZBondAtom(const int i) const
Index of the 1st atom used to define the i-th atom in the Z-Matrix (the one from which the bondlength...
Definition: ZScatterer.cpp:441
REAL GetZAtomZ(const int i) const
Get the Z fractionnal coordinate of atom i.
Definition: ZScatterer.cpp:440
long GetZDihedralAngleAtom(const int i) const
Index of the 3rd atom used to define the i-th atom in the Z-Matrix (the one from which the dihedral a...
Definition: ZScatterer.cpp:447
REAL GetZAtomY(const int i) const
Get the Y fractionnal coordinate of atom i.
Definition: ZScatterer.cpp:439
long GetZAngleAtom(const int i) const
Index of the 2nd atom used to define the i-th atom in the Z-Matrix (the one from which the angle is c...
Definition: ZScatterer.cpp:444
Vector library (Blitz++ mimic) for ObjCryst++.
Definition: CrystVector.h:123
Cubic spline interpolation.
Definition: CrystVector.h:565
void AddRefinableObj(RefinableObj &)
Add a refined object. All sub-objects are also added.
Base object for Monte-Carlo Global Optimization methods.
void SetAlgorithmParallTempering(const AnnealingSchedule scheduleTemp, const REAL tMax, const REAL tMin, const AnnealingSchedule scheduleMutation=ANNEALING_CONSTANT, const REAL mutMax=16., const REAL mutMin=.125)
Set the refinement method to Parallel Tempering.
virtual void Optimize(long &nbSteps, const bool silent=false, const REAL finalcost=0, const REAL maxTime=-1)
Launch optimization (a single run) for N steps.
class to input or output a well-formatted xml beginning or ending tag.
class of refinable parameter types.
Definition: RefinableObj.h:80
bool IsDescendantFromOrSameAs(const RefParType *type) const
Returns true if the parameter is a descendant of 'type'.
We need to record exactly when refinable objects have been modified for the last time (to avoid re-co...
Definition: RefinableObj.h:140
void Reset()
Reset a Clock to 0, to force an update.
void AddChild(const RefinableObjClock &)
Add a 'child' clock.
void Click()
Record an event for this clock (generally, the 'time' an object has been modified,...
Generic class for parameters of refinable objects.
Definition: RefinableObj.h:225
void XMLOutput(ostream &os, const string &name, int indent=0) const
XMLOutput to stream in well-formed XML.
void SetDerivStep(const REAL)
Fixed step to use to compute numerical derivative.
REAL GetMin() const
Minimum value allowed (if limited or periodic)
REAL GetValue() const
of the parameter.
void SetGlobalOptimStep(const REAL)
Maximum step to use during Global Optimization algorithms.
void AssignClock(RefinableObjClock &clock)
REAL GetMax() const
Get the maximum value allowed (if limited)
void SetName(const string &)
Set the name of the parameter. It should be unique in the RefinableObj.
void XMLInput(istream &is, const XMLCrystTag &tag)
XMLInput From stream.
void XMLOutput(ostream &os, int indent=0) const
XMLOutput to stream in well-formed XML.
virtual void EndOptimization()
This should be called by any optimization class at the end of an optimization.
void RestoreParamSet(const unsigned long id)
Restore a saved set of values.
void AddPar(const RefinablePar &newRefPar)
Add a refinable parameter.
void AddRestraint(Restraint *pNewRestraint)
Add a new restraint.
bool IsBeingRefined() const
Is the object being refined ? (Can be refined by one algorithm at a time only.)
virtual void SetName(const string &name)
Name of the object.
virtual const CrystVector_REAL & GetLSQDeriv(const unsigned int, RefinablePar &)
Get the first derivative values for the LSQ function, for a given parameter.
RefinablePar & GetPar(const long i)
Access all parameters in the order they were inputted.
vector< Restraint * >::iterator RemoveRestraint(Restraint *pRestraint)
Remove a restraint from the list of known restraints.
vector< RefinablePar * >::iterator RemovePar(RefinablePar *refPar)
Remove a refinable parameter.
unsigned int GetNbOption() const
Number of Options for this object.
virtual const string & GetName() const
Name of the object.
void SaveParamSet(const unsigned long id) const
Save the current set of refined values over a previously-created set of saved values.
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.
RefObjOpt & GetOption(const unsigned int i)
Access to the options.
ObjRegistry< RefObjOpt > mOptionRegistry
List of options for this object.
void AddOption(RefObjOpt *opt)
void ClearParamSet(const unsigned long id) const
Erase the param set with the given id, releasing memory.
unsigned long CreateParamSet(const string name="") const
Save the current set of refined values in a new set.
virtual void UpdateDisplay() const
If there is an interface, this should be automatically be called each time there is a 'new,...
virtual REAL GetLogLikelihood() const
Get -log(likelihood) of the current configuration for the object.
vector< Restraint * > mvpRestraint
Vector of pointers to the restraints for this object.
string mName
Name for this RefinableObject. Should be unique, at least in the same scope.+.
virtual void RandomizeConfiguration()
Randomize Configuration (before a global optimization).
virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type=gpRefParTypeObjCryst)
Make a random move of the current configuration.
Abstract base class for all objects in wxCryst.
Definition: wxCryst.h:128
wx class for MolAtom objects
Definition: wxMolecule.h:44
wx class for MolBond objects
Definition: wxMolecule.h:62
wx class for MolBondAngle objects
Definition: wxMolecule.h:85
wx class for MolDihedralAngle objects
Definition: wxMolecule.h:106
wxCryst class for Molecule objects
Definition: wxMolecule.h:128