FOX/ObjCryst++  1.10.X (development)
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 
28 #include "ObjCryst/Quirks/VFNStreamFormat.h"
29 #include "ObjCryst/ObjCryst/Molecule.h"
30 #include "ObjCryst/RefinableObj/GlobalOptimObj.h"
31 
32 #ifdef OBJCRYST_GL
33  #ifdef __DARWIN__
34  #include <OpenGL/glu.h>
35  #else
36  #include <GL/glu.h>
37  #endif
38 #endif
39 
40 #ifdef __WX__CRYST__
41  #include "ObjCryst/wxCryst/wxMolecule.h"
42 #endif
43 
44 //#include <xmmintrin.h>
45 
46 // Try new approach for rigid bodies ?
47 #define RIGID_BODY_STRICT_EXPERIMENTAL
48 
49 // Tighter restraints x**2+x**4+x**6 instead of just X**2
50 #undef RESTRAINT_X2_X4_X6
51 
52 using namespace std;
53 
54 
55 namespace ObjCryst
56 {
57 XYZ::XYZ(REAL x0,REAL y0,REAL z0):x(x0),y(y0),z(z0){};
58 
59 REAL GetBondLength(const MolAtom&at1,const MolAtom&at2)
60 {
61  //TAU_PROFILE("GetBondLength()","REAL (...)",TAU_DEFAULT);
62 
63  /*
64  __m128 m128=_mm_set_ps(0.0f,
65  at1.GetZ()-at2.GetZ(),
66  at1.GetY()-at2.GetY(),
67  at1.GetX()-at2.GetX());
68 
69  __m128 a = _mm_mul_ps(m128,m128);
70 
71  // horizontal add
72  __m128 b = _mm_add_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0,0,0,0)),
73  _mm_add_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(1,1,1,1)),
74  _mm_shuffle_ps(a, a, _MM_SHUFFLE(2,2,2,2))));
75  union m128_float
76  {
77  __m128 m128;
78  struct
79  {
80  float x, y, z, pad;
81  };
82  };
83  union m128_float l;
84  l.m128 = _mm_sqrt_ss(b);
85 
86  return l.x;
87  */
88  return sqrt( (at1.GetX()-at2.GetX())
89  *(at1.GetX()-at2.GetX())
90  +(at1.GetY()-at2.GetY())
91  *(at1.GetY()-at2.GetY())
92  +(at1.GetZ()-at2.GetZ())
93  *(at1.GetZ()-at2.GetZ()) );
94 }
95 REAL GetBondAngle(const MolAtom &at1,const MolAtom &at2,const MolAtom &at3)
96 {
97  //TAU_PROFILE("GetBondAngle()","REAL (...)",TAU_DEFAULT);
98  const REAL x21=at1.GetX()-at2.GetX();
99  const REAL y21=at1.GetY()-at2.GetY();
100  const REAL z21=at1.GetZ()-at2.GetZ();
101  const REAL x23=at3.GetX()-at2.GetX();
102  const REAL y23=at3.GetY()-at2.GetY();
103  const REAL z23=at3.GetZ()-at2.GetZ();
104  const REAL norm21_norm23= sqrt( (x21*x21+y21*y21+z21*z21)
105  *(x23*x23+y23*y23+z23*z23)+1e-6);
106  const REAL angle=(x21*x23+y21*y23+z21*z23)/norm21_norm23;
107  if(angle>=1) return 0;
108  if(angle<=-1) return M_PI;
109  return acos(angle);
110 }
111 REAL GetDihedralAngle(const MolAtom &at1,const MolAtom &at2,const MolAtom &at3,const MolAtom &at4)
112 {
113  //TAU_PROFILE("GetDihedralAngle()","REAL (...)",TAU_DEFAULT);
114  const REAL x21=at1.GetX()-at2.GetX();
115  const REAL y21=at1.GetY()-at2.GetY();
116  const REAL z21=at1.GetZ()-at2.GetZ();
117 
118  const REAL x34=at4.GetX()-at3.GetX();
119  const REAL y34=at4.GetY()-at3.GetY();
120  const REAL z34=at4.GetZ()-at3.GetZ();
121 
122  const REAL x23=at3.GetX()-at2.GetX();
123  const REAL y23=at3.GetY()-at2.GetY();
124  const REAL z23=at3.GetZ()-at2.GetZ();
125 
126  // v21 x v23
127  const REAL x123= y21*z23-z21*y23;
128  const REAL y123= z21*x23-x21*z23;
129  const REAL z123= x21*y23-y21*x23;
130 
131  // v32 x v34 (= -v23 x v34)
132  const REAL x234= -(y23*z34-z23*y34);
133  const REAL y234= -(z23*x34-x23*z34);
134  const REAL z234= -(x23*y34-y23*x34);
135 
136  const REAL norm123_norm234= sqrt( (x123*x123+y123*y123+z123*z123)
137  *(x234*x234+y234*y234+z234*z234)+1e-6);
138 
139  REAL angle=(x123*x234+y123*y234+z123*z234)/norm123_norm234;
140  if(angle>= 1) angle=0;
141  else
142  {
143  if(angle<=-1) angle=M_PI;
144  else angle=acos(angle);
145  }
146  if((x21*x234 + y21*y234 + z21*z234)<0) return -angle;
147  return angle;
148 }
149 
150 
152  const map<MolAtom*,set<MolAtom*> > &connect,
153  set<MolAtom*> &atomlist,const MolAtom* finalAtom)
154 {
155  const pair<set<MolAtom*>::iterator,bool> status=atomlist.insert(atom);
156  if(false==status.second) return;
157  if(finalAtom==atom) return;
158  map<MolAtom*,set<MolAtom*> >::const_iterator c=connect.find(atom);
159  set<MolAtom*>::const_iterator pos;
160  for(pos=c->second.begin();pos!=c->second.end();++pos)
161  {
162  ExpandAtomGroupRecursive(*pos,connect,atomlist,finalAtom);
163  }
164 }
165 
167  const map<MolAtom*,set<MolAtom*> > &connect,
168  map<MolAtom*,unsigned long> &atomlist,const unsigned long maxdepth,unsigned long depth)
169 {
170  if(atomlist.count(atom)>0)
171  if(atomlist[atom]<=depth) return;
172  atomlist[atom]=depth;
173  if(depth==maxdepth) return;//maxdepth reached
174  map<MolAtom*,set<MolAtom*> >::const_iterator c=connect.find(atom);
175  set<MolAtom*>::const_iterator pos;
176  for(pos=c->second.begin();pos!=c->second.end();++pos)
177  {
178  ExpandAtomGroupRecursive(*pos,connect,atomlist,maxdepth,depth+1);
179  }
180 }
181 
182 //######################################################################
183 //
184 // MolAtom
185 //
186 //######################################################################
187 
188 MolAtom::MolAtom(const REAL x, const REAL y, const REAL z,
189  const ScatteringPower *pPow, const string &name, Molecule &parent):
190 mName(name),mX(x),mY(y),mZ(z),mOccupancy(1.),mpScattPow(pPow),mpMol(&parent),mIsInRing(false)
191 #ifdef __WX__CRYST__
192 ,mpWXCrystObj(0)
193 #endif
194 {
195  VFN_DEBUG_MESSAGE("MolAtom::MolAtom()",4)
196 }
197 
199 {
200 #ifdef __WX__CRYST__
201 this->WXDelete();
202 #endif
203 }
204 
205 void MolAtom::SetName(const string &name)
206 {
207  mName=name;
208  // Set parameter's name in the parent molecule
209  // The atom should already be part of a Molecule, but just in case be careful
210  if((mName!="") && (mpMol!=0))
211  {
212  try
213  {
214  mpMol->GetPar(&mX).SetName(mpMol->GetName()+"_"+mName+"_x");
215  mpMol->GetPar(&mY).SetName(mpMol->GetName()+"_"+mName+"_y");
216  mpMol->GetPar(&mZ).SetName(mpMol->GetName()+"_"+mName+"_z");
217  }
218  catch(const ObjCrystException &except)
219  {
220  cerr<<"MolAtom::SetName(): Atom parameters not yet declared in a Molecule ?"<<endl;
221  }
222  }
223 }
224 
225 const string& MolAtom::GetName()const{return mName;}
226  string& MolAtom::GetName() {return mName;}
227 
228 const Molecule& MolAtom::GetMolecule()const{return *mpMol;}
229  Molecule& MolAtom::GetMolecule() {return *mpMol;}
230 
231 const REAL& MolAtom::X()const{return mX;}
232 const REAL& MolAtom::Y()const{return mY;}
233 const REAL& MolAtom::Z()const{return mZ;}
234 
235 REAL& MolAtom::X(){return mX;}
236 REAL& MolAtom::Y(){return mY;}
237 REAL& MolAtom::Z(){return mZ;}
238 
239 REAL MolAtom::GetX()const{return mX;}
240 REAL MolAtom::GetY()const{return mY;}
241 REAL MolAtom::GetZ()const{return mZ;}
242 REAL MolAtom::GetOccupancy()const{return mOccupancy;}
243 
244 void MolAtom::SetX(const REAL a)const{ mX=a;mpMol->GetAtomPositionClock().Click();}
245 void MolAtom::SetY(const REAL a)const{ mY=a;mpMol->GetAtomPositionClock().Click();}
246 void MolAtom::SetZ(const REAL a)const{ mZ=a;mpMol->GetAtomPositionClock().Click();}
247 void MolAtom::SetOccupancy(const REAL a){ mOccupancy=a;}
248 
249 bool MolAtom::IsDummy()const{return mpScattPow==0;}
250 const ScatteringPower& MolAtom::GetScatteringPower()const{return *mpScattPow;}
251 void MolAtom::SetScatteringPower(const ScatteringPower& pow){mpScattPow=&pow;}
252 
253 void MolAtom::XMLOutput(ostream &os,int indent)const
254 {
255  VFN_DEBUG_ENTRY("MolAtom::XMLOutput()",4)
256  for(int i=0;i<indent;i++) os << " " ;
257  XMLCrystTag tag("Atom",false,true);
258  tag.AddAttribute("Name",this->GetName());
259  if(!this->IsDummy())tag.AddAttribute("ScattPow",this->GetScatteringPower().GetName());
260  {
261  stringstream ss;
262  ss.precision(os.precision());
263  ss <<mX;
264  tag.AddAttribute("x",ss.str());
265  }
266  {
267  stringstream ss;
268  ss.precision(os.precision());
269  ss <<mY;
270  tag.AddAttribute("y",ss.str());
271  }
272  {
273  stringstream ss;
274  ss.precision(os.precision());
275  ss <<mZ;
276  tag.AddAttribute("z",ss.str());
277  }
278  {
279  stringstream ss;
280  ss.precision(os.precision());
281  ss <<mOccupancy;
282  tag.AddAttribute("Occup",ss.str());
283  }
284  os <<tag<<endl;
285  VFN_DEBUG_EXIT("MolAtom::XMLOutput()",4)
286 }
287 
288 void MolAtom::XMLInput(istream &is,const XMLCrystTag &tag)
289 {
290  VFN_DEBUG_ENTRY("MolAtom::XMLInput()",7)
291  string name;
292  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
293  {
294  if("Name"==tag.GetAttributeName(i))
295  {
296  name=tag.GetAttributeValue(i);
297  }
298  if("ScattPow"==tag.GetAttributeName(i))
299  {
300  mpScattPow=&(mpMol->GetCrystal().GetScatteringPower(tag.GetAttributeValue(i)));
301  }
302  if("x"==tag.GetAttributeName(i))
303  {
304  stringstream ss(tag.GetAttributeValue(i));
305  ss >>mX;
306  }
307  if("y"==tag.GetAttributeName(i))
308  {
309  stringstream ss(tag.GetAttributeValue(i));
310  ss >>mY;
311  }
312  if("z"==tag.GetAttributeName(i))
313  {
314  stringstream ss(tag.GetAttributeValue(i));
315  ss >>mZ;
316  }
317  if("Occup"==tag.GetAttributeName(i))
318  {
319  stringstream ss(tag.GetAttributeValue(i));
320  ss >>mOccupancy;
321  }
322  }
323  this->SetName(name);
324  VFN_DEBUG_EXIT("MolAtom::XMLInput()",7)
325 }
326 
327 void MolAtom::SetIsInRing(const bool r)const{mIsInRing=r;}
328 bool MolAtom::IsInRing()const{return mIsInRing;}
329 
330 #ifdef __WX__CRYST__
331 WXCrystObjBasic* MolAtom::WXCreate(wxWindow* parent)
332 {
333  VFN_DEBUG_ENTRY("MolAtom::WXCreate()",5)
334  mpWXCrystObj=new WXMolAtom(parent,this);
335  VFN_DEBUG_EXIT("MolAtom::WXCreate()",5)
336  return mpWXCrystObj;
337 }
338 WXCrystObjBasic* MolAtom::WXGet(){return mpWXCrystObj;}
339 void MolAtom::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;}
340 void MolAtom::WXNotifyDelete(){mpWXCrystObj=0;}
341 #endif
342 //######################################################################
343 //
344 // MolBond
345 //
346 //######################################################################
348  const REAL length0, const REAL sigma, const REAL delta,
349  Molecule &parent,const REAL bondOrder):
350 mAtomPair(make_pair(&atom1,&atom2)),
351 mLength0(length0),mDelta(delta),mSigma(sigma),
352 mBondOrder(bondOrder),mIsFreeTorsion(false),mpMol(&parent)
353 #ifdef __WX__CRYST__
354 ,mpWXCrystObj(0)
355 #endif
356 {}
357 
359 {
360 #ifdef __WX__CRYST__
361 this->WXDelete();
362 #endif
363 }
364 
365 const Molecule& MolBond::GetMolecule()const{return *mpMol;}
366  Molecule& MolBond::GetMolecule() {return *mpMol;}
367 
368 string MolBond::GetName()const
369 {return this->GetAtom1().GetName()+"-"+this->GetAtom2().GetName();}
370 
371 void MolBond::XMLOutput(ostream &os,int indent)const
372 {
373  VFN_DEBUG_ENTRY("MolBond::XMLOutput()",4)
374  for(int i=0;i<indent;i++) os << " " ;
375  XMLCrystTag tag("Bond",false,true);
376  tag.AddAttribute("Atom1",mAtomPair.first->GetName());
377  tag.AddAttribute("Atom2",mAtomPair.second->GetName());
378  {
379  stringstream ss;
380  ss.precision(os.precision());
381  ss <<mLength0;
382  tag.AddAttribute("Length",ss.str());
383  }
384  {
385  stringstream ss;
386  ss.precision(os.precision());
387  ss <<mDelta;
388  tag.AddAttribute("Delta",ss.str());
389  }
390  {
391  stringstream ss;
392  ss.precision(os.precision());
393  ss <<mSigma;
394  tag.AddAttribute("Sigma",ss.str());
395  }
396  {
397  stringstream ss;
398  ss.precision(os.precision());
399  ss <<mBondOrder;
400  tag.AddAttribute("BondOrder",ss.str());
401  }
402  {
403  stringstream ss;
404  ss.precision(os.precision());
405  ss <<mIsFreeTorsion;
406  tag.AddAttribute("FreeTorsion",ss.str());
407  }
408  os <<tag<<endl;
409  VFN_DEBUG_EXIT("MolBond::XMLOutput()",4)
410 }
411 
412 void MolBond::XMLInput(istream &is,const XMLCrystTag &tag)
413 {
414  VFN_DEBUG_ENTRY("MolBond::XMLInput():",7)
415  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
416  {
417  if("Atom1"==tag.GetAttributeName(i))
418  {
419  mAtomPair.first=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
420  }
421  if("Atom2"==tag.GetAttributeName(i))
422  {
423  mAtomPair.second=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
424  }
425  if("Length"==tag.GetAttributeName(i))
426  {
427  stringstream ss(tag.GetAttributeValue(i));
428  ss >>mLength0;
429  }
430  if("Delta"==tag.GetAttributeName(i))
431  {
432  stringstream ss(tag.GetAttributeValue(i));
433  ss >>mDelta;
434  }
435  if("Sigma"==tag.GetAttributeName(i))
436  {
437  stringstream ss(tag.GetAttributeValue(i));
438  ss >>mSigma;
439  }
440  if("BondOrder"==tag.GetAttributeName(i))
441  {
442  stringstream ss(tag.GetAttributeValue(i));
443  ss >>mBondOrder;
444  }
445  if("FreeTorsion"==tag.GetAttributeName(i))
446  {
447  stringstream ss(tag.GetAttributeValue(i));
448  ss >>mIsFreeTorsion;
449  }
450  }
451  VFN_DEBUG_EXIT("MolBond::XMLInput():",7)
452 }
453 
454 REAL MolBond::GetLogLikelihood()const{return this->GetLogLikelihood(false,true);}
455 
456 REAL MolBond::GetLogLikelihood(const bool calcDeriv, const bool recalc)const
457 {
458  if(!recalc) return mLLK;
459  VFN_DEBUG_ENTRY("MolBond::GetLogLikelihood():",2)
460  //TAU_PROFILE("MolBond::GetLogLikelihood()","REAL (bool,bool)",TAU_DEFAULT);
461  //const REAL length=this->GetLength();
462  const REAL x=this->GetAtom2().GetX()-this->GetAtom1().GetX();
463  const REAL y=this->GetAtom2().GetY()-this->GetAtom1().GetY();
464  const REAL z=this->GetAtom2().GetZ()-this->GetAtom1().GetZ();
465  const REAL length=sqrt(abs(x*x+y*y+z*z));
466 
467  if(calcDeriv)
468  {
469  const REAL tmp2=1/(length+1e-10);
470  mDerivAtom1.x=-x*tmp2;
471  mDerivAtom1.y=-y*tmp2;
472  mDerivAtom1.z=-z*tmp2;
473 
474  mDerivAtom2.x=-mDerivAtom1.x;
475  mDerivAtom2.y=-mDerivAtom1.y;
476  mDerivAtom2.z=-mDerivAtom1.z;
477  }
478 
479  if(mSigma<1e-6)
480  {
481  if(calcDeriv) mDerivLLKCoeff=0;
482  mLLK=0;
483  return 0;
484  }
485  mLLK=length-(mLength0+mDelta);
486  if(mLLK>0)
487  {
488  mLLK /= mSigma;
489  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
490  #ifdef RESTRAINT_X2_X4_X6
491  const float mLLK2=mLLK*mLLK;
492  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
493  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
494  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
495  mLLK=mLLK2*(1+mLLK2);
496  #else
497  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
498  mLLK *= mLLK;
499  #endif
500  VFN_DEBUG_EXIT("MolBond::GetLogLikelihood():",2)
501  return mLLK;
502  }
503  mLLK=length-(mLength0-mDelta);
504  if(mLLK<0)
505  {
506  mLLK /= mSigma;
507  #ifdef RESTRAINT_X2_X4_X6
508  const float mLLK2=mLLK*mLLK;
509  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
510  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
511  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
512  mLLK=mLLK2*(1+mLLK2);
513  #else
514  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
515  mLLK *= mLLK;
516  #endif
517  VFN_DEBUG_EXIT("MolBond::GetLogLikelihood():",2)
518  return mLLK;
519  }
520  if(calcDeriv) mDerivLLKCoeff=0;
521  mLLK=0;
522  VFN_DEBUG_EXIT("MolBond::GetLogLikelihood():",2)
523  return mLLK;
524 }
525 
526 REAL MolBond::GetDeriv(const map<const MolAtom*,XYZ> &m, const bool llk)const
527 {
528  //TAU_PROFILE("MolBond::GetDeriv()","REAL (mak,bool)",TAU_DEFAULT);
529  REAL d=0;
530  map<const MolAtom*,XYZ>::const_iterator pos;
531  pos=m.find(mAtomPair.first);
532  if(pos!=m.end())
533  d+= pos->second.x*mDerivAtom1.x
534  +pos->second.y*mDerivAtom1.y
535  +pos->second.z*mDerivAtom1.z;
536  pos=m.find(mAtomPair.second);
537  if(pos!=m.end())
538  d+= pos->second.x*mDerivAtom2.x
539  +pos->second.y*mDerivAtom2.y
540  +pos->second.z*mDerivAtom2.z;
541  if(llk) return mDerivLLKCoeff*d;
542  return d;
543 }
544 
545 void MolBond::CalcGradient(std::map<MolAtom*,XYZ> &m)const
546 {
547  this->GetLogLikelihood(true,true);
548  map<MolAtom*,XYZ>::iterator pos;
549  pos=m.find(mAtomPair.first);
550  if(pos!=m.end())
551  {
552  pos->second.x+=mDerivLLKCoeff*mDerivAtom1.x;
553  pos->second.y+=mDerivLLKCoeff*mDerivAtom1.y;
554  pos->second.z+=mDerivLLKCoeff*mDerivAtom1.z;
555  }
556  pos=m.find(mAtomPair.second);
557  if(pos!=m.end())
558  {
559  pos->second.x+=mDerivLLKCoeff*mDerivAtom2.x;
560  pos->second.y+=mDerivLLKCoeff*mDerivAtom2.y;
561  pos->second.z+=mDerivLLKCoeff*mDerivAtom2.z;
562  }
563  #if 0
564  // Display gradient - for tests
565  cout<<this->GetName()<<" :LLK"<<endl;
566  for(map<MolAtom*,XYZ>::const_iterator pos=m.begin();pos!=m.end();++pos)
567  {
568  char buf[100];
569  sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)",
570  pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z);
571  cout<<buf<<endl;
572  }
573  #endif
574 }
575 
576 const MolAtom& MolBond::GetAtom1()const{return *(mAtomPair.first);}
577 const MolAtom& MolBond::GetAtom2()const{return *(mAtomPair.second);}
578 MolAtom& MolBond::GetAtom1(){return *(mAtomPair.first);}
579 MolAtom& MolBond::GetAtom2(){return *(mAtomPair.second);}
580 void MolBond::SetAtom1(MolAtom &at){mAtomPair.first =&at;}
581 void MolBond::SetAtom2(MolAtom &at){mAtomPair.second=&at;}
582 REAL MolBond::GetLength()const
583 {
584  return GetBondLength(GetAtom1(),this->GetAtom2());
585 }
586 
587 REAL MolBond::GetLength0()const{return mLength0;}
588 REAL MolBond::GetLengthDelta()const{return mDelta;}
589 REAL MolBond::GetLengthSigma()const{return mSigma;}
590 REAL MolBond::GetBondOrder()const{return mBondOrder;}
591 
592 REAL& MolBond::Length0(){return mLength0;}
593 REAL& MolBond::LengthDelta(){return mDelta;}
594 REAL& MolBond::LengthSigma(){return mSigma;}
595 REAL& MolBond::BondOrder(){return mBondOrder;}
596 
597 void MolBond::SetLength0(const REAL a){mLength0=a;}
598 void MolBond::SetLengthDelta(const REAL a){mDelta=a;}
599 void MolBond::SetLengthSigma(const REAL a){mSigma=a;}
600 void MolBond::SetBondOrder(const REAL a){mBondOrder=a;}
601 
602 bool MolBond::IsFreeTorsion()const{return mIsFreeTorsion;}
603 void MolBond::SetFreeTorsion(const bool isFreeTorsion)
604 {
605  if(mIsFreeTorsion==isFreeTorsion) return;
606  mIsFreeTorsion=isFreeTorsion;
608 }
609 #ifdef __WX__CRYST__
610 WXCrystObjBasic* MolBond::WXCreate(wxWindow* parent)
611 {
612  VFN_DEBUG_ENTRY("MolBond::WXCreate()",5)
613  mpWXCrystObj=new WXMolBond(parent,this);
614  VFN_DEBUG_EXIT("MolBond::WXCreate()",5)
615  return mpWXCrystObj;
616 }
617 WXCrystObjBasic* MolBond::WXGet(){return mpWXCrystObj;}
618 void MolBond::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;}
619 void MolBond::WXNotifyDelete(){mpWXCrystObj=0;}
620 #endif
621 //######################################################################
622 //
623 // MolBondAngle
624 //
625 //######################################################################
627  const REAL angle, const REAL sigma, const REAL delta,
628  Molecule &parent):
629 mAngle0(angle),mDelta(delta),mSigma(sigma),mpMol(&parent)
630 #ifdef __WX__CRYST__
631 ,mpWXCrystObj(0)
632 #endif
633 {
634  mvpAtom.push_back(&atom1);
635  mvpAtom.push_back(&atom2);
636  mvpAtom.push_back(&atom3);
637 }
638 
640 {
641 #ifdef __WX__CRYST__
642 this->WXDelete();
643 #endif
644 }
645 
646 const Molecule& MolBondAngle::GetMolecule()const{return *mpMol;}
647  Molecule& MolBondAngle::GetMolecule() {return *mpMol;}
648 
649 string MolBondAngle::GetName()const
650 {
651  return this->GetAtom1().GetName()+"-"
652  +this->GetAtom2().GetName()+"-"
653  +this->GetAtom3().GetName();
654 }
655 
656 void MolBondAngle::XMLOutput(ostream &os,int indent)const
657 {
658  VFN_DEBUG_ENTRY("MolBondAngle::XMLOutput()",4)
659  for(int i=0;i<indent;i++) os << " " ;
660  XMLCrystTag tag("BondAngle",false,true);
661  tag.AddAttribute("Atom1",this->GetAtom1().GetName());
662  tag.AddAttribute("Atom2",this->GetAtom2().GetName());
663  tag.AddAttribute("Atom3",this->GetAtom3().GetName());
664  {
665  stringstream ss;
666  ss.precision(os.precision());
667  ss <<mAngle0*RAD2DEG;
668  tag.AddAttribute("Angle",ss.str());
669  }
670  {
671  stringstream ss;
672  ss.precision(os.precision());
673  ss <<mDelta*RAD2DEG;
674  tag.AddAttribute("Delta",ss.str());
675  }
676  {
677  stringstream ss;
678  ss.precision(os.precision());
679  ss <<mSigma*RAD2DEG;
680  tag.AddAttribute("Sigma",ss.str());
681  }
682  os <<tag<<endl;
683  VFN_DEBUG_EXIT("MolBondAngle::XMLOutput()",4)
684 }
685 
686 void MolBondAngle::XMLInput(istream &is,const XMLCrystTag &tag)
687 {
688  VFN_DEBUG_ENTRY("MolBondAngle::XMLInput():",4)
689  mvpAtom.resize(3);
690  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
691  {
692  if("Atom1"==tag.GetAttributeName(i))
693  {
694  mvpAtom[0]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
695  }
696  if("Atom2"==tag.GetAttributeName(i))
697  {
698  mvpAtom[1]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
699  }
700  if("Atom3"==tag.GetAttributeName(i))
701  {
702  mvpAtom[2]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
703  }
704  if("Angle"==tag.GetAttributeName(i))
705  {
706  stringstream ss(tag.GetAttributeValue(i));
707  ss >>mAngle0;
708  mAngle0*=DEG2RAD;
709  }
710  if("Delta"==tag.GetAttributeName(i))
711  {
712  stringstream ss(tag.GetAttributeValue(i));
713  ss >>mDelta;
714  mDelta*=DEG2RAD;
715  }
716  if("Sigma"==tag.GetAttributeName(i))
717  {
718  stringstream ss(tag.GetAttributeValue(i));
719  ss >>mSigma;
720  mSigma*=DEG2RAD;
721  }
722  }
723  VFN_DEBUG_EXIT("MolBondAngle::XMLInput():",4)
724 }
725 REAL& MolBondAngle::Angle0()
726 {
727  return mAngle0;
728 }
729 REAL& MolBondAngle::AngleDelta(){return mDelta;}
730 REAL& MolBondAngle::AngleSigma(){return mSigma;}
731 
732 REAL MolBondAngle::GetAngle0()const{return mAngle0;}
733 REAL MolBondAngle::GetAngleDelta()const{return mDelta;}
734 REAL MolBondAngle::GetAngleSigma()const{return mSigma;}
735 
736 void MolBondAngle::SetAngle0(const REAL angle){mAngle0=angle;}
737 void MolBondAngle::SetAngleDelta(const REAL delta){mDelta=delta;}
738 void MolBondAngle::SetAngleSigma(const REAL sigma){mSigma=sigma;}
739 
740 REAL MolBondAngle::GetAngle()const
741 {
742  return GetBondAngle(this->GetAtom1(),this->GetAtom2(),this->GetAtom3());
743 }
744 
745 REAL MolBondAngle::GetLogLikelihood()const{return this->GetLogLikelihood(false,true);}
746 
747 REAL MolBondAngle::GetLogLikelihood(const bool calcDeriv, const bool recalc)const
748 {
749  if(!recalc) return mLLK;
750  VFN_DEBUG_ENTRY("MolBondAngle::GetLogLikelihood():",2)
751  //TAU_PROFILE("MolBondAngle::GetLogLikelihood()","REAL (bool,bool)",TAU_DEFAULT);
752  //const REAL angle=this->GetAngle();
753  const REAL x21=this->GetAtom1().GetX()-this->GetAtom2().GetX();
754  const REAL y21=this->GetAtom1().GetY()-this->GetAtom2().GetY();
755  const REAL z21=this->GetAtom1().GetZ()-this->GetAtom2().GetZ();
756  const REAL x23=this->GetAtom3().GetX()-this->GetAtom2().GetX();
757  const REAL y23=this->GetAtom3().GetY()-this->GetAtom2().GetY();
758  const REAL z23=this->GetAtom3().GetZ()-this->GetAtom2().GetZ();
759 
760  const REAL n1=sqrt(abs(x21*x21+y21*y21+z21*z21));
761  const REAL n3=sqrt(abs(x23*x23+y23*y23+z23*z23));
762  const REAL p=x21*x23+y21*y23+z21*z23;
763 
764  const REAL a0=p/(n1*n3+1e-10);
765  REAL angle;
766  if(a0>=1) angle=0;
767  else
768  {
769  if(a0<=-1) angle=M_PI;
770  else angle=acos(a0);
771  }
772 
773  if(calcDeriv)
774  {
775  const REAL s=1/(sqrt(1-a0*a0+1e-6));
776  const REAL s0=-s/(n1*n3+1e-10);
777  const REAL s1= s*p/(n3*n1*n1*n1+1e-10);
778  const REAL s3= s*p/(n1*n3*n3*n3+1e-10);
779  mDerivAtom1.x=s0*x23+s1*x21;
780  mDerivAtom1.y=s0*y23+s1*y21;
781  mDerivAtom1.z=s0*z23+s1*z21;
782 
783  mDerivAtom3.x=s0*x21+s3*x23;
784  mDerivAtom3.y=s0*y21+s3*y23;
785  mDerivAtom3.z=s0*z21+s3*z23;
786 
787  mDerivAtom2.x=-(mDerivAtom1.x+mDerivAtom3.x);
788  mDerivAtom2.y=-(mDerivAtom1.y+mDerivAtom3.y);
789  mDerivAtom2.z=-(mDerivAtom1.z+mDerivAtom3.z);
790  }
791 
792  if(mSigma<1e-6)
793  {
794  if(calcDeriv) mDerivLLKCoeff=0;
795  mLLK=0;
796  return 0;
797  }
798 
799  mLLK=angle-(mAngle0+mDelta);
800  if(mLLK>0)
801  {
802  mLLK/=mSigma;
803  #ifdef RESTRAINT_X2_X4_X6
804  const float mLLK2=mLLK*mLLK;
805  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
806  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
807  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
808  mLLK=mLLK2*(1+mLLK2);
809  #else
810  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
811  mLLK *= mLLK;
812  #endif
813  VFN_DEBUG_EXIT("MolBondAngle::GetLogLikelihood():",2)
814  return mLLK;
815  }
816  mLLK=angle-(mAngle0-mDelta);
817  if(mLLK<0)
818  {
819  mLLK/=mSigma;
820  #ifdef RESTRAINT_X2_X4_X6
821  const float mLLK2=mLLK*mLLK;
822  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
823  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
824  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
825  mLLK=mLLK2*(1+mLLK2);
826  #else
827  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
828  mLLK *= mLLK;
829  #endif
830  VFN_DEBUG_EXIT("MolBondAngle::GetLogLikelihood():",2)
831  return mLLK;
832  }
833  VFN_DEBUG_EXIT("MolBondAngle::GetLogLikelihood():",2)
834  if(calcDeriv) mDerivLLKCoeff=0;
835  mLLK=0;
836  return mLLK;
837 }
838 
839 REAL MolBondAngle::GetDeriv(const std::map<const MolAtom*,XYZ> &m,const bool llk)const
840 {
841  //TAU_PROFILE("MolBondAngle::GetDeriv()","REAL (mak,bool)",TAU_DEFAULT);
842  REAL d=0;
843  map<const MolAtom*,XYZ>::const_iterator pos;
844  pos=m.find(mvpAtom[0]);
845  if(pos!=m.end())
846  d+= pos->second.x*mDerivAtom1.x
847  +pos->second.y*mDerivAtom1.y
848  +pos->second.z*mDerivAtom1.z;
849  pos=m.find(mvpAtom[1]);
850  if(pos!=m.end())
851  d+= pos->second.x*mDerivAtom2.x
852  +pos->second.y*mDerivAtom2.y
853  +pos->second.z*mDerivAtom2.z;
854  pos=m.find(mvpAtom[2]);
855  if(pos!=m.end())
856  d+= pos->second.x*mDerivAtom3.x
857  +pos->second.y*mDerivAtom3.y
858  +pos->second.z*mDerivAtom3.z;
859  if(llk) return mDerivLLKCoeff*d;
860  return d;
861 }
862 
863 void MolBondAngle::CalcGradient(std::map<MolAtom*,XYZ> &m)const
864 {
865  this->GetLogLikelihood(true,true);
866  map<MolAtom*,XYZ>::iterator pos;
867  pos=m.find(mvpAtom[0]);
868  if(pos!=m.end())
869  {
870  pos->second.x+=mDerivLLKCoeff*mDerivAtom1.x;
871  pos->second.y+=mDerivLLKCoeff*mDerivAtom1.y;
872  pos->second.z+=mDerivLLKCoeff*mDerivAtom1.z;
873  }
874  pos=m.find(mvpAtom[1]);
875  if(pos!=m.end())
876  {
877  pos->second.x+=mDerivLLKCoeff*mDerivAtom2.x;
878  pos->second.y+=mDerivLLKCoeff*mDerivAtom2.y;
879  pos->second.z+=mDerivLLKCoeff*mDerivAtom2.z;
880  }
881  pos=m.find(mvpAtom[2]);
882  if(pos!=m.end())
883  {
884  pos->second.x+=mDerivLLKCoeff*mDerivAtom3.x;
885  pos->second.y+=mDerivLLKCoeff*mDerivAtom3.y;
886  pos->second.z+=mDerivLLKCoeff*mDerivAtom3.z;
887  }
888  #if 0
889  // Display gradient - for tests
890  cout<<this->GetName()<<" :LLK"<<endl;
891  for(map<MolAtom*,XYZ>::const_iterator pos=m.begin();pos!=m.end();++pos)
892  {
893  char buf[100];
894  sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)",
895  pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z);
896  cout<<buf<<endl;
897  }
898  #endif
899 }
900 
901 const MolAtom& MolBondAngle::GetAtom1()const{return *(mvpAtom[0]);}
902 const MolAtom& MolBondAngle::GetAtom2()const{return *(mvpAtom[1]);}
903 const MolAtom& MolBondAngle::GetAtom3()const{return *(mvpAtom[2]);}
904 MolAtom& MolBondAngle::GetAtom1(){return *(mvpAtom[0]);}
905 MolAtom& MolBondAngle::GetAtom2(){return *(mvpAtom[1]);}
906 MolAtom& MolBondAngle::GetAtom3(){return *(mvpAtom[2]);}
907 void MolBondAngle::SetAtom1(MolAtom& at){mvpAtom[0]=&at;}
908 void MolBondAngle::SetAtom2(MolAtom& at){mvpAtom[1]=&at;}
909 void MolBondAngle::SetAtom3(MolAtom& at){mvpAtom[2]=&at;}
910 //MolAtom& MolBondAngle::GetAtom1(){return *(mvpAtom[0]);}
911 //MolAtom& MolBondAngle::GetAtom2(){return *(mvpAtom[1]);}
912 //MolAtom& MolBondAngle::GetAtom3(){return *(mvpAtom[2]);}
913 #ifdef __WX__CRYST__
914 WXCrystObjBasic* MolBondAngle::WXCreate(wxWindow* parent)
915 {
916  VFN_DEBUG_ENTRY("MolBondAngle::WXCreate()",5)
917  mpWXCrystObj=new WXMolBondAngle(parent,this);
918  VFN_DEBUG_EXIT("MolBondAngle::WXCreate()",5)
919  return mpWXCrystObj;
920 }
921 WXCrystObjBasic* MolBondAngle::WXGet(){return mpWXCrystObj;}
922 void MolBondAngle::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;}
923 void MolBondAngle::WXNotifyDelete(){mpWXCrystObj=0;}
924 #endif
925 //######################################################################
926 //
927 // MolDihedralAngle
928 //
929 //######################################################################
931  MolAtom &atom3, MolAtom &atom4,
932  const REAL angle, const REAL sigma, const REAL delta,
933  Molecule &parent):
934 mAngle0(angle),mDelta(delta),mSigma(sigma),mpMol(&parent)
935 #ifdef __WX__CRYST__
936 ,mpWXCrystObj(0)
937 #endif
938 {
939  VFN_DEBUG_ENTRY("MolDihedralAngle::MolDihedralAngle()",5)
940  mvpAtom.push_back(&atom1);
941  mvpAtom.push_back(&atom2);
942  mvpAtom.push_back(&atom3);
943  mvpAtom.push_back(&atom4);
944  // We want the angle in [-pi;pi]
945  mAngle0=fmod((REAL)mAngle0,(REAL)(2*M_PI));
946  if(mAngle0<(-M_PI)) mAngle0+=2*M_PI;
947  if(mAngle0>M_PI) mAngle0-=2*M_PI;
948  VFN_DEBUG_EXIT("MolDihedralAngle::MolDihedralAngle()",5)
949 }
950 
952 {
953 #ifdef __WX__CRYST__
954 this->WXDelete();
955 #endif
956 }
957 
958 const Molecule& MolDihedralAngle::GetMolecule()const{return *mpMol;}
959  Molecule& MolDihedralAngle::GetMolecule() {return *mpMol;}
960 
961 string MolDihedralAngle::GetName()const
962 {
963  return this->GetAtom1().GetName()+"-"
964  +this->GetAtom2().GetName()+"-"
965  +this->GetAtom3().GetName()+"-"
966  +this->GetAtom4().GetName();
967 }
968 
969 void MolDihedralAngle::XMLOutput(ostream &os,int indent)const
970 {
971  VFN_DEBUG_ENTRY("MolDihedralAngle::XMLOutput()",4)
972  for(int i=0;i<indent;i++) os << " " ;
973  XMLCrystTag tag("DihedralAngle",false,true);
974  tag.AddAttribute("Atom1",this->GetAtom1().GetName());
975  tag.AddAttribute("Atom2",this->GetAtom2().GetName());
976  tag.AddAttribute("Atom3",this->GetAtom3().GetName());
977  tag.AddAttribute("Atom4",this->GetAtom4().GetName());
978  {
979  stringstream ss;
980  ss.precision(os.precision());
981  ss <<mAngle0*RAD2DEG;
982  tag.AddAttribute("Angle",ss.str());
983  }
984  {
985  stringstream ss;
986  ss.precision(os.precision());
987  ss <<mDelta*RAD2DEG;
988  tag.AddAttribute("Delta",ss.str());
989  }
990  {
991  stringstream ss;
992  ss.precision(os.precision());
993  ss <<mSigma*RAD2DEG;
994  tag.AddAttribute("Sigma",ss.str());
995  }
996  os <<tag<<endl;
997  VFN_DEBUG_EXIT("MolDihedralAngle::XMLOutput()",4)
998 }
999 
1000 void MolDihedralAngle::XMLInput(istream &is,const XMLCrystTag &tag)
1001 {
1002  VFN_DEBUG_ENTRY("MolDihedralAngle::XMLInput():",5)
1003  mvpAtom.resize(4);
1004  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
1005  {
1006  if("Atom1"==tag.GetAttributeName(i))
1007  {
1008  mvpAtom[0]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
1009  }
1010  if("Atom2"==tag.GetAttributeName(i))
1011  {
1012  mvpAtom[1]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
1013  }
1014  if("Atom3"==tag.GetAttributeName(i))
1015  {
1016  mvpAtom[2]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
1017  }
1018  if("Atom4"==tag.GetAttributeName(i))
1019  {
1020  mvpAtom[3]=&(mpMol->GetAtom(tag.GetAttributeValue(i)));
1021  }
1022  if("Angle"==tag.GetAttributeName(i))
1023  {
1024  stringstream ss(tag.GetAttributeValue(i));
1025  ss >>mAngle0;
1026  mAngle0*=DEG2RAD;
1027  }
1028  if("Delta"==tag.GetAttributeName(i))
1029  {
1030  stringstream ss(tag.GetAttributeValue(i));
1031  ss >>mDelta;
1032  mDelta*=DEG2RAD;
1033  }
1034  if("Sigma"==tag.GetAttributeName(i))
1035  {
1036  stringstream ss(tag.GetAttributeValue(i));
1037  ss >>mSigma;
1038  mSigma*=DEG2RAD;
1039  }
1040  }
1041  VFN_DEBUG_EXIT("MolDihedralAngle::XMLInput():",5)
1042 }
1043 
1044 REAL MolDihedralAngle::GetAngle()const
1045 {
1046  //Get the angle [2pi] closest to the restraint
1047  const REAL angle=GetDihedralAngle(this->GetAtom1(),this->GetAtom2(),this->GetAtom3(),this->GetAtom4());
1048  if((angle-mAngle0)>M_PI) return angle-2*M_PI;
1049  else if((angle-mAngle0)<(-M_PI)) return angle+2*M_PI;
1050 
1051  return angle;
1052 }
1053 
1054 REAL& MolDihedralAngle::Angle0(){return mAngle0;}
1055 REAL& MolDihedralAngle::AngleDelta(){return mDelta;}
1056 REAL& MolDihedralAngle::AngleSigma(){return mSigma;}
1057 
1058 REAL MolDihedralAngle::GetAngle0()const{return mAngle0;}
1059 REAL MolDihedralAngle::GetAngleDelta()const{return mDelta;}
1060 REAL MolDihedralAngle::GetAngleSigma()const{return mSigma;}
1061 
1062 void MolDihedralAngle::SetAngle0(const REAL angle){mAngle0=angle;}
1063 void MolDihedralAngle::SetAngleDelta(const REAL delta){mDelta=delta;}
1064 void MolDihedralAngle::SetAngleSigma(const REAL sigma){mSigma=sigma;}
1065 
1066 REAL MolDihedralAngle::GetLogLikelihood()const{return this->GetLogLikelihood(false,true);}
1067 
1068 REAL MolDihedralAngle::GetLogLikelihood(const bool calcDeriv, const bool recalc)const
1069 {
1070  if(!recalc) return mLLK;
1071  VFN_DEBUG_ENTRY("MolDihedralAngle::GetLogLikelihood():",2)
1072  //TAU_PROFILE("MolDihedralAngle::GetLogLikelihood()","REAL (bool,bool)",TAU_DEFAULT);
1073  const REAL x21=this->GetAtom1().GetX()-this->GetAtom2().GetX();
1074  const REAL y21=this->GetAtom1().GetY()-this->GetAtom2().GetY();
1075  const REAL z21=this->GetAtom1().GetZ()-this->GetAtom2().GetZ();
1076 
1077  const REAL x34=this->GetAtom4().GetX()-this->GetAtom3().GetX();
1078  const REAL y34=this->GetAtom4().GetY()-this->GetAtom3().GetY();
1079  const REAL z34=this->GetAtom4().GetZ()-this->GetAtom3().GetZ();
1080 
1081  const REAL x23=this->GetAtom3().GetX()-this->GetAtom2().GetX();
1082  const REAL y23=this->GetAtom3().GetY()-this->GetAtom2().GetY();
1083  const REAL z23=this->GetAtom3().GetZ()-this->GetAtom2().GetZ();
1084 
1085  // v21 x v23
1086  const REAL x123= y21*z23-z21*y23;
1087  const REAL y123= z21*x23-x21*z23;
1088  const REAL z123= x21*y23-y21*x23;
1089 
1090  // v32 x v34 (= -v23 x v34)
1091  const REAL x234= -(y23*z34-z23*y34);
1092  const REAL y234= -(z23*x34-x23*z34);
1093  const REAL z234= -(x23*y34-y23*x34);
1094 
1095  const REAL n123= sqrt(x123*x123+y123*y123+z123*z123+1e-7);
1096  const REAL n234= sqrt(x234*x234+y234*y234+z234*z234+1e-6);
1097 
1098  const REAL p=x123*x234+y123*y234+z123*z234;
1099  const REAL a0=p/(n123*n234+1e-10);
1100  REAL angle;
1101  if(a0>= 1) angle=0;
1102  else
1103  {
1104  if(a0<=-1) angle=M_PI;
1105  else angle=acos(a0);
1106  }
1107  REAL sgn=1.0;
1108  if((x21*x34 + y21*y34 + z21*z34)<0) {angle=-angle;sgn=-1;}
1109 
1110 
1111  if(calcDeriv)
1112  {
1113  const REAL s=sgn/(sqrt(1-a0*a0+1e-6));
1114  const REAL s0=-s/(n123*n234+1e-10);
1115  const REAL s1= s*p/(n234*n123*n123*n123+1e-10);
1116  const REAL s3= s*p/(n123*n234*n234*n234+1e-10);
1117  mDerivAtom1.x=s0*(-z23*y234+y23*z234)+s1*(-z23*y123+y23*z123);
1118  mDerivAtom1.y=s0*(-x23*z234+z23*x234)+s1*(-x23*z123+z23*x123);
1119  mDerivAtom1.z=s0*(-y23*x234+x23*y234)+s1*(-y23*x123+x23*y123);
1120 
1121  mDerivAtom4.x=s0*(-z23*y123+y23*z123)+s3*(-z23*y234+y23*z234);
1122  mDerivAtom4.y=s0*(-x23*z123+z23*x123)+s3*(-x23*z234+z23*x234);
1123  mDerivAtom4.z=s0*(-y23*x123+x23*y123)+s3*(-y23*x234+x23*y234);
1124 
1125  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);
1126  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);
1127  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);
1128 
1129  mDerivAtom3.x=-(mDerivAtom1.x+mDerivAtom2.x+mDerivAtom4.x);
1130  mDerivAtom3.y=-(mDerivAtom1.y+mDerivAtom2.y+mDerivAtom4.y);
1131  mDerivAtom3.z=-(mDerivAtom1.z+mDerivAtom2.z+mDerivAtom4.z);
1132  }
1133 
1134  if(mSigma<1e-6)
1135  {
1136  if(calcDeriv) mDerivLLKCoeff=0;
1137  mLLK=0;
1138  return mLLK;
1139  }
1140  mLLK=angle-(mAngle0+mDelta);
1141  if(mLLK<(-M_PI)) mLLK += 2*M_PI;
1142  if(mLLK> M_PI ) mLLK -= 2*M_PI;
1143  if(mLLK>0)
1144  {
1145  mLLK/=mSigma;
1146  #ifdef RESTRAINT_X2_X4_X6
1147  const float mLLK2=mLLK*mLLK;
1148  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
1149  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
1150  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
1151  mLLK=mLLK2*(1+mLLK2);
1152  #else
1153  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
1154  mLLK *= mLLK;
1155  #endif
1156  VFN_DEBUG_EXIT("MolDihedralAngle::GetLogLikelihood():",2)
1157  return mLLK;
1158  }
1159  mLLK=angle-(mAngle0-mDelta);
1160  if(mLLK<(-M_PI)) mLLK += 2*M_PI;
1161  if(mLLK> M_PI ) mLLK -= 2*M_PI;
1162  if(mLLK<0)
1163  {
1164  mLLK/=mSigma;
1165  #ifdef RESTRAINT_X2_X4_X6
1166  const float mLLK2=mLLK*mLLK;
1167  //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma;
1168  //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2);
1169  if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma;
1170  mLLK=mLLK2*(1+mLLK2);
1171  #else
1172  if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma;
1173  mLLK *= mLLK;
1174  #endif
1175  VFN_DEBUG_EXIT("MolDihedralAngle::GetLogLikelihood():",2)
1176  return mLLK;
1177  }
1178  VFN_DEBUG_EXIT("MolDihedralAngle::GetLogLikelihood():",2)
1179  if(calcDeriv) mDerivLLKCoeff=0;
1180  mLLK=0;
1181  return 0;
1182 }
1183 
1184 REAL MolDihedralAngle::GetDeriv(const std::map<const MolAtom*,XYZ> &m,const bool llk)const
1185 {
1186  //TAU_PROFILE("MolDihedralAngle::GetDeriv()","REAL (mak,bool)",TAU_DEFAULT);
1187  REAL d=0;
1188  map<const MolAtom*,XYZ>::const_iterator pos;
1189  pos=m.find(mvpAtom[0]);
1190  if(pos!=m.end())
1191  d+= pos->second.x*mDerivAtom1.x
1192  +pos->second.y*mDerivAtom1.y
1193  +pos->second.z*mDerivAtom1.z;
1194  pos=m.find(mvpAtom[1]);
1195  if(pos!=m.end())
1196  d+= pos->second.x*mDerivAtom2.x
1197  +pos->second.y*mDerivAtom2.y
1198  +pos->second.z*mDerivAtom2.z;
1199  pos=m.find(mvpAtom[2]);
1200  if(pos!=m.end())
1201  d+= pos->second.x*mDerivAtom3.x
1202  +pos->second.y*mDerivAtom3.y
1203  +pos->second.z*mDerivAtom3.z;
1204  pos=m.find(mvpAtom[3]);
1205  if(pos!=m.end())
1206  d+= pos->second.x*mDerivAtom4.x
1207  +pos->second.y*mDerivAtom4.y
1208  +pos->second.z*mDerivAtom4.z;
1209  if(llk) return mDerivLLKCoeff*d;
1210  return d;
1211 }
1212 
1213 void MolDihedralAngle::CalcGradient(std::map<MolAtom*,XYZ> &m)const
1214 {
1215  this->GetLogLikelihood(true,true);
1216  map<MolAtom*,XYZ>::iterator pos;
1217  pos=m.find(mvpAtom[0]);
1218  if(pos!=m.end())
1219  {
1220  pos->second.x+=mDerivLLKCoeff*mDerivAtom1.x;
1221  pos->second.y+=mDerivLLKCoeff*mDerivAtom1.y;
1222  pos->second.z+=mDerivLLKCoeff*mDerivAtom1.z;
1223  }
1224  pos=m.find(mvpAtom[1]);
1225  if(pos!=m.end())
1226  {
1227  pos->second.x+=mDerivLLKCoeff*mDerivAtom2.x;
1228  pos->second.y+=mDerivLLKCoeff*mDerivAtom2.y;
1229  pos->second.z+=mDerivLLKCoeff*mDerivAtom2.z;
1230  }
1231  pos=m.find(mvpAtom[2]);
1232  if(pos!=m.end())
1233  {
1234  pos->second.x+=mDerivLLKCoeff*mDerivAtom3.x;
1235  pos->second.y+=mDerivLLKCoeff*mDerivAtom3.y;
1236  pos->second.z+=mDerivLLKCoeff*mDerivAtom3.z;
1237  }
1238  pos=m.find(mvpAtom[3]);
1239  if(pos!=m.end())
1240  {
1241  pos->second.x+=mDerivLLKCoeff*mDerivAtom4.x;
1242  pos->second.y+=mDerivLLKCoeff*mDerivAtom4.y;
1243  pos->second.z+=mDerivLLKCoeff*mDerivAtom4.z;
1244  }
1245  #if 0
1246  // Display gradient - for tests
1247  cout<<this->GetName()<<" :LLK"<<endl;
1248  for(map<MolAtom*,XYZ>::const_iterator pos=m.begin();pos!=m.end();++pos)
1249  {
1250  char buf[100];
1251  sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)",
1252  pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z);
1253  cout<<buf<<endl;
1254  }
1255  #endif
1256 }
1257 
1258 const MolAtom& MolDihedralAngle::GetAtom1()const{return *(mvpAtom[0]);}
1259 const MolAtom& MolDihedralAngle::GetAtom2()const{return *(mvpAtom[1]);}
1260 const MolAtom& MolDihedralAngle::GetAtom3()const{return *(mvpAtom[2]);}
1261 const MolAtom& MolDihedralAngle::GetAtom4()const{return *(mvpAtom[3]);}
1262 void MolDihedralAngle::SetAtom1(MolAtom& at){mvpAtom[0]=&at;}
1263 void MolDihedralAngle::SetAtom2(MolAtom& at){mvpAtom[1]=&at;}
1264 void MolDihedralAngle::SetAtom3(MolAtom& at){mvpAtom[2]=&at;}
1265 void MolDihedralAngle::SetAtom4(MolAtom& at){mvpAtom[3]=&at;}
1266 MolAtom& MolDihedralAngle::GetAtom1(){return *(mvpAtom[0]);}
1267 MolAtom& MolDihedralAngle::GetAtom2(){return *(mvpAtom[1]);}
1268 MolAtom& MolDihedralAngle::GetAtom3(){return *(mvpAtom[2]);}
1269 MolAtom& MolDihedralAngle::GetAtom4(){return *(mvpAtom[3]);}
1270 #ifdef __WX__CRYST__
1271 WXCrystObjBasic* MolDihedralAngle::WXCreate(wxWindow* parent)
1272 {
1273  VFN_DEBUG_ENTRY("MolDihedralAngle::WXCreate()",5)
1274  mpWXCrystObj=new WXMolDihedralAngle(parent,this);
1275  VFN_DEBUG_EXIT("MolDihedralAngle::WXCreate()",5)
1276  return mpWXCrystObj;
1277 }
1278 WXCrystObjBasic* MolDihedralAngle::WXGet(){return mpWXCrystObj;}
1279 void MolDihedralAngle::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;}
1280 void MolDihedralAngle::WXNotifyDelete(){mpWXCrystObj=0;}
1281 #endif
1282 //######################################################################
1283 //
1284 // RigidGroup
1285 //
1286 //######################################################################
1287 string RigidGroup::GetName()const
1288 {
1289  set<MolAtom *>::const_iterator at=this->begin();
1290  string name=(*at++)->GetName();
1291  for(;at!=this->end();++at) name+=", "+(*at)->GetName();
1292  return name;
1293 }
1294 //######################################################################
1295 //
1296 // MolRing
1297 //
1298 //######################################################################
1299 MolRing::MolRing()
1300 {}
1301 
1302 const std::list<MolAtom*>& MolRing::GetAtomList()const
1303 {return mvpAtom;}
1304 
1305 std::list<MolAtom*>& MolRing::GetAtomList()
1306 {return mvpAtom;}
1307 //######################################################################
1308 //
1309 // Quaternion
1310 //
1311 //######################################################################
1313 mQ0(1),mQ1(0),mQ2(0),mQ3(0),mIsUniQuaternion(true)
1314 {
1315  VFN_DEBUG_MESSAGE("Quaternion::Quaternion()",5)
1316 }
1317 
1319  const REAL q1,
1320  const REAL q2,
1321  const REAL q3,
1322  bool unit):
1323 mQ0(q0),mQ1(q1),mQ2(q2),mQ3(q3),mIsUniQuaternion(unit)
1324 {
1325  VFN_DEBUG_MESSAGE("Quaternion::Quaternion()",5)
1326  if(unit) this->Normalize();
1327 }
1328 
1329 Quaternion::~Quaternion()
1330 {
1331  VFN_DEBUG_MESSAGE("Quaternion::~Quaternion()",5)
1332 }
1333 
1335  const REAL v1,
1336  const REAL v2,
1337  const REAL v3)
1338 {
1339  VFN_DEBUG_MESSAGE("Quaternion::RotationQuaternion()",4)
1340  const REAL s=sin(ang/2.)/sqrt(v1*v1+v2*v2+v3*v3+1e-7);
1341  return Quaternion(cos(ang/2.),s*v1,s*v2,s*v3,
1342  true);
1343 }
1344 
1346 {
1347  return Quaternion(mQ0,-mQ1,-mQ2,-mQ3);
1348 }
1350 {
1351  // http://www.cs.berkeley.edu/~laura/cs184/quat/quaternion.html
1352  return Quaternion
1353  (this->Q0()*q.Q0()-this->Q1()*q.Q1()-this->Q2()*q.Q2()-this->Q3()*q.Q3(),
1354  this->Q0()*q.Q1()+this->Q1()*q.Q0()+this->Q2()*q.Q3()-this->Q3()*q.Q2(),
1355  this->Q0()*q.Q2()-this->Q1()*q.Q3()+this->Q2()*q.Q0()+this->Q3()*q.Q1(),
1356  this->Q0()*q.Q3()+this->Q1()*q.Q2()-this->Q2()*q.Q1()+this->Q3()*q.Q0(),false);
1357 }
1358 
1359 void Quaternion::operator*=(const Quaternion &q)
1360 {
1361  //cout<<"Quaternion::operator*= before:";this->XMLOutput(cout);
1362  //cout<<"Quaternion::operator*= by :";q.XMLOutput(cout);
1363  const REAL q1=this->Q0()*q.Q1()+this->Q1()*q.Q0()+this->Q2()*q.Q3()-this->Q3()*q.Q2();
1364  const REAL q2=this->Q0()*q.Q2()+this->Q2()*q.Q0()-this->Q1()*q.Q3()+this->Q3()*q.Q1();
1365  const REAL q3=this->Q0()*q.Q3()+this->Q3()*q.Q0()+this->Q1()*q.Q2()-this->Q2()*q.Q1();
1366  this->Q0()= this->Q0()*q.Q0()-this->Q1()*q.Q1()-this->Q2()*q.Q2()-this->Q3()*q.Q3();
1367  this->Q1()=q1;
1368  this->Q2()=q2;
1369  this->Q3()=q3;
1370  this->Normalize();
1371  //cout<<"Quaternion::operator*= after :";this->XMLOutput(cout);
1372 }
1373 
1374 void Quaternion::XMLOutput(ostream &os,int indent)const
1375 {
1376  VFN_DEBUG_ENTRY("Quaternion::XMLOutput()",4)
1377  for(int i=0;i<indent;i++) os << " " ;
1378  XMLCrystTag tag("Quaternion",false,true);
1379  //#error "which atoms for this bond ?"
1380  {
1381  stringstream ss;
1382  ss.precision(os.precision());
1383  ss <<mQ0;
1384  tag.AddAttribute("Q0",ss.str());
1385  }
1386  {
1387  stringstream ss;
1388  ss.precision(os.precision());
1389  ss <<mQ1;
1390  tag.AddAttribute("Q1",ss.str());
1391  }
1392  {
1393  stringstream ss;
1394  ss.precision(os.precision());
1395  ss <<mQ2;
1396  tag.AddAttribute("Q2",ss.str());
1397  }
1398  {
1399  stringstream ss;
1400  ss.precision(os.precision());
1401  ss <<mQ3;
1402  tag.AddAttribute("Q3",ss.str());
1403  }
1404  {
1405  stringstream ss;
1406  ss.precision(os.precision());
1407  ss <<mIsUniQuaternion;
1408  tag.AddAttribute("IsUnitQuaternion",ss.str());
1409  }
1410  os <<tag<<endl;
1411  VFN_DEBUG_EXIT("Quaternion::XMLOutput()",4)
1412 }
1413 
1414 void Quaternion::XMLInput(istream &is,const XMLCrystTag &tag)
1415 {
1416  VFN_DEBUG_ENTRY("Quaternion::XMLInput()",5)
1417  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
1418  {
1419  if("Q0"==tag.GetAttributeName(i))
1420  {
1421  stringstream ss(tag.GetAttributeValue(i));
1422  ss >>mQ0;
1423  }
1424  if("Q1"==tag.GetAttributeName(i))
1425  {
1426  stringstream ss(tag.GetAttributeValue(i));
1427  ss >>mQ1;
1428  }
1429  if("Q2"==tag.GetAttributeName(i))
1430  {
1431  stringstream ss(tag.GetAttributeValue(i));
1432  ss >>mQ2;
1433  }
1434  if("Q3"==tag.GetAttributeName(i))
1435  {
1436  stringstream ss(tag.GetAttributeValue(i));
1437  ss >>mQ3;
1438  }
1439  if("IsUnitQuaternion"==tag.GetAttributeName(i))
1440  {
1441  stringstream ss(tag.GetAttributeValue(i));
1442  ss >>mIsUniQuaternion;
1443  }
1444  }
1445  if(mIsUniQuaternion) this->Normalize();
1446  VFN_DEBUG_EXIT("Quaternion::XMLInput()",5)
1447 }
1448 
1449 void Quaternion::RotateVector(REAL &v1,REAL &v2, REAL &v3)const
1450 {
1451  #if 0
1452  //#error P should not be a _UNIT_ quaternion...
1453  Quaternion P(0,v1,v2,v3,false);
1454  //cout<<"RotQuat:(n="<<this->GetNorm()<<")";this->XMLOutput(cout);
1455  //cout<<"before :(n="<<P.GetNorm()<<")";P.XMLOutput(cout);
1456  P= (*this)* P * this->GetConjugate();
1457  //cout<<"rotated:(n="<<P.GetNorm()<<")";P.XMLOutput(cout);
1458  v1=P.Q1();
1459  v2=P.Q2();
1460  v3=P.Q3();
1461  #endif
1462  const REAL p0=-mQ1*v1 - mQ2*v2 - mQ3*v3;
1463  const REAL p1= mQ0*v1 + mQ2*v3 - mQ3*v2;
1464  const REAL p2= mQ0*v2 - mQ1*v3 + mQ3*v1;
1465  const REAL p3= mQ0*v3 + mQ1*v2 - mQ2*v1;
1466 
1467  v1 =-p0*mQ1 + p1*mQ0 - p2*mQ3 + p3*mQ2;
1468  v2 =-p0*mQ2 + p2*mQ0 + p1*mQ3 - p3*mQ1;
1469  v3 =-p0*mQ3 + p3*mQ0 - p1*mQ2 + p2*mQ1;
1470 }
1471 
1473 {
1474  const REAL norm=sqrt( this->Q0()*this->Q0()
1475  +this->Q1()*this->Q1()
1476  +this->Q2()*this->Q2()
1477  +this->Q3()*this->Q3());
1478  mQ0 /= norm;
1479  mQ1 /= norm;
1480  mQ2 /= norm;
1481  mQ3 /= norm;
1482 }
1483 REAL Quaternion::GetNorm()const
1484 {return sqrt( this->Q0()*this->Q0()
1485  +this->Q1()*this->Q1()
1486  +this->Q2()*this->Q2()
1487  +this->Q3()*this->Q3());}
1488 
1489 const REAL& Quaternion::Q0()const{return mQ0;}
1490 const REAL& Quaternion::Q1()const{return mQ1;}
1491 const REAL& Quaternion::Q2()const{return mQ2;}
1492 const REAL& Quaternion::Q3()const{return mQ3;}
1493 REAL& Quaternion::Q0(){return mQ0;}
1494 REAL& Quaternion::Q1(){return mQ1;}
1495 REAL& Quaternion::Q2(){return mQ2;}
1496 REAL& Quaternion::Q3(){return mQ3;}
1497 //######################################################################
1498 //
1499 // Molecule Stretch Modes
1500 //
1501 //######################################################################
1502 StretchMode::~StretchMode(){}
1503 
1505  const MolBond *pBond):
1506 mpAtom0(&at0),mpAtom1(&at1),mpBond(pBond)
1507 {
1508  mBaseAmplitude=0.1;
1509  mpMol = &(at1.GetMolecule());
1510 }
1511 
1512 StretchModeBondLength::~StretchModeBondLength(){}
1513 
1514 void StretchModeBondLength::CalcDeriv(const bool derivllk)const
1515 {
1516  //TAU_PROFILE("StretchModeBondLength::CalcDeriv()","void ()",TAU_DEFAULT);
1517  // Derivative of the atom positions
1518  //mDerivXYZ.clear();
1519  REAL dx=mpAtom1->GetX()-mpAtom0->GetX();
1520  REAL dy=mpAtom1->GetY()-mpAtom0->GetY();
1521  REAL dz=mpAtom1->GetZ()-mpAtom0->GetZ();
1522  const REAL n=sqrt(dx*dx+dy*dy+dz*dz+1e-7);
1523  if(n<1e-6) return;//:KLUDGE: ?
1524  dx/=n;
1525  dy/=n;
1526  dz/=n;
1527  for(set<MolAtom *>::const_iterator pos=mvTranslatedAtomList.begin();
1528  pos!=mvTranslatedAtomList.end();++pos)
1529  {
1530  XYZ *const p=&(mDerivXYZ[*pos]);
1531  p->x=dx;
1532  p->y=dy;
1533  p->z=dz;
1534  }
1535  // Derivative of the LLK
1536  if(derivllk)
1537  {
1538  mLLKDeriv=0;
1539  for(map<const MolBond*,REAL>::const_iterator pos=this->mvpBrokenBond.begin();
1540  pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1541  for(map<const MolBondAngle*,REAL>::const_iterator pos=this->mvpBrokenBondAngle.begin();
1542  pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1543  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=this->mvpBrokenDihedralAngle.begin();
1544  pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1545  }
1546 }
1547 
1548 void StretchModeBondLength::Print(ostream &os,bool full)const
1549 {
1550  cout<<mpAtom0->GetName()<<"-"<<mpAtom1->GetName();
1551  if(full)
1552  {
1553  cout<<", Translated Atoms:";
1554  for(set<MolAtom*>::const_iterator atom=mvTranslatedAtomList.begin();
1555  atom!=mvTranslatedAtomList.end();++atom)
1556  {
1557  cout<<(*atom)->GetName()<<",";
1558  }
1559  }
1560 }
1561 
1562 void StretchModeBondLength::Stretch(const REAL amplitude,
1563  const bool keepCenter)
1564 {
1565  REAL dx=mpAtom1->GetX()-mpAtom0->GetX();
1566  REAL dy=mpAtom1->GetY()-mpAtom0->GetY();
1567  REAL dz=mpAtom1->GetZ()-mpAtom0->GetZ();
1568  const REAL l=sqrt(dx*dx+dy*dy+dz*dz+1e-7);
1569  if(l<1e-6) return;// :KLUDGE:
1570  const REAL change=amplitude/l;
1571  dx*=change;
1572  dy*=change;
1573  dz*=change;
1574  mpMol->TranslateAtomGroup(mvTranslatedAtomList,dx,dy,dz,keepCenter);
1575 }
1576 
1577 void StretchModeBondLength::RandomStretch(const REAL amplitude,
1578  const bool keepCenter)
1579 {
1580  mpMol->BondLengthRandomChange(*this,amplitude,keepCenter);
1581 }
1582 
1584  const MolBondAngle *pBondAngle):
1585 mpAtom0(&at0),mpAtom1(&at1),mpAtom2(&at2),mpBondAngle(pBondAngle)
1586 {
1587  mBaseAmplitude=M_PI*0.02;
1588  mpMol = &(at1.GetMolecule());
1589 }
1590 
1591 StretchModeBondAngle::~StretchModeBondAngle(){}
1592 
1593 void StretchModeBondAngle::CalcDeriv(const bool derivllk)const
1594 {
1595  //TAU_PROFILE("StretchModeBondAngle::CalcDeriv()","void ()",TAU_DEFAULT);
1596  // Derivative of the atomic positions
1597  const REAL x1=mpAtom1->GetX(),
1598  y1=mpAtom1->GetY(),
1599  z1=mpAtom1->GetZ();
1600 
1601  const REAL dx10=mpAtom0->GetX()-x1,
1602  dy10=mpAtom0->GetY()-y1,
1603  dz10=mpAtom0->GetZ()-z1,
1604  dx12=mpAtom2->GetX()-x1,
1605  dy12=mpAtom2->GetY()-y1,
1606  dz12=mpAtom2->GetZ()-z1;
1607 
1608  REAL vx=dy10*dz12-dz10*dy12,
1609  vy=dz10*dx12-dx10*dz12,
1610  vz=dx10*dy12-dy10*dx12;
1611  //const REAL n=sqrt((dx10*dx10+dy10*dy10+dz10*dz10)*(dx12*dx12+dy12*dy12+dz12*dz12))+1e-10;
1612  const REAL n=sqrt(vx*vx+vy*vy+vz*vz+1e-10);
1613  vx/=n;
1614  vy/=n;
1615  vz/=n;
1616 
1617  if(n<1e-6)
1618  {
1619  mDerivXYZ.clear();
1620  return;//:KLUDGE: ?
1621  }
1622 
1623  for(set<MolAtom *>::const_iterator pos=mvRotatedAtomList.begin();
1624  pos!=mvRotatedAtomList.end();++pos)
1625  {
1626  XYZ *const p=&(mDerivXYZ[*pos]);
1627  const REAL x=(*pos)->GetX()-x1,
1628  y=(*pos)->GetY()-y1,
1629  z=(*pos)->GetZ()-z1;
1630  p->x=z*vy-y*vz;
1631  p->y=x*vz-z*vx;
1632  p->z=y*vx-x*vy;
1633  }
1634  // Derivative of the LLK
1635  if(derivllk)
1636  {
1637  mLLKDeriv=0;
1638  for(map<const MolBond*,REAL>::const_iterator pos=this->mvpBrokenBond.begin();
1639  pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1640  for(map<const MolBondAngle*,REAL>::const_iterator pos=this->mvpBrokenBondAngle.begin();
1641  pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1642  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=this->mvpBrokenDihedralAngle.begin();
1643  pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1644  }
1645 }
1646 
1647 void StretchModeBondAngle::Print(ostream &os,bool full)const
1648 {
1649  cout<<mpAtom0->GetName()<<"-"<<mpAtom1->GetName()<<"-"<<mpAtom2->GetName();
1650  if(full)
1651  {
1652  cout<<", Rotated Atoms:";
1653  for(set<MolAtom*>::const_iterator atom=mvRotatedAtomList.begin();
1654  atom!=mvRotatedAtomList.end();++atom)
1655  {
1656  cout<<(*atom)->GetName()<<",";
1657  }
1658  }
1659 }
1660 
1661 void StretchModeBondAngle::Stretch(const REAL amplitude,
1662  const bool keepCenter)
1663 {
1664  REAL dx10=mpAtom0->GetX()-mpAtom1->GetX();
1665  REAL dy10=mpAtom0->GetY()-mpAtom1->GetY();
1666  REAL dz10=mpAtom0->GetZ()-mpAtom1->GetZ();
1667  REAL dx12=mpAtom2->GetX()-mpAtom1->GetX();
1668  REAL dy12=mpAtom2->GetY()-mpAtom1->GetY();
1669  REAL dz12=mpAtom2->GetZ()-mpAtom1->GetZ();
1670 
1671  const REAL vx=dy10*dz12-dz10*dy12;
1672  const REAL vy=dz10*dx12-dx10*dz12;
1673  const REAL vz=dx10*dy12-dy10*dx12;
1674  mpMol->RotateAtomGroup(*mpAtom1,vx,vy,vz,mvRotatedAtomList,amplitude,keepCenter);
1675 }
1676 
1677 void StretchModeBondAngle::RandomStretch(const REAL amplitude,
1678  const bool keepCenter)
1679 {
1680  mpMol->BondAngleRandomChange(*this,amplitude,keepCenter);
1681 }
1682 
1684  const MolDihedralAngle *pAngle):
1685 mpAtom1(&at1),mpAtom2(&at2),mpDihedralAngle(pAngle)
1686 {
1687  mBaseAmplitude=M_PI*0.02;
1688  mpMol = &(at1.GetMolecule());
1689 }
1690 
1691 StretchModeTorsion::~StretchModeTorsion(){}
1692 
1693 void StretchModeTorsion::CalcDeriv(const bool derivllk)const
1694 {
1695  //TAU_PROFILE("StretchModeTorsion::CalcDeriv()","void ()",TAU_DEFAULT);
1696  // Derivative of the LLK
1697  //mDerivXYZ.clear();
1698  const REAL x1=mpAtom1->GetX(),
1699  y1=mpAtom1->GetY(),
1700  z1=mpAtom1->GetZ();
1701 
1702  REAL vx=mpAtom2->GetX()-x1,
1703  vy=mpAtom2->GetY()-y1,
1704  vz=mpAtom2->GetZ()-z1;
1705 
1706  const REAL n=sqrt(vx*vx+vy*vy+vz*vz+1e-10);
1707  vx/=n;
1708  vy/=n;
1709  vz/=n;
1710 
1711  for(set<MolAtom *>::const_iterator pos=mvRotatedAtomList.begin();
1712  pos!=mvRotatedAtomList.end();++pos)
1713  {
1714  XYZ *const p=&(mDerivXYZ[*pos]);
1715  const REAL x=(*pos)->GetX()-x1,
1716  y=(*pos)->GetY()-y1,
1717  z=(*pos)->GetZ()-z1;
1718  p->x=z*vy-y*vz;
1719  p->y=x*vz-z*vx;
1720  p->z=y*vx-x*vy;
1721  }
1722  // Derivative of the LLK
1723  if(derivllk)
1724  {
1725  mLLKDeriv=0;
1726  for(map<const MolBond*,REAL>::const_iterator pos=this->mvpBrokenBond.begin();
1727  pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1728  for(map<const MolBondAngle*,REAL>::const_iterator pos=this->mvpBrokenBondAngle.begin();
1729  pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1730  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=this->mvpBrokenDihedralAngle.begin();
1731  pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1732  }
1733 }
1734 
1735 void StretchModeTorsion::Print(ostream &os,bool full)const
1736 {
1737  cout<<mpAtom1->GetName()<<"-"<<mpAtom2->GetName();
1738  if(full)
1739  {
1740  cout<<", Rotated Atoms:";
1741  for(set<MolAtom*>::const_iterator atom=mvRotatedAtomList.begin();
1742  atom!=mvRotatedAtomList.end();++atom)
1743  {
1744  cout<<(*atom)->GetName()<<",";
1745  }
1746  }
1747 }
1748 
1749 void StretchModeTorsion::Stretch(const REAL amplitude, const bool keepCenter)
1750 {
1751  mpMol->RotateAtomGroup(*mpAtom1,*mpAtom2,mvRotatedAtomList,amplitude,keepCenter);
1752 }
1753 
1754 void StretchModeTorsion::RandomStretch(const REAL amplitude,
1755  const bool keepCenter)
1756 {
1757  mpMol->DihedralAngleRandomChange(*this,amplitude,keepCenter);
1758 }
1759 
1760 
1761 //######################################################################
1762 //
1763 // StretchModeTwist
1764 //
1765 //######################################################################
1767 mpAtom1(&at1),mpAtom2(&at2)
1768 {
1769  mBaseAmplitude=M_PI*0.02;
1770  mpMol = &(at1.GetMolecule());
1771 }
1772 
1773 StretchModeTwist::~StretchModeTwist(){}
1774 
1775 void StretchModeTwist::CalcDeriv(const bool derivllk)const
1776 {// Identical to StretchModeTorsion::CalcDeriv()
1777  // Derivative of the LLK
1778  //mDerivXYZ.clear();
1779  const REAL x1=mpAtom1->GetX(),
1780  y1=mpAtom1->GetY(),
1781  z1=mpAtom1->GetZ();
1782 
1783  REAL vx=mpAtom2->GetX()-x1,
1784  vy=mpAtom2->GetY()-y1,
1785  vz=mpAtom2->GetZ()-z1;
1786 
1787  const REAL n=sqrt(vx*vx+vy*vy+vz*vz+1e-10);
1788  vx/=n;
1789  vy/=n;
1790  vz/=n;
1791 
1792  for(set<MolAtom *>::const_iterator pos=mvRotatedAtomList.begin();
1793  pos!=mvRotatedAtomList.end();++pos)
1794  {
1795  XYZ *const p=&(mDerivXYZ[*pos]);
1796  const REAL x=(*pos)->GetX()-x1,
1797  y=(*pos)->GetY()-y1,
1798  z=(*pos)->GetZ()-z1;
1799  p->x=z*vy-y*vz;
1800  p->y=x*vz-z*vx;
1801  p->z=y*vx-x*vy;
1802  }
1803  // Derivative of the LLK
1804  if(derivllk)
1805  {
1806  mLLKDeriv=0;
1807  for(map<const MolBond*,REAL>::const_iterator pos=this->mvpBrokenBond.begin();
1808  pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1809  for(map<const MolBondAngle*,REAL>::const_iterator pos=this->mvpBrokenBondAngle.begin();
1810  pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1811  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=this->mvpBrokenDihedralAngle.begin();
1812  pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true);
1813  }
1814 }
1815 
1816 void StretchModeTwist::Print(ostream &os,bool full)const
1817 {
1818  os<<mpAtom1->GetName()<<"/"<<mpAtom2->GetName()<<"-"<<mpAtom2->GetName();
1819  if(full)
1820  {
1821  os<<", Rotated Atoms:";
1822  for(set<MolAtom*>::const_iterator atom=mvRotatedAtomList.begin();
1823  atom!=mvRotatedAtomList.end();++atom)
1824  {
1825  os<<(*atom)->GetName()<<",";
1826  }
1827  }
1828 }
1829 
1830 void StretchModeTwist::Stretch(const REAL amplitude, const bool keepCenter)
1831 {
1832  mpMol->RotateAtomGroup(*mpAtom1,*mpAtom2,mvRotatedAtomList,amplitude,keepCenter);
1833 }
1834 
1835 void StretchModeTwist::RandomStretch(const REAL amplitude,
1836  const bool keepCenter)
1837 {
1838  const REAL dx=mpAtom2->GetX()-mpAtom1->GetX();
1839  const REAL dy=mpAtom2->GetY()-mpAtom1->GetY();
1840  const REAL dz=mpAtom2->GetZ()-mpAtom1->GetZ();
1841  if((abs(dx)+abs(dy)+abs(dz))<1e-6) return;// :KLUDGE:
1842  const REAL change=(REAL)(2.*rand()-RAND_MAX)/(REAL)RAND_MAX*mBaseAmplitude*amplitude;
1843  mpMol->RotateAtomGroup(*mpAtom1,*mpAtom2,mvRotatedAtomList,change,keepCenter);
1844 }
1845 
1846 //######################################################################
1847 //
1848 // MDAtomGroup
1849 //
1850 //######################################################################
1852 
1853 MDAtomGroup::MDAtomGroup(set<MolAtom*> &vat,
1854  set<MolBond*> &vb,
1855  set<MolBondAngle*> &va,
1856  set<MolDihedralAngle*> &vd):
1857 mvpAtom(vat)
1858 {
1859  // Use vector instead of sets for MolecularDynamicsEvolve & general
1860  // storage in molecule compatibility
1861  for(set<MolBond*>::iterator pos=vb.begin();pos!=vb.end();++pos)
1862  mvpBond.push_back(*pos);
1863  for(set<MolBondAngle*>::iterator pos=va.begin();pos!=va.end();++pos)
1864  mvpBondAngle.push_back(*pos);
1865  for(set<MolDihedralAngle*>::iterator pos=vd.begin();pos!=vd.end();++pos)
1866  mvpDihedralAngle.push_back(*pos);
1867 }
1868 
1869 void MDAtomGroup::Print(ostream &os,bool full)const
1870 {
1871  if(full) os<<"MDAtomGroup: ";
1872  for(set<MolAtom*>::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
1873  os<<(*pos)->GetName()<<" ";
1874  if(full)
1875  {
1876  os<<endl<<" Involving bond restraints:";
1877  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
1878  os<<(*pos)->GetName()<<" ";
1879  os<<endl<<" Involving bond angle restraints:";
1880  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
1881  os<<(*pos)->GetName()<<" ";
1882  os<<endl<<" Involving dihedral angle restraints:";
1883  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos)
1884  os<<(*pos)->GetName()<<" ";
1885  os<<endl;
1886  }
1887 }
1888 
1889 //######################################################################
1890 //
1891 // Molecule
1892 //
1893 //######################################################################
1894 Molecule::Molecule(Crystal &cryst, const string &name):
1895 mDeleteSubObjInDestructor(1), mBaseRotationAmplitude(M_PI*0.02), mIsSelfOptimizing(false),
1896 mpCenterAtom(0), mMDMoveFreq(0.0), mMDMoveEnergy(40.), mLogLikelihoodScale(1.0)
1897 {
1898  VFN_DEBUG_MESSAGE("Molecule::Molecule()",5)
1899  mpCryst=&cryst;
1900  {
1901  RefinablePar tmp(name+"_x",&mXYZ(0),0.,1.,
1902  gpRefParTypeScattTranslX,
1903  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
1905  tmp.SetDerivStep(1e-5);
1906  this->AddPar(tmp);
1907  }
1908  {
1909  RefinablePar tmp(name+"_y",&mXYZ(1),0,1,
1910  gpRefParTypeScattTranslY,
1911  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
1913  tmp.SetDerivStep(1e-5);
1914  this->AddPar(tmp);
1915  }
1916  {
1917  RefinablePar tmp(name+"_z",&mXYZ(2),0,1,
1918  gpRefParTypeScattTranslZ,
1919  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
1921  tmp.SetDerivStep(1e-5);
1922  this->AddPar(tmp);
1923  }
1924  {
1925  RefinablePar tmp(name+"_Occ",&mOccupancy,0,1,
1926  gpRefParTypeScattOccup,
1927  REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.,1.);
1929  tmp.SetDerivStep(1e-5);
1930  this->AddPar(tmp);
1931  }
1932  {
1933  RefinablePar tmp(name+"_Q0",&(mQuat.Q0()),0,1,
1934  gpRefParTypeScattOrient,
1935  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
1937  tmp.SetGlobalOptimStep(0.04);
1938  tmp.SetDerivStep(1e-4);
1939  this->AddPar(tmp);
1940  }
1941  {
1942  RefinablePar tmp(name+"_Q1",&(mQuat.Q1()),0,1,
1943  gpRefParTypeScattOrient,
1944  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
1946  tmp.SetGlobalOptimStep(0.04);
1947  tmp.SetDerivStep(1e-4);
1948  this->AddPar(tmp);
1949  }
1950  {
1951  RefinablePar tmp(name+"_Q2",&(mQuat.Q2()),0,1,
1952  gpRefParTypeScattOrient,
1953  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
1955  tmp.SetGlobalOptimStep(0.04);
1956  tmp.SetDerivStep(1e-4);
1957  this->AddPar(tmp);
1958  }
1959  {
1960  RefinablePar tmp(name+"_Q3",&(mQuat.Q3()),0,1,
1961  gpRefParTypeScattOrient,
1962  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
1964  tmp.SetGlobalOptimStep(0.04);
1965  tmp.SetDerivStep(1e-4);
1966  this->AddPar(tmp);
1967  }
1968  this->SetName(name);
1969  mLocalParamSet=this->CreateParamSet("saved parameters for local minimization");
1970  this->InitOptions();
1971  mClockScatterer.AddChild(mClockAtomList);
1972  mClockScatterer.AddChild(mClockBondList);
1973  mClockScatterer.AddChild(mClockBondAngleList);
1974  mClockScatterer.AddChild(mClockDihedralAngleList);
1975  mClockScatterer.AddChild(mClockRingList);
1976  mClockScatterer.AddChild(mClockRigidGroup);
1977  mClockScatterer.AddChild(mClockAtomPosition);
1978  mClockScatterer.AddChild(mClockAtomScattPow);
1979  mClockScatterer.AddChild(mClockOrientation);
1980 }
1981 
1983 mDeleteSubObjInDestructor(old.mDeleteSubObjInDestructor), mIsSelfOptimizing(false), mpCenterAtom(0)
1984 {
1985  VFN_DEBUG_ENTRY("Molecule::Molecule(old&)",5)
1986  // a hack, but const-correct
1987  mpCryst=&(gCrystalRegistry.GetObj(gCrystalRegistry.Find(old.GetCrystal())));
1988  {
1989  RefinablePar tmp(this->GetName()+"_x",&mXYZ(0),0.,1.,
1990  gpRefParTypeScattTranslX,
1991  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
1993  tmp.SetDerivStep(1e-5);
1994  this->AddPar(tmp);
1995  }
1996  {
1997  RefinablePar tmp(this->GetName()+"_y",&mXYZ(1),0,1,
1998  gpRefParTypeScattTranslY,
1999  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
2001  tmp.SetDerivStep(1e-5);
2002  this->AddPar(tmp);
2003  }
2004  {
2005  RefinablePar tmp(this->GetName()+"_z",&mXYZ(2),0,1,
2006  gpRefParTypeScattTranslZ,
2007  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.);
2009  tmp.SetDerivStep(1e-5);
2010  this->AddPar(tmp);
2011  }
2012  {
2013  RefinablePar tmp(this->GetName()+"_Occ",&mOccupancy,0,1,
2014  gpRefParTypeScattOccup,
2015  REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.,1.);
2017  tmp.SetDerivStep(1e-5);
2018  this->AddPar(tmp);
2019  }
2020  {
2021  RefinablePar tmp(this->GetName()+"Q0",&(mQuat.Q0()),0,1,
2022  gpRefParTypeScattOrient,
2023  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
2025  tmp.SetGlobalOptimStep(0.04);
2026  tmp.SetDerivStep(1e-4);
2027  this->AddPar(tmp);
2028  }
2029  {
2030  RefinablePar tmp(this->GetName()+"Q1",&(mQuat.Q1()),0,1,
2031  gpRefParTypeScattOrient,
2032  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
2034  tmp.SetGlobalOptimStep(0.04);
2035  tmp.SetDerivStep(1e-4);
2036  this->AddPar(tmp);
2037  }
2038  {
2039  RefinablePar tmp(this->GetName()+"Q2",&(mQuat.Q2()),0,1,
2040  gpRefParTypeScattOrient,
2041  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
2043  tmp.SetGlobalOptimStep(0.04);
2044  tmp.SetDerivStep(1e-4);
2045  this->AddPar(tmp);
2046  }
2047  {
2048  RefinablePar tmp(this->GetName()+"Q3",&(mQuat.Q3()),0,1,
2049  gpRefParTypeScattOrient,
2050  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
2052  tmp.SetGlobalOptimStep(0.04);
2053  tmp.SetDerivStep(1e-4);
2054  this->AddPar(tmp);
2055  }
2056  mLocalParamSet=this->CreateParamSet("saved parameters for local minimization");
2057  this->InitOptions();
2058  mClockScatterer.AddChild(mClockAtomList);
2059  mClockScatterer.AddChild(mClockBondList);
2060  mClockScatterer.AddChild(mClockBondAngleList);
2061  mClockScatterer.AddChild(mClockDihedralAngleList);
2062  mClockScatterer.AddChild(mClockRingList);
2063  mClockScatterer.AddChild(mClockRigidGroup);
2064  mClockScatterer.AddChild(mClockAtomPosition);
2065  mClockScatterer.AddChild(mClockAtomScattPow);
2066  mClockScatterer.AddChild(mClockOrientation);
2067 
2068  stringstream str;
2069  old.XMLOutput(str);
2070  XMLCrystTag tag(str);
2071  this->XMLInput(str,tag);
2072  VFN_DEBUG_EXIT("Molecule::Molecule(old&)",5)
2073 }
2074 
2076 {
2077  VFN_DEBUG_ENTRY("Molecule::~Molecule()",5)
2079  {
2080  {
2081  vector<MolAtom*>::iterator pos;
2082  for(pos=mvpAtom.begin();pos!=mvpAtom.end();pos++) delete *pos;
2083  }
2084  {
2085  vector<MolBond*>::iterator pos;
2086  for(pos=mvpBond.begin();pos!=mvpBond.end();pos++) delete *pos;
2087  }
2088  {
2089  vector<MolBondAngle*>::iterator pos;
2090  for(pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();pos++) delete *pos;
2091  }
2092  {
2093  vector<MolDihedralAngle*>::iterator pos;
2094  for(pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();pos++) delete *pos;
2095  }
2096  }
2097  VFN_DEBUG_EXIT("Molecule::~Molecule()",5)
2098 }
2099 
2101 {
2102  VFN_DEBUG_MESSAGE("Molecule::CreateCopy()",5)
2103  return new Molecule(*this);
2104 }
2105 
2106 const string& Molecule::GetClassName() const
2107 {
2108  static const string className="Molecule";
2109  return className;
2110 }
2111 
2112 void Molecule::SetName(const string &name)
2113 {
2114  if(mName==name) return;
2115  this->RefinableObj::SetName(name);
2116  // Set parameter's name including the Molecule's name
2117  try
2118  {
2119  this->GetPar(&mXYZ(0)).SetName(mName+"_x");
2120  this->GetPar(&mXYZ(1)).SetName(mName+"_y");
2121  this->GetPar(&mXYZ(2)).SetName(mName+"_z");
2122  this->GetPar(&mOccupancy).SetName(mName+"_Occ");
2123  this->GetPar(&(mQuat.Q0())).SetName(mName+"_Q0");
2124  this->GetPar(&(mQuat.Q1())).SetName(mName+"_Q1");
2125  this->GetPar(&(mQuat.Q2())).SetName(mName+"_Q2");
2126  this->GetPar(&(mQuat.Q3())).SetName(mName+"_Q3");
2127  }
2128  catch(const ObjCrystException &except)
2129  {
2130  cerr<<"Molecule::SetName(): parameters not yet declared in a Molecule ?"<<endl;
2131  }
2132 }
2133 
2134 std::string Molecule::GetFormula() const
2135 {
2136  if(this->GetNbComponent()==0) return "";
2137  std::map<std::string,float> velts;
2138  for(std::vector<MolAtom*>::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
2139  {
2140  if((*pos)->IsDummy()) continue;
2141  string p;
2142  if((*pos)->GetScatteringPower().GetClassName()=="ScatteringPowerAtom")
2143  p=dynamic_cast<const ScatteringPowerAtom*>(&((*pos)->GetScatteringPower()))->GetSymbol();
2144  else p=(*pos)->GetScatteringPower().GetName();
2145  if(velts.count(p)==0)
2146  velts[(*pos)->GetScatteringPower().GetName()]=(*pos)->GetOccupancy();
2147  else velts[(*pos)->GetScatteringPower().GetName()]+=(*pos)->GetOccupancy();
2148  }
2149  stringstream s;
2150  s<<std::setprecision(2);
2151  for(std::map<std::string,float>::const_iterator pos=velts.begin();pos!=velts.end();++pos)
2152  {
2153  if(pos!=velts.begin()) s<<" ";
2154  float nb=pos->second;
2155  if((abs(nb)-nb)<0.01) s<<pos->first<<int(round(nb));
2156  else s<<pos->first<<nb;
2157  }
2158  return s.str();
2159 }
2160 
2161 void Molecule::Print()const
2162 {
2163  VFN_DEBUG_MESSAGE("Molecule::Print()",5)
2164  this->XMLOutput(cout);
2165 }
2166 
2167 void Molecule::XMLOutput(ostream &os,int indent)const
2168 {
2169  VFN_DEBUG_ENTRY("Molecule::XMLOutput()",4)
2170 
2171  // :KLUDGE: this may be dangerous if the molecule is beaing refined !
2172  this->ResetRigidGroupsPar();
2173 
2174  for(int i=0;i<indent;i++) os << " " ;
2175  XMLCrystTag tag("Molecule");
2176  tag.AddAttribute("Name",mName);
2177  stringstream sst;
2178  sst<<mMDMoveFreq;
2179  tag.AddAttribute("MDMoveFreq",sst.str());
2180  sst.str("");
2181  sst<<mMDMoveEnergy;
2182  tag.AddAttribute("MDMoveEnergy",sst.str());
2183  sst.str("");
2184  sst<<mLogLikelihoodScale;
2185  tag.AddAttribute("LogLikelihoodScale",sst.str());
2186  os <<tag<<endl;
2187  indent++;
2188 
2189  mQuat.Normalize();
2190  mQuat.XMLOutput(os,indent);
2191 
2192  this->GetPar(mXYZ.data()+0).XMLOutput(os,"x",indent);
2193  os <<endl;
2194 
2195  this->GetPar(mXYZ.data()+1).XMLOutput(os,"y",indent);
2196  os <<endl;
2197 
2198  this->GetPar(mXYZ.data()+2).XMLOutput(os,"z",indent);
2199  os <<endl;
2200 
2201  this->GetPar(&mOccupancy).XMLOutput(os,"Occup",indent);
2202  os <<endl<<endl;
2203 
2204  for(unsigned int i=0;i<this->GetNbOption();i++)
2205  {
2206  this->GetOption(i).XMLOutput(os,indent);
2207  os <<endl;
2208  }
2209  os <<endl;
2210 
2211  {
2212  vector<MolAtom*>::const_iterator pos;
2213  for(pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
2214  (*pos)->XMLOutput(os,indent);
2215  }
2216  {
2217  vector<MolBond*>::const_iterator pos;
2218  for(pos=mvpBond.begin();pos!=mvpBond.end();++pos)
2219  (*pos)->XMLOutput(os,indent);
2220  }
2221  {
2222  vector<MolBondAngle*>::const_iterator pos;
2223  for(pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
2224  (*pos)->XMLOutput(os,indent);
2225  }
2226  {
2227  vector<MolDihedralAngle*>::const_iterator pos;
2228  for(pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos)
2229  (*pos)->XMLOutput(os,indent);
2230  }
2231  {
2232  vector<RigidGroup*>::const_iterator pos;
2233  for(pos=mvRigidGroup.begin();pos!=mvRigidGroup.end();++pos)
2234  {
2235  XMLCrystTag tagg("RigidGroup",false,true);
2236  for(set<MolAtom *>::const_iterator at=(*pos)->begin();at!=(*pos)->end();++at)
2237  tagg.AddAttribute("Atom",(*at)->GetName());
2238  /*
2239  tagg.AddAttribute("Q0",(*pos)->mQuat.Q0());
2240  tagg.AddAttribute("Q1",(*pos)->mQuat.Q1());
2241  tagg.AddAttribute("Q2",(*pos)->mQuat.Q2());
2242  tagg.AddAttribute("Q3",(*pos)->mQuat.Q3());
2243  tagg.AddAttribute("dX",(*pos)->mX);
2244  tagg.AddAttribute("dY",(*pos)->mY);
2245  tagg.AddAttribute("dZ",(*pos)->mZ);
2246  */
2247  for(int i=0;i<indent;i++) os << " " ;
2248  os <<tagg<<endl;
2249  }
2250  }
2251  if(this->GetCenterAtom()!=0)
2252  {
2253 
2254  XMLCrystTag tagg("CenterAtom",false,true);
2255  tagg.AddAttribute("Name",this->GetCenterAtom()->GetName());
2256  for(int i=0;i<indent;i++) os << " " ;
2257  os <<tagg<<endl;
2258  }
2259 
2260  indent--;
2261  tag.SetIsEndTag(true);
2262  for(int i=0;i<indent;i++) os << " " ;
2263  os <<tag<<endl;
2264  VFN_DEBUG_EXIT("Molecule::XMLOutput()",4)
2265 }
2266 
2267 void Molecule::XMLInput(istream &is,const XMLCrystTag &tag)
2268 {
2269  VFN_DEBUG_ENTRY("Molecule::XMLInput()",5)
2270  for(unsigned int i=0;i<tag.GetNbAttribute();i++)
2271  {
2272  if("Name"==tag.GetAttributeName(i))
2273  {
2274  mName=tag.GetAttributeValue(i);
2275  }
2276  if("MDMoveFreq"==tag.GetAttributeName(i))
2277  {
2278  mMDMoveFreq=string2floatC(tag.GetAttributeValue(i));
2279  }
2280  if("MDMoveEnergy"==tag.GetAttributeName(i))
2281  {
2282  mMDMoveEnergy=string2floatC(tag.GetAttributeValue(i));
2283  }
2284  if("LogLikelihoodScale"==tag.GetAttributeName(i))
2285  {
2286  mLogLikelihoodScale=string2floatC(tag.GetAttributeValue(i));
2287  }
2288  }
2289  while(true)
2290  {
2291  XMLCrystTag tagg(is);
2292  if(("Molecule"==tagg.GetName())&&tagg.IsEndTag())
2293  {
2294  //this->XMLOutput(cout);
2295  this->UpdateDisplay();
2296  VFN_DEBUG_EXIT("Molecule::XMLInput():"<<this->GetName(),5)
2297  return;
2298  }
2299  if("Quaternion"==tagg.GetName())
2300  {
2301  mQuat.XMLInput(is,tagg);
2302  }
2303  if("Atom"==tagg.GetName())
2304  {
2305  this->AddAtom(0.,0.,0.,(ScatteringPower *)0,"",false);
2306  mvpAtom.back()->XMLInput(is,tagg);
2307  }
2308  if("Bond"==tagg.GetName())
2309  {
2310  this->AddBond(this->GetAtom(0),this->GetAtom(1),1.5,.01,.05,1.,false);
2311  mvpBond.back()->XMLInput(is,tagg);
2312  }
2313  if("BondAngle"==tagg.GetName())
2314  {
2315  this->AddBondAngle(this->GetAtom(0),this->GetAtom(1),this->GetAtom(2),1.5,.01,.05,false);
2316  mvpBondAngle.back()->XMLInput(is,tagg);
2317  }
2318  if("DihedralAngle"==tagg.GetName())
2319  {
2320  this->AddDihedralAngle(this->GetAtom(0),this->GetAtom(1),
2321  this->GetAtom(2),this->GetAtom(3),1.5,.01,.05,false);
2322  mvpDihedralAngle.back()->XMLInput(is,tagg);
2323  }
2324  if("RigidGroup"==tagg.GetName())
2325  {
2326  RigidGroup s;
2327  for(unsigned int i=0;i<tagg.GetNbAttribute();i++)
2328  if("Atom"==tagg.GetAttributeName(i))
2329  s.insert(&(this->GetAtom(tagg.GetAttributeValue(i))));
2330  this->AddRigidGroup(s);
2331  }
2332  if("CenterAtom"==tagg.GetName())
2333  {
2334  RigidGroup s;
2335  for(unsigned int i=0;i<tagg.GetNbAttribute();i++)
2336  if("Name"==tagg.GetAttributeName(i))
2337  this->SetCenterAtom(this->GetAtom(tagg.GetAttributeValue(i)));
2338  }
2339  if("Option"==tagg.GetName())
2340  {
2341  for(unsigned int i=0;i<tagg.GetNbAttribute();i++)
2342  if("Name"==tagg.GetAttributeName(i))
2343  mOptionRegistry.GetObj(tagg.GetAttributeValue(i)).XMLInput(is,tagg);
2344  continue;
2345  }
2346  if("Par"==tagg.GetName())
2347  {
2348  for(unsigned int i=0;i<tagg.GetNbAttribute();i++)
2349  {
2350  if("Name"==tagg.GetAttributeName(i))
2351  {
2352  if("x"==tagg.GetAttributeValue(i))
2353  {
2354  this->GetPar(mXYZ.data()+0).XMLInput(is,tagg);
2355  break;
2356  }
2357  if("y"==tagg.GetAttributeValue(i))
2358  {
2359  this->GetPar(mXYZ.data()+1).XMLInput(is,tagg);
2360  break;
2361  }
2362  if("z"==tagg.GetAttributeValue(i))
2363  {
2364  this->GetPar(mXYZ.data()+2).XMLInput(is,tagg);
2365  break;
2366  }
2367  if("Occup"==tagg.GetAttributeValue(i))
2368  {
2369  this->GetPar(&mOccupancy).XMLInput(is,tagg);
2370  break;
2371  }
2372  }
2373  }
2374  }
2375  }
2376  VFN_DEBUG_EXIT("Molecule::XMLInput()",5)
2377 }
2378 
2380 {
2381  this->ResetRigidGroupsPar();
2383 }
2384 
2385 void Molecule::BeginOptimization(const bool allowApproximations,const bool enableRestraints)
2386 {
2387  if(this->IsBeingRefined())
2388  {
2389  // RefinableObj::BeginOptimization() will increase the optimization depth
2390  this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints);
2391  return;
2392  }
2393  TAU_PROFILE("Molecule::BeginOptimization()","void (bool,bool)",TAU_DEFAULT);
2394  #if 1 // Is doing this automatically too dangerous ?
2395  if( (!mIsSelfOptimizing)
2396  &&(mAutoOptimizeConformation.GetChoice()==0))
2397  {
2398  if(this->GetLogLikelihood()>(mvpRestraint.size()*500))
2399  {
2400  (*fpObjCrystInformUser)("Optimizing initial conformation of Molecule:"+this->GetName());
2401  this->OptimizeConformation(100000,(REAL)(mvpRestraint.size()));
2402  (*fpObjCrystInformUser)("");
2403  }
2404  mAutoOptimizeConformation.SetChoice(1);
2405  }
2406  #endif
2407 
2408  RefinableObjClock clockConf, clockMode;
2409  clockConf=mClockAtomList;
2410  if(clockConf<mClockBondList) clockConf=mClockBondList;
2411  if(clockConf<mClockBondAngleList) clockConf=mClockBondAngleList;
2412  if(clockConf<mClockDihedralAngleList) clockConf=mClockDihedralAngleList;
2413  if(clockConf<mClockRigidGroup) clockConf=mClockRigidGroup;
2414  if(clockConf<mClockAtomScattPow) clockConf=mClockAtomScattPow;
2415 
2416  clockMode=mClockConnectivityTable;
2417  if(clockMode<mClockRingList) clockMode=mClockRingList;
2418  if(clockMode<mClockRotorGroup) clockMode=mClockRotorGroup;
2419  if(clockMode<mClockFlipGroup) clockMode=mClockFlipGroup;
2420  if(clockMode<mClockStretchModeBondLength) clockMode=mClockStretchModeBondLength;
2421  if(clockMode<mClockStretchModeBondAngle) clockMode=mClockStretchModeBondAngle;
2422  if(clockMode<mClockStretchModeTorsion) clockMode=mClockStretchModeTorsion;
2423  if(clockMode<mClockStretchModeTwist) clockMode=mClockStretchModeTwist;
2424  if(clockMode<mClockMDAtomGroup) clockMode=mClockMDAtomGroup;
2425 
2426 
2427  if( (!mIsSelfOptimizing) && (clockMode<clockConf))
2428  {
2429  #if 0
2430  this->BuildRotorGroup();
2431  #endif
2432  if(mFlexModel.GetChoice()!=1)
2433  {
2434  this->BuildFlipGroup();
2435  this->BuildRingList();
2437  this->BuildStretchModeBondAngle();
2438  this->BuildStretchModeTorsion();
2439  //this->BuildStretchModeTwist();
2441  this->BuildStretchModeGroups();
2442  this->BuildMDAtomGroups();
2443  }
2444  }
2445  if(mOptimizeOrientation.GetChoice()==1)
2446  {
2447  this->GetPar(&(mQuat.Q0())).SetIsFixed(true);
2448  this->GetPar(&(mQuat.Q1())).SetIsFixed(true);
2449  this->GetPar(&(mQuat.Q2())).SetIsFixed(true);
2450  this->GetPar(&(mQuat.Q3())).SetIsFixed(true);
2451  }
2452  else
2453  {
2454  this->GetPar(&(mQuat.Q0())).SetIsFixed(false);
2455  this->GetPar(&(mQuat.Q1())).SetIsFixed(false);
2456  this->GetPar(&(mQuat.Q2())).SetIsFixed(false);
2457  this->GetPar(&(mQuat.Q3())).SetIsFixed(false);
2458  }
2459  if(1==mFlexModel.GetChoice())
2460  {// Molecule is a rigid body - fix all individual atomic parameters
2461  for(vector<MolAtom*>::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at)
2462  {
2463  this->GetPar(&((*at)->X())).SetIsFixed(true);
2464  this->GetPar(&((*at)->Y())).SetIsFixed(true);
2465  this->GetPar(&((*at)->Z())).SetIsFixed(true);
2466  }
2467  }
2468  else
2469  {// Molecule is flexible - rigid groups are handled below
2470  for(vector<MolAtom*>::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at)
2471  {
2472  this->GetPar(&((*at)->X())).SetIsFixed(false);
2473  this->GetPar(&((*at)->Y())).SetIsFixed(false);
2474  this->GetPar(&((*at)->Z())).SetIsFixed(false);
2475  }
2476  }
2477  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
2478  // Block individual refinable parameters from atoms in rigid groups
2479  // And create the index of the atoms
2480  for(vector<RigidGroup *>::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
2481  {
2482  // Init the translation & rotation parameters (ignored outside an optimization)
2483  (*pos)->mX=0;
2484  (*pos)->mY=0;
2485  (*pos)->mZ=0;
2486  (*pos)->mQuat.Q0()=1;
2487  (*pos)->mQuat.Q1()=0;
2488  (*pos)->mQuat.Q2()=0;
2489  (*pos)->mQuat.Q3()=0;
2490  (*pos)->mvIdx.clear();
2491  for(set<MolAtom *>::iterator at=(*pos)->begin();at!=(*pos)->end();++at)
2492  {
2493  this->GetPar(&((*at)->X())).SetIsFixed(true);
2494  this->GetPar(&((*at)->Y())).SetIsFixed(true);
2495  this->GetPar(&((*at)->Z())).SetIsFixed(true);
2496  for(int i = 0; i < this->GetNbComponent(); ++i)
2497  if(&(this->GetAtom(i))==*at)
2498  {
2499  (*pos)->mvIdx.insert(i);
2500  break;
2501  }
2502  }
2503  }
2504  #endif
2505 
2506  this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints);
2507  mRandomConformChangeNbTest=0;
2508  mRandomConformChangeNbAccept=0;
2509  mRandomConformChangeTemp=1.;//(REAL)this->GetNbComponent();
2510 }
2511 
2513 {
2514  /*
2515  if(mOptimizationDepth>1)
2516  {
2517  this->RefinableObj::EndOptimization();
2518  return;
2519  }
2520  */
2521  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
2522  // Un-block individual refinable parameters from atoms in rigid groups
2523  for(vector<RigidGroup *>::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
2524  {
2525  for(set<MolAtom *>::iterator at=(*pos)->begin();at!=(*pos)->end();++at)
2526  {
2527  this->GetPar(&((*at)->X())).SetIsFixed(false);
2528  this->GetPar(&((*at)->Y())).SetIsFixed(false);
2529  this->GetPar(&((*at)->Z())).SetIsFixed(false);
2530  }
2531  }
2532  // Apply the translations & rotations of the rigid group parameters, and
2533  // use this as the newly stored atomic coordinates.
2534  this->ResetRigidGroupsPar();
2535  #endif
2537 }
2538 
2540 {
2541  TAU_PROFILE("Molecule::RandomizeConfiguration()","void ()",TAU_DEFAULT);
2542  VFN_DEBUG_ENTRY("Molecule::RandomizeConfiguration()",4)
2543 
2544  if( (!mIsSelfOptimizing)
2545  &&(this->GetLogLikelihood()>(mvpRestraint.size()*500))
2546  &&(mAutoOptimizeConformation.GetChoice()==0))
2547  {// This is only done once, for a newly-created molecule with atoms not conforming to restraints
2548  (*fpObjCrystInformUser)("Optimizing initial conformation of Molecule:"+this->GetName());
2549  this->OptimizeConformation(100000,(REAL)(mvpRestraint.size()));
2550  (*fpObjCrystInformUser)("");
2551  }
2552 
2553  if( (!(this->IsBeingRefined()))
2554  && (mvStretchModeTorsion.size()==0)
2555  &&(mvStretchModeBondAngle.size()==0)
2556  &&(mvStretchModeBondLength.size()==0)
2557  &&(mvStretchModeTwist.size()==0)
2558  &&(mvMDAtomGroup.size()==0))
2559  {
2560  //This will build stretch modes & MD groups
2561  if(mFlexModel.GetChoice()!=1)
2562  {
2563  this->BuildStretchModeTorsion();
2565  //this->BuildStretchModeGroups();
2566  this->BuildMDAtomGroups();
2567  }
2568  }
2569 
2570  #if 0
2571  this->BuildRotorGroup();
2572  if((mFlexModel.GetChoice()==0)||(mFlexModel.GetChoice()==2))
2573  for(list<RotorGroup>::const_iterator pos=mvRotorGroupTorsion.begin();
2574  pos!=mvRotorGroupTorsion.end();++pos)
2575  {
2576  const REAL angle=(REAL)rand()*2.*M_PI/(REAL)RAND_MAX;
2577  this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),
2578  pos->mvRotatedAtomList,angle);
2579  }
2580  if(mFlexModel.GetChoice()==0)
2581  for(list<RotorGroup>::const_iterator pos=mvRotorGroupTorsionSingleChain.begin();
2582  pos!=mvRotorGroupTorsionSingleChain.end();++pos)
2583  {
2584  const REAL angle=(REAL)rand()*2.*M_PI/(REAL)RAND_MAX;
2585  this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),
2586  pos->mvRotatedAtomList,angle);
2587  }
2588  if(mFlexModel.GetChoice()==0)
2589  for(list<RotorGroup>::const_iterator pos=mvRotorGroupInternal.begin();
2590  pos!=mvRotorGroupInternal.end();++pos)
2591  {
2592  const REAL angle=(REAL)rand()*2.*M_PI/(REAL)RAND_MAX;
2593  this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),
2594  pos->mvRotatedAtomList,angle);
2595  }
2596  #else
2597  for(list<StretchModeTorsion>::const_iterator
2598  pos=mvStretchModeTorsion.begin();
2599  pos!=mvStretchModeTorsion.end();++pos)
2600  {
2601  const REAL amp=2*M_PI*rand()/(REAL)RAND_MAX;
2602  this->DihedralAngleRandomChange(*pos,amp,true);
2603  }
2604  // Molecular dynamics moves
2605  if((mvMDAtomGroup.size()>0)&&(mMDMoveFreq>0)&&(mMDMoveEnergy>0))
2606  {
2607  // Random initial speed for all atoms
2608  map<MolAtom*,XYZ> v0;
2609  for(vector<MolAtom*>::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at)
2610  v0[*at]=XYZ(rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5);
2611 
2612  const REAL nrj0=mMDMoveEnergy*( this->GetBondList().size()
2613  +this->GetBondAngleList().size()
2614  +this->GetDihedralAngleList().size());
2615  map<RigidGroup*,std::pair<XYZ,XYZ> > vr;
2616  this->MolecularDynamicsEvolve(v0, 5000,0.004,
2617  this->GetBondList(),
2618  this->GetBondAngleList(),
2619  this->GetDihedralAngleList(),
2620  vr,nrj0);
2621  }
2622 
2623  #endif
2624  // this will only change limited parameters i.e. translation
2626  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
2627  // Init rigid groups translation & rotation parameters to zero
2628  for(vector<RigidGroup *>::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
2629  {
2630  // Init the translation & rotation parameters (ignored outside an optimization
2631  (*pos)->mX=0;
2632  (*pos)->mY=0;
2633  (*pos)->mZ=0;
2634  (*pos)->mQuat.Q0()=1;
2635  (*pos)->mQuat.Q1()=0;
2636  (*pos)->mQuat.Q2()=0;
2637  (*pos)->mQuat.Q3()=0;
2638  }
2639  #endif
2640  if(mOptimizeOrientation.GetChoice()==0)
2641  {//Rotate around an arbitrary vector
2642  const REAL amp=M_PI/RAND_MAX;
2644  ((2.*(REAL)rand()-(REAL)RAND_MAX)*amp,
2645  (REAL)rand(),(REAL)rand(),(REAL)rand());
2646  mQuat.Normalize();
2647  mClockOrientation.Click();
2648  }
2649  VFN_DEBUG_EXIT("Molecule::RandomizeConfiguration()",4)
2650 }
2651 
2652 void Molecule::GlobalOptRandomMove(const REAL mutationAmplitude,
2653  const RefParType *type)
2654 {
2655  if(mRandomMoveIsDone) return;
2656  if(mIsSelfOptimizing)
2657  {
2658  this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,type);
2659  mQuat.Normalize();
2660  VFN_DEBUG_EXIT("Molecule::GlobalOptRandomMove()",4)
2661  return;
2662  }
2663  TAU_PROFILE("Molecule::GlobalOptRandomMove()","void (REAL,RefParType*)",TAU_DEFAULT);
2664  TAU_PROFILE_TIMER(timer1,"Molecule::GlobalOptRandomMove 1","", TAU_FIELD);
2665  TAU_PROFILE_TIMER(timer2,"Molecule::GlobalOptRandomMove 2","", TAU_FIELD);
2666  TAU_PROFILE_TIMER(timer3,"Molecule::GlobalOptRandomMove 3","", TAU_FIELD);
2667  TAU_PROFILE_TIMER(timer4,"Molecule::GlobalOptRandomMove 4","", TAU_FIELD);
2668  TAU_PROFILE_TIMER(timer5,"Molecule::GlobalOptRandomMove 5","", TAU_FIELD);
2669  VFN_DEBUG_ENTRY("Molecule::GlobalOptRandomMove()",4)
2671 
2672 
2673  #if 1
2674  // From time to time, just do one flip
2675  if( (mFlexModel.GetChoice()!=1)
2676  &&(mFlipModel.GetChoice()==0)
2677  &&(gpRefParTypeScattConform->IsDescendantFromOrSameAs(type))
2678  &&(mvFlipGroup.size()>0)
2679  &&(((rand()%100)==0)))
2680  {
2681 
2682  this->SaveParamSet(mLocalParamSet);
2683  const REAL llk0=this->GetLogLikelihood()/mLogLikelihoodScale;
2684  const unsigned long i=rand() % mvFlipGroup.size();
2685  list<FlipGroup>::iterator pos=mvFlipGroup.begin();
2686  for(unsigned long j=0;j<i;++j)++pos;
2687  this->FlipAtomGroup(*pos,true);
2688  #if 0
2689  static unsigned long ctflip1=0,ctflip2=0;
2690  if(pos->mvRotatedChainList.begin()->first==pos->mpAtom0)
2691  {
2692  cout <<"TRYING: Flip group from atom "
2693  <<pos->mpAtom0->GetName()<<",exchanging bonds with "
2694  <<pos->mpAtom1->GetName()<<" and "
2695  <<pos->mpAtom2->GetName()<<", resulting in a 180deg rotation of atoms : ";
2696  for(set<MolAtom*>::iterator pos1=pos->mvRotatedChainList.begin()->second.begin();
2697  pos1!=pos->mvRotatedChainList.begin()->second.end();++pos1)
2698  cout<<(*pos1)->GetName()<<" ";
2699  }
2700  else
2701  {
2702  cout <<"TRYING: Flip group with respect to: "
2703  <<pos->mpAtom1->GetName()<<"-"
2704  <<pos->mpAtom0->GetName()<<"-"
2705  <<pos->mpAtom2->GetName()<<" : ";
2706  for(list<pair<const MolAtom *,set<MolAtom*> > >::const_iterator
2707  chain=pos->mvRotatedChainList.begin();
2708  chain!=pos->mvRotatedChainList.end();++chain)
2709  {
2710  cout<<" -"<<chain->first->GetName()<<":";
2711  for(set<MolAtom*>::const_iterator pos1=chain->second.begin();
2712  pos1!=chain->second.end();++pos1)
2713  cout<<(*pos1)->GetName()<<" ";
2714  }
2715  }
2716  ctflip1++;
2717  if((this->GetLogLikelihood()/mLogLikelihoodScale-llk0)>.3*llk0)
2718  {
2719  cout<<" FLIP REJECTED ("<<int(float(ctflip2)/ctflip1*100)<<"% accepted): llk="<<llk0<<" -> "<<this->GetLogLikelihood()/mLogLikelihoodScale<<endl;
2720  this->RestoreParamSet(mLocalParamSet);
2721  }
2722  else
2723  {
2724  ctflip2++;
2725  cout<<" FLIP ACCEPTED ("<<float(ctflip2)/ctflip1*100<<"% accepted)"<<endl;
2726  }
2727  #else
2728  if((this->GetLogLikelihood()/mLogLikelihoodScale-llk0)>.3*llk0)
2729  this->RestoreParamSet(mLocalParamSet);
2730  #endif
2731  }
2732  else
2733  #endif
2734  {
2735  TAU_PROFILE_START(timer1);
2736  if(mOptimizeOrientation.GetChoice()==0)
2737  {//Rotate around an arbitrary vector
2738  static const REAL amp=mBaseRotationAmplitude/(REAL)RAND_MAX;
2739  REAL mult=1.0;
2740  if((1==mFlexModel.GetChoice())||(mvRotorGroupTorsion.size()<2)) mult=2.0;
2742  ((2.*(REAL)rand()-(REAL)RAND_MAX)*amp*mutationAmplitude*mult,
2743  (REAL)rand(),(REAL)rand(),(REAL)rand());
2744  mQuat.Normalize();
2745  mClockOrientation.Click();
2746  }
2747  // Occupancy
2748  if(gpRefParTypeScattOccup->IsDescendantFromOrSameAs(type))
2749  this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,gpRefParTypeScattOccup);
2750  mRandomMoveIsDone=false;
2751  //translation
2752  if(gpRefParTypeScattTransl->IsDescendantFromOrSameAs(type))
2753  this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,gpRefParTypeScattTransl);
2754  mRandomMoveIsDone=false;
2755  TAU_PROFILE_STOP(timer1);
2756  if(gpRefParTypeScattConform->IsDescendantFromOrSameAs(type))
2757  {
2758  if(mFlexModel.GetChoice()!=1)
2759  {
2760  #if 1 // Move as many atoms as possible
2761  if((mvMDFullAtomGroup.size()>3)&&(rand()<(RAND_MAX*mMDMoveFreq)))
2762  {
2763  #if 0
2764  // Use one center for the position of an impulsion, applied to all atoms with an exponential decrease
2765  // Determine extent of atom group
2766  REAL xmin=(*mvMDFullAtomGroup.begin())->GetX();
2767  REAL xmax=(*mvMDFullAtomGroup.begin())->GetX();
2768  REAL ymin=(*mvMDFullAtomGroup.begin())->GetY();
2769  REAL ymax=(*mvMDFullAtomGroup.begin())->GetY();
2770  REAL zmin=(*mvMDFullAtomGroup.begin())->GetZ();
2771  REAL zmax=(*mvMDFullAtomGroup.begin())->GetZ();
2772  for(set<MolAtom*>::iterator at=mvMDFullAtomGroup.begin();at!=mvMDFullAtomGroup.end();++at)
2773  {
2774  if((*at)->GetX()<xmin) xmin=(*at)->GetX();
2775  if((*at)->GetX()>xmax) xmax=(*at)->GetX();
2776  if((*at)->GetY()<ymin) ymin=(*at)->GetY();
2777  if((*at)->GetY()>ymax) ymax=(*at)->GetY();
2778  if((*at)->GetZ()<zmin) zmin=(*at)->GetZ();
2779  if((*at)->GetZ()>zmax) zmax=(*at)->GetZ();
2780  }
2781  // Apply a gaussian impulsion to part of the atom group (FWHM=1/3 of group size)
2782  REAL dx=(xmax-xmin)/5.,dy=(ymax-ymin)/5.,dz=(zmax-zmin)/5.;
2783  if(dx<2) dx=2;
2784  if(dy<2) dy=2;
2785  if(dz<2) dz=2;
2786  const REAL xc=xmin+rand()/(REAL)RAND_MAX*(xmax-xmin);
2787  const REAL yc=ymin+rand()/(REAL)RAND_MAX*(ymax-ymin);
2788  const REAL zc=zmin+rand()/(REAL)RAND_MAX*(zmax-zmin);
2789  map<MolAtom*,XYZ> v0;
2790  const REAL ax=-4.*log(2.)/(dx*dx);
2791  const REAL ay=-4.*log(2.)/(dy*dy);
2792  const REAL az=-4.*log(2.)/(dz*dz);
2793  for(set<MolAtom*>::iterator at=mvMDFullAtomGroup.begin();at!=mvMDFullAtomGroup.end();++at)
2794  v0[*at]=XYZ(exp(ax*((*at)->GetX()-xc)*((*at)->GetX()-xc)),
2795  exp(ay*((*at)->GetY()-yc)*((*at)->GetY()-yc)),
2796  exp(az*((*at)->GetZ()-zc)*((*at)->GetZ()-zc)));
2797  #else
2798  // Use one atom for the center of the impulsion, 'push' atoms depending on distance & connectivity table
2799  map<MolAtom*,XYZ> v0;
2800  for(set<MolAtom*>::iterator at=this->mvMDFullAtomGroup.begin();at!=this->mvMDFullAtomGroup.end();++at)
2801  v0[*at]=XYZ(0,0,0);
2802  std::map<MolAtom*,unsigned long> pushedAtoms;
2803  unsigned long idx=rand()%v0.size();
2804  set<MolAtom*>::iterator at0=this->mvMDFullAtomGroup.begin();
2805  for(unsigned int i=0;i<idx;i++) at0++;
2806  const REAL xc=(*at0)->GetX();
2807  const REAL yc=(*at0)->GetY();
2808  const REAL zc=(*at0)->GetZ();
2809  const map<MolAtom *,set<MolAtom *> > *pConnect=&(this-> GetConnectivityTable());
2810  ExpandAtomGroupRecursive(*at0,*pConnect,pushedAtoms,3);
2811  REAL ux,uy,uz,n=0;
2812  while(n<1)
2813  {
2814  ux=REAL(rand()-RAND_MAX/2);
2815  uy=REAL(rand()-RAND_MAX/2);
2816  uz=REAL(rand()-RAND_MAX/2);
2817  n=sqrt(ux*ux+uy*uy+uz*uz);
2818  }
2819  ux=ux/n;uy=uy/n;uz=uz/n;
2820  const REAL a=-4.*log(2.)/(2*2);//FWHM=2 Angstroems
2821  if(rand()%2==0)
2822  for(map<MolAtom*,unsigned long>::iterator at=pushedAtoms.begin() ;at!=pushedAtoms.end();++at)
2823  v0[at->first]=XYZ(ux*exp(a*(at->first->GetX()-xc)*(at->first->GetX()-xc)),
2824  uy*exp(a*(at->first->GetY()-yc)*(at->first->GetY()-yc)),
2825  uz*exp(a*(at->first->GetZ()-zc)*(at->first->GetZ()-zc)));
2826  else
2827  for(map<MolAtom*, unsigned long>::iterator at=pushedAtoms.begin() ;at!=pushedAtoms.end();++at)
2828  v0[at->first]=XYZ((at->first->GetX()-xc)*ux*exp(a*(at->first->GetX()-xc)*(at->first->GetX()-xc)),
2829  (at->first->GetY()-yc)*uy*exp(a*(at->first->GetY()-yc)*(at->first->GetY()-yc)),
2830  (at->first->GetZ()-zc)*uz*exp(a*(at->first->GetZ()-zc)*(at->first->GetZ()-zc)));
2831 
2832 
2833  #endif
2834  const REAL nrj0=mMDMoveEnergy*( this->GetBondList().size()
2835  +this->GetBondAngleList().size()
2836  +this->GetDihedralAngleList().size());
2837  map<RigidGroup*,std::pair<XYZ,XYZ> > vr;
2838  this->MolecularDynamicsEvolve(v0, int(100*sqrt(mutationAmplitude)),0.004,
2839  this->GetBondList(),
2840  this->GetBondAngleList(),
2841  this->GetDihedralAngleList(),
2842  vr,nrj0);
2843  }
2844  #else // Move atoms belonging to a MD group
2845  if((mvMDAtomGroup.size()>0)&&(rand()<(RAND_MAX*mMDMoveFreq)))
2846  {
2847  const unsigned int n=rand()%mvMDAtomGroup.size();
2848  list<MDAtomGroup>::iterator pos=mvMDAtomGroup.begin();
2849  for(unsigned int i=0;i<n;++i)++pos;
2850  map<MolAtom*,XYZ> v0;
2851  for(set<MolAtom*>::iterator at=pos->mvpAtom.begin();at!=pos->mvpAtom.end();++at)
2852  v0[*at]=XYZ(rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5);
2853 
2854  const REAL nrj0=mMDMoveEnergy*( pos->mvpBond.size()
2855  +pos->mvpBondAngle.size()
2856  +pos->mvpDihedralAngle.size());
2857  map<RigidGroup*,std::pair<XYZ,XYZ> > vr;
2858  float nrjMult=1.0+mutationAmplitude*0.2;
2859  if((rand()%20)==0) nrjMult=4.0;
2860  this->MolecularDynamicsEvolve(v0, int(100*sqrt(mutationAmplitude)),0.004,
2861  pos->mvpBond,
2862  pos->mvpBondAngle,
2863  pos->mvpDihedralAngle,
2864  vr,nrj0*nrjMult);
2865  }
2866  #endif
2867  else
2868  {
2869  #if 0 // For tests
2870  mLogLikelihood=0;
2871  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
2872  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
2873  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
2874  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
2875  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos)
2876  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
2877  for(list<StretchMode*>::const_iterator mode=mvpStretchModeNotFree.begin();
2878  mode!=mvpStretchModeNotFree.end();++mode)
2879  {
2880  //if((rand()%3)==0)
2881  {
2882  // 2) Get the derivative of the overall LLK for this mode
2883  (*mode)->CalcDeriv();
2884  REAL llk=0;
2885  for(map<const MolBond*,REAL>::const_iterator pos=(*mode)->mvpBrokenBond.begin();
2886  pos!=(*mode)->mvpBrokenBond.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
2887  for(map<const MolBondAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenBondAngle.begin();
2888  pos!=(*mode)->mvpBrokenBondAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
2889  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenDihedralAngle.begin();
2890  pos!=(*mode)->mvpBrokenDihedralAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
2891  // 3) Calculate MD move. base step =0.1 A (accelerated moves may go faster)
2892  REAL change=(2.*(REAL)rand()-(REAL)RAND_MAX)/(REAL)RAND_MAX;
2893  // if llk>100, change has to be in the opposite direction
2894  // For a single restraint, sqrt(llk)=dx/sigma, so do not go above 10*sigma
2895  if((*mode)->mLLKDeriv>0)
2896  {
2897  change -= 0.3*sqrt(llk);
2898  if(change<-1) change=-1;
2899  }
2900  else
2901  {
2902  change += 0.3*sqrt(llk);
2903  if(change>1) change=1;
2904  }
2905  (*mode)->Print(cout);
2906  change *= mutationAmplitude * (*mode)->mBaseAmplitude;
2907  cout <<" Change="<<change<<" (dLLK= "<<(*mode)->mLLKDeriv<<"), llk= "<<llk<<" ?->"<<llk+(*mode)->mLLKDeriv*change<<endl;
2908  //change *= mutationAmplitude * (*mode)->mBaseAmplitude;
2909  (*mode)->Stretch(change);
2910  llk=0;
2911  //(*mode)->RandomStretch(change * mutationAmplitude * (*mode)->mBaseAmplitude);
2912  for(map<const MolBond*,REAL>::const_iterator pos=(*mode)->mvpBrokenBond.begin();
2913  pos!=(*mode)->mvpBrokenBond.end();++pos)
2914  {
2915  cout<<" "<<pos->first->GetName()<<", llk= "<<pos->first->GetLogLikelihood(false,false)
2916  <<" ?->"<<pos->first->GetLogLikelihood(false,false)+pos->first->GetDeriv((*mode)->mDerivXYZ,true)*change
2917  <<"? (deriv="<<pos->first->GetDeriv((*mode)->mDerivXYZ)<<", "<<pos->first->GetDeriv((*mode)->mDerivXYZ,true);
2918  cout<<") ->" <<pos->first->GetLogLikelihood()<<endl;
2919  llk+=pos->first->GetLogLikelihood(false,false);
2920  }
2921  for(map<const MolBondAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenBondAngle.begin();
2922  pos!=(*mode)->mvpBrokenBondAngle.end();++pos)
2923  {
2924  cout<<" "<<pos->first->GetName()<<", llk= "<<pos->first->GetLogLikelihood(false,false)
2925  <<" ?->"<<pos->first->GetLogLikelihood(false,false)+pos->first->GetDeriv((*mode)->mDerivXYZ,true)*change
2926  <<"? (deriv="<<pos->first->GetDeriv((*mode)->mDerivXYZ)<<", "<<pos->first->GetDeriv((*mode)->mDerivXYZ,true);
2927  cout<<") ->" <<pos->first->GetLogLikelihood()<<endl;
2928  llk+=pos->first->GetLogLikelihood(false,false);
2929  }
2930  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenDihedralAngle.begin();
2931  pos!=(*mode)->mvpBrokenDihedralAngle.end();++pos)
2932  {
2933  cout<<" "<<pos->first->GetName()<<", llk= "<<pos->first->GetLogLikelihood(false,false)
2934  <<" ?->"<<pos->first->GetLogLikelihood(false,false)+pos->first->GetDeriv((*mode)->mDerivXYZ,true)*change
2935  <<"? (deriv="<<pos->first->GetDeriv((*mode)->mDerivXYZ)<<", "<<pos->first->GetDeriv((*mode)->mDerivXYZ,true);
2936  cout<<") ->" <<pos->first->GetLogLikelihood()<<endl;
2937  llk+=pos->first->GetLogLikelihood(false,false);
2938  }
2939  cout <<" -> "<<llk<<endl;
2940  }
2941  }
2942  #else
2943  // First move free Stretch modes
2944  TAU_PROFILE_START(timer2);
2945  for(list<StretchMode*>::iterator mode=mvpStretchModeFree.begin();
2946  mode!=mvpStretchModeFree.end();++mode)
2947  {
2948  if((rand()%2)==0) (*mode)->RandomStretch(mutationAmplitude);
2949  }
2950  TAU_PROFILE_STOP(timer2);
2951  if((rand()%3)==0)
2952  {
2953  // Now do an hybrid move for other modes, with a smaller amplitude (<=0.5)
2954  // 1) Calc LLK and derivatives for restraints
2955  mLogLikelihood=0;
2956  TAU_PROFILE_START(timer3);
2957  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
2958  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
2959  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
2960  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
2961  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos)
2962  mLogLikelihood+=(*pos)->GetLogLikelihood(true,true);
2963  TAU_PROFILE_STOP(timer3);
2964 
2965  TAU_PROFILE_START(timer4);
2966  for(list<StretchMode*>::const_iterator mode=mvpStretchModeNotFree.begin();
2967  mode!=mvpStretchModeNotFree.end();++mode)
2968  {
2969  // 2) Choose Stretch modes
2970  if((rand()%3)==0)
2971  {
2972  // 2) Get the derivative of the overall LLK for this mode
2973  (*mode)->CalcDeriv();
2974  REAL llk=0;
2975  for(map<const MolBond*,REAL>::const_iterator pos=(*mode)->mvpBrokenBond.begin();
2976  pos!=(*mode)->mvpBrokenBond.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
2977  for(map<const MolBondAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenBondAngle.begin();
2978  pos!=(*mode)->mvpBrokenBondAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
2979  for(map<const MolDihedralAngle*,REAL>::const_iterator pos=(*mode)->mvpBrokenDihedralAngle.begin();
2980  pos!=(*mode)->mvpBrokenDihedralAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false);
2981  REAL change=(2.*(REAL)rand()-(REAL)RAND_MAX)/(REAL)RAND_MAX;
2982  // if llk>100, change has to be in the direction minimising the llk
2983  if((*mode)->mLLKDeriv>0)
2984  {
2985  change -= 0.01*llk;
2986  if(change<-1) change=-1;
2987  }
2988  else
2989  {
2990  change += 0.01*llk;
2991  if(change>1) change=1;
2992  }
2993  if(mutationAmplitude<0.5) change *= mutationAmplitude * (*mode)->mBaseAmplitude;
2994  else change *= 0.5 * (*mode)->mBaseAmplitude;
2995  (*mode)->Stretch(change);
2996  }
2997  }
2998  // Here we do not take mLogLikelihoodScale into account
2999  // :TODO: take into account cases where the lllk cannot go down to 0 because of
3000  // combined restraints.
3001  if( ((rand()%100)==0) && (mLogLikelihood>(mvpRestraint.size()*10)))
3003  TAU_PROFILE_STOP(timer4);
3004  }
3005 
3006  // Perform MD moves if there are MDAtomGroups
3007  #if 0
3008  for(list<MDAtomGroup>::iterator pos=mvMDAtomGroup.begin();pos!=mvMDAtomGroup.end();++pos)
3009  {
3010  if((rand()%100)==0)
3011  {
3012  map<MolAtom*,XYZ> v0;
3013  for(set<MolAtom*>::iterator at=pos->mvpAtom.begin();at!=pos->mvpAtom.end();++at)
3014  v0[*at]=XYZ(rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5);
3015 
3016  const REAL nrj0=20*(pos->mvpBond.size()+pos->mvpBondAngle.size()+pos->mvpDihedralAngle.size());
3017  map<RigidGroup*,std::pair<XYZ,XYZ> > vr;
3018  this->MolecularDynamicsEvolve(v0, int(100*sqrt(mutationAmplitude)),0.002,
3019  (const vector<MolBond*>) (pos->mvpBond),
3020  (const vector<MolBondAngle*>) (pos->mvpBondAngle),
3021  (const vector<MolDihedralAngle*>) (pos->mvpDihedralAngle),
3022  vr,nrj0);
3023  }
3024  }
3025  #endif
3026  }
3027  // Do a steepest descent from time to time
3028  if((rand()%100)==0) this->OptimizeConformationSteepestDescent(0.02,1);
3029 
3030  mClockLogLikelihood.Click();
3031  #endif
3032  }
3033  }
3034  }
3035  if((rand()%100)==0)
3036  {// From time to time, bring back average position to 0
3037  REAL x0=0,y0=0,z0=0;
3038  for(vector<MolAtom*>::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
3039  {
3040  x0 += (*pos)->X();
3041  y0 += (*pos)->Y();
3042  z0 += (*pos)->Z();
3043  }
3044  x0 /= mvpAtom.size();
3045  y0 /= mvpAtom.size();
3046  z0 /= mvpAtom.size();
3047  for(vector<MolAtom*>::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
3048  {
3049  (*pos)->X() -= x0;
3050  (*pos)->Y() -= y0;
3051  (*pos)->Z() -= z0;
3052  }
3053  }
3054  mRandomMoveIsDone=true;
3055  VFN_DEBUG_EXIT("Molecule::GlobalOptRandomMove()",4)
3056 }
3057 
3059 {
3060  if( (mClockLogLikelihood>mClockAtomList)
3061  &&(mClockLogLikelihood>mClockBondList)
3062  &&(mClockLogLikelihood>mClockBondAngleList)
3063  &&(mClockLogLikelihood>mClockDihedralAngleList)
3064  &&(mClockLogLikelihood>mClockAtomPosition)
3065  &&(mClockLogLikelihood>mClockScatterer)) return mLogLikelihood*mLogLikelihoodScale;
3066  TAU_PROFILE("Molecule::GetLogLikelihood()","REAL ()",TAU_DEFAULT);
3068  mClockLogLikelihood.Click();
3070 }
3071 
3072 unsigned int Molecule::GetNbLSQFunction()const
3073 {
3074  return 1;
3075 }
3076 
3077 const CrystVector_REAL& Molecule::GetLSQCalc(const unsigned int) const
3078 {
3079  mLSQCalc.resize(mvpRestraint.size());
3080  REAL *p=mLSQCalc.data();
3081  for(vector<MolBond*>::const_iterator pos=this->GetBondList().begin();pos!=this->GetBondList().end();++pos)
3082  *p++=(*pos)->GetLength();
3083  for(vector<MolBondAngle*>::const_iterator pos=this->GetBondAngleList().begin();pos!=this->GetBondAngleList().end();++pos)
3084  *p++=(*pos)->GetAngle();
3085  for(vector<MolDihedralAngle*>::const_iterator pos=this->GetDihedralAngleList().begin();pos!=this->GetDihedralAngleList().end();++pos)
3086  *p++=(*pos)->GetAngle();
3087  return mLSQCalc;
3088 }
3089 
3090 const CrystVector_REAL& Molecule::GetLSQObs(const unsigned int) const
3091 {
3092  mLSQObs.resize(mvpRestraint.size());
3093  REAL *p=mLSQObs.data();
3094  for(vector<MolBond*>::const_iterator pos=this->GetBondList().begin();pos!=this->GetBondList().end();++pos)
3095  *p++=(*pos)->GetLength0();
3096  for(vector<MolBondAngle*>::const_iterator pos=this->GetBondAngleList().begin();pos!=this->GetBondAngleList().end();++pos)
3097  *p++=(*pos)->GetAngle0();
3098  for(vector<MolDihedralAngle*>::const_iterator pos=this->GetDihedralAngleList().begin();pos!=this->GetDihedralAngleList().end();++pos)
3099  *p++=(*pos)->GetAngle0();
3100  return mLSQObs;
3101 }
3102 
3103 const CrystVector_REAL& Molecule::GetLSQWeight(const unsigned int) const
3104 {
3105  //:TODO: USe a clock to avoid re-computation
3106  mLSQWeight.resize(mvpRestraint.size());
3107  REAL *p=mLSQWeight.data();
3108  for(vector<MolBond*>::const_iterator pos=this->GetBondList().begin();pos!=this->GetBondList().end();++pos)
3109  *p++=1/((*pos)->GetLengthSigma()* (*pos)->GetLengthSigma()+1e-6);
3110  for(vector<MolBondAngle*>::const_iterator pos=this->GetBondAngleList().begin();pos!=this->GetBondAngleList().end();++pos)
3111  *p++=1/((*pos)->GetAngleSigma()* (*pos)->GetAngleSigma()+1e-6);
3112  for(vector<MolDihedralAngle*>::const_iterator pos=this->GetDihedralAngleList().begin();pos!=this->GetDihedralAngleList().end();++pos)
3113  *p++=1/((*pos)->GetAngleSigma()* (*pos)->GetAngleSigma()+1e-6);
3115  return mLSQWeight;
3116 }
3117 
3118 const CrystVector_REAL& Molecule::GetLSQDeriv(const unsigned int n, RefinablePar&par)
3119 {
3120  //:TODO: return analytical derivatives
3121  return RefinableObj::GetLSQDeriv(n,par);
3122 }
3123 
3125 {
3126  this->ResetRigidGroupsPar();
3127  #if 0
3128  cout<<"Molecule::TagNewBestConfig()"<<endl;
3129  {
3130  vector<MolBond*>::const_iterator pos;
3131  for(pos=mvpBond.begin();pos!=mvpBond.end();++pos)
3132  {
3133  cout<<"BondLength="<<(*pos)->GetLength();
3134  (*pos)->XMLOutput(cout);
3135  }
3136  }
3137  {
3138  vector<MolBondAngle*>::const_iterator pos;
3139  for(pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
3140  {
3141  cout<<"BondAngle="<<(*pos)->GetAngle();
3142  (*pos)->XMLOutput(cout);
3143  }
3144  }
3145  {
3146  vector<MolDihedralAngle*>::const_iterator pos;
3147  for(pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos)
3148  {
3149  cout<<"DihedralAngle="<<(*pos)->GetAngle();
3150  (*pos)->XMLOutput(cout);
3151  }
3152  }
3153 
3154  for(list<MDAtomGroup>::iterator pos=mvMDAtomGroup.begin();pos!=mvMDAtomGroup.end();++pos)
3155  {
3156  char buf[100];
3157  for(set<MolAtom*>::iterator at1=pos->mvpAtom.begin();at1!=pos->mvpAtom.end();++at1)
3158  {
3159  sprintf(buf,"%5s : ",(*at1)->GetName().c_str());
3160  cout<<buf;
3161  for(set<MolAtom*>::iterator at2=at1;at2!=pos->mvpAtom.end();++at2)
3162  {
3163  if(at1==at2) continue;
3164  sprintf(buf,"%5s(%6.3f),",(*at2)->GetName().c_str(),GetBondLength(**at1,**at2));
3165  cout<<buf;
3166  }
3167  cout<<endl;
3168  }
3169  }
3170  #endif
3171 }
3172 
3173 int Molecule::GetNbComponent() const { return mvpAtom.size();}
3174 
3176 {
3177  VFN_DEBUG_ENTRY("Molecule::GetScatteringComponentList()",3)
3178  this->UpdateScattCompList();
3179  VFN_DEBUG_EXIT("Molecule::GetScatteringComponentList()",3)
3180  return mScattCompList;
3181 }
3182 
3183 string Molecule::GetComponentName(const int i) const
3184 {
3185  //if(mvpAtom[i]->IsDummy()) return "Dummy";
3186  return mvpAtom[i]->GetName();
3187 }
3188 
3189 ostream& Molecule::POVRayDescription(ostream &os,const CrystalPOVRayOptions &options)const
3190 {
3191  VFN_DEBUG_ENTRY("Molecule::POVRayDescription()",3)
3192  const REAL xMin=options.mXmin; const REAL xMax=options.mXmax;
3193  const REAL yMin=options.mYmin; const REAL yMax=options.mYmax;
3194  const REAL zMin=options.mZmin; const REAL zMax=options.mZmax;
3195  if(mvpAtom.size()==0)
3196  {
3197  VFN_DEBUG_EXIT("Molecule::POVRayDescription():No atom to display !",4)
3198  return os;
3199  }
3200  this->UpdateScattCompList();
3201 
3202  const REAL aa=this->GetCrystal().GetLatticePar(0);
3203  const REAL bb=this->GetCrystal().GetLatticePar(1);
3204  const REAL cc=this->GetCrystal().GetLatticePar(2);
3205 
3206  os << "// Description of Molecule :" << this->GetName() <<endl;
3207  vector<CrystMatrix_REAL> vXYZCoords;
3208  {
3210  REAL x0,y0,z0;
3211  for(long i=0;i<mScattCompList.GetNbComponent();++i)
3212  {
3213  x0=mScattCompList(i).mX;
3214  y0=mScattCompList(i).mY;
3215  z0=mScattCompList(i).mZ;
3216  vXYZCoords.push_back(this->GetCrystal().GetSpaceGroup().
3217  GetAllSymmetrics(x0,y0,z0,false,false,false));
3218  }
3219  }
3220  CrystMatrix_int translate(27,3);
3221  translate= -1,-1,-1,
3222  -1,-1, 0,
3223  -1,-1, 1,
3224  -1, 0,-1,
3225  -1, 0, 0,
3226  -1, 0, 1,
3227  -1, 1,-1,
3228  -1, 1, 0,
3229  -1, 1, 1,
3230  0,-1,-1,
3231  0,-1, 0,
3232  0,-1, 1,
3233  0, 0,-1,
3234  0, 0, 0,
3235  0, 0, 1,
3236  0, 1,-1,
3237  0, 1, 0,
3238  0, 1, 1,
3239  1,-1,-1,
3240  1,-1, 0,
3241  1,-1, 1,
3242  1, 0,-1,
3243  1, 0, 0,
3244  1, 0, 1,
3245  1, 1,-1,
3246  1, 1, 0,
3247  1, 1, 1;
3248  REAL dx,dy,dz;
3249  CrystVector_REAL x(mvpAtom.size()),y(mvpAtom.size()),z(mvpAtom.size());
3250  CrystVector_REAL xSave,ySave,zSave;
3251  const int nbSymmetrics=vXYZCoords[0].rows();
3252  unsigned int ct=0;
3253  for(int i=0;i<nbSymmetrics;i++)
3254  {
3255  VFN_DEBUG_ENTRY("Molecule::POVRayDescription():Symmetric#"<<i,3)
3256  for(unsigned int j=0;j<mvpAtom.size();j++)
3257  {
3258  x(j)=vXYZCoords[j](i,0);
3259  y(j)=vXYZCoords[j](i,1);
3260  z(j)=vXYZCoords[j](i,2);
3261  }
3262  //Bring back central atom in unit cell; move peripheral atoms with the same amount
3263  dx=x(0);
3264  dy=y(0);
3265  dz=z(0);
3266  x(0) = fmod((float) x(0),(float)1); if(x(0)<0) x(0)+=1.;
3267  y(0) = fmod((float) y(0),(float)1); if(y(0)<0) y(0)+=1.;
3268  z(0) = fmod((float) z(0),(float)1); if(z(0)<0) z(0)+=1.;
3269  dx = x(0)-dx;
3270  dy = y(0)-dy;
3271  dz = z(0)-dz;
3272  for(unsigned int j=1;j<mvpAtom.size();j++)
3273  {
3274  x(j) += dx;
3275  y(j) += dy;
3276  z(j) += dz;
3277  }
3278  //Generate also translated atoms near the unit cell
3279  xSave=x;
3280  ySave=y;
3281  zSave=z;
3282  for(int j=0;j<translate.rows();j++)
3283  {
3284  x += translate(j,0);
3285  y += translate(j,1);
3286  z += translate(j,2);
3287  CrystVector<bool> isinside(x.numElements());
3288  CrystVector<REAL> borderdist(x.numElements());//distance to display limit
3289  CrystVector<REAL> x0,y0,z0;
3290  x0=x;y0=y;z0=z;
3291  if( ((x.min()<xMax) && (x.max()>xMin))
3292  &&((y.min()<yMax) && (y.max()>yMin))
3293  &&((z.min()<zMax) && (z.max()>zMin)))
3294  {
3295  os<<" //Symetric#"<<++ct<<endl;
3296  for(unsigned int k=0;k<mvpAtom.size();k++)
3297  {
3298  isinside(k)=((x(k)>=xMin) && (x(k)<=xMax)) && ((y(k)>=yMin) && (y(k)<=yMax)) && ((z(k)>=zMin) && (z(k)<=zMax));
3299  if(isinside(k)) borderdist(k)=0;
3300  else
3301  {
3302  borderdist(k)=0;
3303  if(xMin>x(k)) borderdist(k)+=(xMin-x(k))*aa*(xMin-x(k))*aa;
3304  if(yMin>y(k)) borderdist(k)+=(yMin-y(k))*bb*(yMin-y(k))*bb;
3305  if(zMin>z(k)) borderdist(k)+=(zMin-z(k))*cc*(zMin-z(k))*cc;
3306  if(xMax<x(k)) borderdist(k)+=(xMax-x(k))*aa*(xMax-x(k))*aa;
3307  if(yMax<y(k)) borderdist(k)+=(yMax-y(k))*bb*(yMax-y(k))*bb;
3308  if(zMax<z(k)) borderdist(k)+=(zMax-z(k))*cc*(zMax-z(k))*cc;
3309  borderdist(k)=sqrt(borderdist(k));
3310  }
3311  REAL fout=1.0;
3312  if(isinside(k)==false) fout=exp(-borderdist(k))*this->GetCrystal().GetDynPopCorr(this,k);
3313 
3314  this->GetCrystal().FractionalToOrthonormalCoords(x(k),y(k),z(k));
3315  if((mvpAtom[k]->IsDummy()) || (fout<0.001)) continue;
3316  if(options.mShowHydrogens==false && (mvpAtom[k]->GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue;
3317  // const float r=mvpAtom[k]->GetScatteringPower().GetColourRGB()[0];
3318  // const float g=mvpAtom[k]->GetScatteringPower().GetColourRGB()[1];
3319  // const float b=mvpAtom[k]->GetScatteringPower().GetColourRGB()[2];
3320  const float f=mvpAtom[k]->GetOccupancy()*this->GetOccupancy();
3321  if(options.mShowLabel)
3322  {
3323  /*
3324  const float colour0[] = {0.0f, 0.0f, 0.0f, 0.0f};
3325  GLfloat colourChar [] = {1.0, 1.0, 1.0, 1.0};
3326  if((r>0.8)&&(g>0.8)&&(b>0.8))
3327  {
3328  colourChar[0] = 0.5;
3329  colourChar[1] = 0.5;
3330  colourChar[2] = 0.5;
3331  }
3332  glMaterialfv(GL_FRONT, GL_AMBIENT, colour0);
3333  glMaterialfv(GL_FRONT, GL_DIFFUSE, colour0);
3334  glMaterialfv(GL_FRONT, GL_SPECULAR, colour0);
3335  glMaterialfv(GL_FRONT, GL_EMISSION, colourChar);
3336  glMaterialfv(GL_FRONT, GL_SHININESS,colour0);
3337  glRasterPos3f(x(k), y(k), z(k));
3338  crystGLPrint(mvpAtom[k]->GetName());
3339  */
3340  }
3341  os << " ObjCrystAtom("
3342  <<x(k)<<","
3343  <<y(k)<<","
3344  <<z(k)<<","
3345  <<mvpAtom[k]->GetScatteringPower().GetRadius()/3.0<<","
3346  <<"colour_"+mvpAtom[k]->GetScatteringPower().GetName()<<","
3347  <<f<<","<<fout
3348  <<")"<<endl;
3349  }
3350  for(unsigned int k=0;k<mvpBond.size();k++)
3351  {
3352  if( (mvpBond[k]->GetAtom1().IsDummy())
3353  ||(mvpBond[k]->GetAtom2().IsDummy()) ) continue;
3354  if(options.mShowHydrogens==false && ( (mvpBond[k]->GetAtom1().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)
3355  ||(mvpBond[k]->GetAtom2().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5))) continue;
3356  unsigned long n1,n2;
3357  //:KLUDGE: Get the atoms
3358  for(n1=0;n1<mvpAtom.size();n1++)
3359  if(mvpAtom[n1]==&(mvpBond[k]->GetAtom1())) break;
3360  for(n2=0;n2<mvpAtom.size();n2++)
3361  if(mvpAtom[n2]==&(mvpBond[k]->GetAtom2())) break;
3362  REAL fout=1.0;
3363  if((isinside(n1)==false) || (isinside(n2)==false))
3364  fout=exp(-(borderdist(n1)+borderdist(n2))/2)*(this->GetCrystal().GetDynPopCorr(this,n1)+this->GetCrystal().GetDynPopCorr(this,n2))/2;
3365  if(fout<0.001) continue;
3366  REAL x1=x(n1),y1=y(n1),z1=z(n1),
3367  x2=x(n2),y2=y(n2),z2=z(n2);
3368  REAL dx=x2-x1,dy=y2-y1,dz=z2-z1;
3369  const REAL r=sqrt(abs(dx*dx+dy*dy+dz*dz))+1e-6;
3370  const REAL r1=mvpAtom[n1]->GetScatteringPower().GetRadius()/3.0;
3371  const REAL r2=mvpAtom[n2]->GetScatteringPower().GetRadius()/3.0;
3372  x1+=dx/r*r1*sqrt(abs(1-0.1/r1));
3373  y1+=dy/r*r1*sqrt(abs(1-0.1/r1));
3374  z1+=dz/r*r1*sqrt(abs(1-0.1/r1));
3375  x2-=dx/r*r2*sqrt(abs(1-0.1/r2));
3376  y2-=dy/r*r2*sqrt(abs(1-0.1/r2));
3377  z2-=dz/r*r2*sqrt(abs(1-0.1/r2));
3378  const REAL f=this->GetOccupancy()*(mvpAtom[n1]->GetOccupancy()+mvpAtom[n2]->GetOccupancy())/2.0;
3379  os << " ObjCrystBond("
3380  <<x1<<","<<y1<<","<<z1<< ","
3381  <<x2<<","<<y2<<","<<z2<< ","
3382  << "0.1,";
3383  if(mvpBond[k]->IsFreeTorsion()) os<<"colour_freebond,";
3384  else os<<"colour_nonfreebond,";
3385  os<<f<<","<<fout<<")"<<endl;
3386  }
3387  }//if in limits
3388  x=xSave;
3389  y=ySave;
3390  z=zSave;
3391  }//for translation
3392  VFN_DEBUG_EXIT("Molecule::POVRayDescription():Symmetric#"<<i,3)
3393  }//for symmetrics
3394  VFN_DEBUG_EXIT("Molecule::POVRayDescription()",3)
3395  return os;
3396 }
3397 
3398 void Molecule::GLInitDisplayList(const bool onlyIndependentAtoms,
3399  const REAL xMin,const REAL xMax,
3400  const REAL yMin,const REAL yMax,
3401  const REAL zMin,const REAL zMax,
3402  const bool displayEnantiomer,
3403  const bool displayNames,
3404  const bool hideHydrogens)const
3405 {
3406  #ifdef OBJCRYST_GL
3407  VFN_DEBUG_ENTRY("Molecule::GLInitDisplayList()",3)
3408  if(mvpAtom.size()==0)
3409  {
3410  VFN_DEBUG_EXIT("Molecule::GLInitDisplayList():No atom to display !",4)
3411  return;
3412  }
3413  bool large=false;
3414  if(mvpAtom.size()>200) large=true;
3415  REAL en=1;
3416  if(displayEnantiomer==true) en=-1;
3417  this->UpdateScattCompList();
3418  //this->BuildRingList();
3419  //this->BuildStretchModeBondLength();
3420  //this->BuildStretchModeBondAngle();
3421  //this->BuildStretchModeTorsion();
3422 
3423  const REAL aa=this->GetCrystal().GetLatticePar(0);
3424  const REAL bb=this->GetCrystal().GetLatticePar(1);
3425  const REAL cc=this->GetCrystal().GetLatticePar(2);
3426 
3427  const GLfloat colour0[] = {0.0f, 0.0f, 0.0f, 0.0f};
3428  glMaterialfv(GL_FRONT, GL_SPECULAR, colour0);
3429  glMaterialfv(GL_FRONT, GL_EMISSION, colour0);
3430  glMaterialfv(GL_FRONT, GL_SHININESS, colour0);
3431  glPolygonMode(GL_FRONT, GL_FILL);
3432 
3433  GLUquadricObj* pQuadric = gluNewQuadric();
3434 
3435  if(true==onlyIndependentAtoms)//
3436  {
3437  REAL xc=mXYZ(0),yc=mXYZ(1),zc=mXYZ(2);
3438  this->GetCrystal().FractionalToOrthonormalCoords(xc,yc,zc);
3439  vector<MolAtom*>::const_iterator pos;
3440  for(pos=mvpAtom.begin();pos!=mvpAtom.end();pos++)
3441  {
3442 
3443  if((*pos)->IsDummy())continue;
3444  if(hideHydrogens && ((*pos)->GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue;
3445  const float r=(*pos)->GetScatteringPower().GetColourRGB()[0];
3446  const float g=(*pos)->GetScatteringPower().GetColourRGB()[1];
3447  const float b=(*pos)->GetScatteringPower().GetColourRGB()[2];
3448  const float f=(*pos)->GetOccupancy()*this->GetOccupancy();
3449  glPushMatrix();
3450  if(displayNames)
3451  {
3452  GLfloat colourChar [] = {1.0, 1.0, 1.0, 1.0};
3453  GLfloat colourCharRing [] = {1.0, 1.0, 0.8, 1.0};
3454  if((r>0.8)&&(g>0.8)&&(b>0.8))
3455  {
3456  colourChar[0] = 0.5;
3457  colourChar[1] = 0.5;
3458  colourChar[2] = 0.5;
3459  }
3460  if((*pos)->IsInRing())
3461  glMaterialfv(GL_FRONT, GL_EMISSION, colourCharRing);
3462  else
3463  glMaterialfv(GL_FRONT, GL_EMISSION, colourChar);
3464  glMaterialfv(GL_FRONT, GL_SHININESS, colour0);
3465  glTranslatef((*pos)->X()*en+xc, (*pos)->Y()+yc, (*pos)->Z()+zc);
3466  crystGLPrint((*pos)->GetName());
3467  }
3468  else
3469  {
3470  const GLfloat colourAtom [] = {r, g, b, f};
3471  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colourAtom);
3472  glTranslatef((*pos)->X()*en+xc, (*pos)->Y()+yc, (*pos)->Z()+zc);
3473  gluSphere(pQuadric,(*pos)->GetScatteringPower().GetRadius()/3.,20,20);
3474  }
3475  glPopMatrix();
3476  }
3477  }//Only independent atoms ?
3478  else
3479  {
3480  VFN_DEBUG_ENTRY("Molecule::GLInitDisplayList():Show all symmetrics",3)
3481  // Reverse index of atoms
3482  map<const MolAtom*,unsigned long> rix;
3483  {
3484  long i=0;
3485  for(vector<MolAtom*>::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
3486  rix[*pos]=i++;
3487  }
3488  vector<CrystMatrix_REAL> vXYZCoords;
3489  {
3491  REAL x0,y0,z0;
3492  for(long i=0;i<mScattCompList.GetNbComponent();++i)
3493  {
3494  x0=mScattCompList(i).mX;
3495  y0=mScattCompList(i).mY;
3496  z0=mScattCompList(i).mZ;
3497  vXYZCoords.push_back(this->GetCrystal().GetSpaceGroup().
3498  GetAllSymmetrics(x0,y0,z0,false,false,false));
3499  }
3500  }
3501  CrystMatrix_int translate(27,3);
3502  translate= -1,-1,-1,
3503  -1,-1, 0,
3504  -1,-1, 1,
3505  -1, 0,-1,
3506  -1, 0, 0,
3507  -1, 0, 1,
3508  -1, 1,-1,
3509  -1, 1, 0,
3510  -1, 1, 1,
3511  0,-1,-1,
3512  0,-1, 0,
3513  0,-1, 1,
3514  0, 0,-1,
3515  0, 0, 0,
3516  0, 0, 1,
3517  0, 1,-1,
3518  0, 1, 0,
3519  0, 1, 1,
3520  1,-1,-1,
3521  1,-1, 0,
3522  1,-1, 1,
3523  1, 0,-1,
3524  1, 0, 0,
3525  1, 0, 1,
3526  1, 1,-1,
3527  1, 1, 0,
3528  1, 1, 1;
3529  REAL dx,dy,dz;
3530  CrystVector_REAL x(mvpAtom.size()),y(mvpAtom.size()),z(mvpAtom.size());
3531  CrystVector_REAL xSave,ySave,zSave;
3532  const int nbSymmetrics=vXYZCoords[0].rows();
3533  for(int i=0;i<nbSymmetrics;i++)
3534  {
3535  VFN_DEBUG_ENTRY("Molecule::GLInitDisplayList():Symmetric#"<<i,3)
3536  for(unsigned int j=0;j<mvpAtom.size();j++)
3537  {
3538  x(j)=vXYZCoords[j](i,0);
3539  y(j)=vXYZCoords[j](i,1);
3540  z(j)=vXYZCoords[j](i,2);
3541  }
3542  //Bring back central atom in unit cell; move peripheral atoms with the same amount
3543  dx=x(0);
3544  dy=y(0);
3545  dz=z(0);
3546  x(0) = fmod((float) x(0),(float)1); if(x(0)<0) x(0)+=1.;
3547  y(0) = fmod((float) y(0),(float)1); if(y(0)<0) y(0)+=1.;
3548  z(0) = fmod((float) z(0),(float)1); if(z(0)<0) z(0)+=1.;
3549  dx = x(0)-dx;
3550  dy = y(0)-dy;
3551  dz = z(0)-dz;
3552  for(unsigned int j=1;j<mvpAtom.size();j++)
3553  {
3554  x(j) += dx;
3555  y(j) += dy;
3556  z(j) += dz;
3557  }
3558  //Generate also translated atoms near the unit cell
3559  xSave=x;
3560  ySave=y;// Keep untranslated, fractionnal values
3561  zSave=z;
3562  for(int j=0;j<translate.rows();j++)
3563  {
3564  x += translate(j,0);
3565  y += translate(j,1);
3566  z += translate(j,2);
3567  CrystVector<bool> isinside(x.numElements());
3568  CrystVector<REAL> borderdist(x.numElements());//distance to display limit
3569  if( ((x.min()<xMax) && (x.max()>xMin))
3570  &&((y.min()<yMax) && (y.max()>yMin))
3571  &&((z.min()<zMax) && (z.max()>zMin)))
3572  {
3573  for(unsigned int k=0;k<mvpAtom.size();k++)
3574  {
3575  isinside(k)=((x(k)>=xMin) && (x(k)<=xMax)) && ((y(k)>=yMin) && (y(k)<=yMax)) && ((z(k)>=zMin) && (z(k)<=zMax));
3576  if(isinside(k)) borderdist(k)=0;
3577  else
3578  {
3579  borderdist(k)=0;
3580  if(xMin>x(k)) borderdist(k)+=(xMin-x(k))*aa*(xMin-x(k))*aa;
3581  if(yMin>y(k)) borderdist(k)+=(yMin-y(k))*bb*(yMin-y(k))*bb;
3582  if(zMin>z(k)) borderdist(k)+=(zMin-z(k))*cc*(zMin-z(k))*cc;
3583  if(xMax<x(k)) borderdist(k)+=(xMax-x(k))*aa*(xMax-x(k))*aa;
3584  if(yMax<y(k)) borderdist(k)+=(yMax-y(k))*bb*(yMax-y(k))*bb;
3585  if(zMax<z(k)) borderdist(k)+=(zMax-z(k))*cc*(zMax-z(k))*cc;
3586  borderdist(k)=sqrt(borderdist(k));
3587  }
3588  REAL fout=1.0;
3589  if(isinside(k)==false) fout=exp(-borderdist(k))*this->GetCrystal().GetDynPopCorr(this,k);
3590  #ifdef __DEBUG__
3591  char ch[100];
3592  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);
3593  VFN_DEBUG_MESSAGE(ch,4)
3594  #endif
3595  this->GetCrystal().FractionalToOrthonormalCoords(x(k),y(k),z(k));
3596  if(mvpAtom[k]->IsDummy()) continue;
3597  if(hideHydrogens && (mvpAtom[k]->GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue;
3598  if(fout<0.01) continue;
3599  glPushMatrix();
3600  const float r=mvpAtom[k]->GetScatteringPower().GetColourRGB()[0];
3601  const float g=mvpAtom[k]->GetScatteringPower().GetColourRGB()[1];
3602  const float b=mvpAtom[k]->GetScatteringPower().GetColourRGB()[2];
3603  const float f=mvpAtom[k]->GetOccupancy()*this->GetOccupancy();
3604  if(displayNames)
3605  {
3606  if(fout>0.99)
3607  {
3608  GLfloat colourChar [] = {1.0, 1.0, 1.0, f*fout};
3609  GLfloat colourCharRing [] = {1.0, 1.0, 0.8, f*fout};
3610  if((r>0.8)&&(g>0.8)&&(b>0.8))
3611  {
3612  colourChar[0] = 0.5;
3613  colourChar[1] = 0.5;
3614  colourChar[2] = 0.5;
3615  }
3616  if(mvpAtom[k]->IsInRing())
3617  glMaterialfv(GL_FRONT, GL_EMISSION, colourCharRing);
3618  else
3619  glMaterialfv(GL_FRONT, GL_EMISSION, colourChar);
3620  glRasterPos3f(x(k)*en, y(k), z(k));
3621  crystGLPrint(mvpAtom[k]->GetName());
3622  }
3623  }
3624  else
3625  {
3626  if(!large)
3627  {
3628  const GLfloat colourAtom [] = {r*fout, g*fout, b*fout, f*fout};
3629  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,colourAtom);
3630  glTranslatef(x(k)*en, y(k), z(k));
3631  gluSphere(pQuadric,
3632  mvpAtom[k]->GetScatteringPower().GetRadius()/3.,20,20);
3633  }
3634  else
3635  {
3636  const GLfloat colourAtom [] = {r*fout, g*fout, b*fout, f*fout};
3637  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,colourAtom);
3638  glTranslatef(x(k)*en, y(k), z(k));
3639  gluSphere(pQuadric,.15,10,10);
3640  }
3641  }
3642  glPopMatrix();
3643  }
3644  if(displayNames==false)
3645  {
3646  if(large)
3647  {
3648  for(unsigned int k=0;k<mvpBond.size();k++)
3649  {
3650  if( (mvpBond[k]->GetAtom1().IsDummy())
3651  ||(mvpBond[k]->GetAtom2().IsDummy()) ) continue;
3652  if(hideHydrogens && ( (mvpBond[k]->GetAtom1().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)
3653  ||(mvpBond[k]->GetAtom2().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5))) continue;
3654  const unsigned long n1=rix[&(mvpBond[k]->GetAtom1())],
3655  n2=rix[&(mvpBond[k]->GetAtom2())];
3656  REAL fout=1.0;
3657  if((isinside(n1)==false) || (isinside(n2)==false))
3658  fout=exp(-(borderdist(n1)+borderdist(n2))/2)*(this->GetCrystal().GetDynPopCorr(this,n1)+this->GetCrystal().GetDynPopCorr(this,n2))/2;
3659  if(fout<0.01) continue;
3660 
3661  const float r1=mvpBond[k]->GetAtom1().GetScatteringPower().GetColourRGB()[0];
3662  const float g1=mvpBond[k]->GetAtom1().GetScatteringPower().GetColourRGB()[1];
3663  const float b1=mvpBond[k]->GetAtom1().GetScatteringPower().GetColourRGB()[2];
3664  const float f1=mvpBond[k]->GetAtom1().GetOccupancy()*this->GetOccupancy();
3665  const float r2=mvpBond[k]->GetAtom2().GetScatteringPower().GetColourRGB()[0];
3666  const float g2=mvpBond[k]->GetAtom2().GetScatteringPower().GetColourRGB()[1];
3667  const float b2=mvpBond[k]->GetAtom2().GetScatteringPower().GetColourRGB()[2];
3668  const float f2=mvpBond[k]->GetAtom2().GetOccupancy()*this->GetOccupancy();
3669  const GLfloat colourAtom1 [] = {r1, g1, b1, f1*fout};
3670  const GLfloat colourAtom2 [] = {r2, g2, b2, f2*fout};
3671  #if 0
3672  glPushMatrix();
3673  glBegin(GL_LINE_STRIP);
3674  glMaterialfv(GL_FRONT, GL_SPECULAR, colourAtom1);
3675  glMaterialfv(GL_FRONT, GL_EMISSION, colourAtom1);
3676  glMaterialfv(GL_FRONT, GL_SHININESS, colourAtom1);
3677  glVertex3f(x(n1)*en,y(n1),z(n1));
3678  glVertex3f((x(n1)+x(n2))/2*en,(y(n1)+y(n2))/2,(z(n1)+z(n2))/2);
3679  glMaterialfv(GL_FRONT, GL_SPECULAR, colourAtom2);
3680  glMaterialfv(GL_FRONT, GL_EMISSION, colourAtom2);
3681  glMaterialfv(GL_FRONT, GL_SHININESS, colourAtom2);
3682  glVertex3f(x(n2)*en,y(n2),z(n2));
3683  glEnd();
3684  glPopMatrix();
3685  #else
3686  const REAL height= sqrt(abs( (x(n2)-x(n1))*(x(n2)-x(n1))
3687  +(y(n2)-y(n1))*(y(n2)-y(n1))
3688  +(z(n2)-z(n1))*(z(n2)-z(n1))));
3689  glPushMatrix();
3690  glTranslatef(x(n1)*en, y(n1), z(n1));
3691  GLUquadricObj *quadobj = gluNewQuadric();
3692  glRotatef(180,(x(n2)-x(n1))*en,y(n2)-y(n1),z(n2)-z(n1)+height);// ?!?!?!
3693 
3694  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colourAtom1);
3695  gluCylinder(quadobj,.1,.1,height/2,10,1 );
3696  gluDeleteQuadric(quadobj);
3697 
3698  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colourAtom2);
3699  GLUquadricObj *quadobj2 = gluNewQuadric();
3700  glTranslatef(0, 0, height/2);
3701  gluCylinder(quadobj2,.1,.1,height/2,10,1 );
3702  gluDeleteQuadric(quadobj2);
3703  glPopMatrix();
3704  #endif
3705  }
3706  }
3707  else
3708  {
3709  for(unsigned int k=0;k<mvpBond.size();k++)
3710  {
3711  if( (mvpBond[k]->GetAtom1().IsDummy())
3712  ||(mvpBond[k]->GetAtom2().IsDummy()) ) continue;
3713  if(hideHydrogens && ( (mvpBond[k]->GetAtom1().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)
3714  ||(mvpBond[k]->GetAtom2().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5))) continue;
3715  const unsigned long n1=rix[&(mvpBond[k]->GetAtom1())],
3716  n2=rix[&(mvpBond[k]->GetAtom2())];
3717  REAL fout=1.0;
3718  if((isinside(n1)==false) || (isinside(n2)==false)) fout=exp(-(borderdist(n1)+borderdist(n2))/2);
3719  if(fout<0.01) continue;
3720  // Is the bond in a rigid group ?
3721  bool isRigidGroup=false;
3722  for(vector<RigidGroup *>::const_iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
3723  {
3724  if( ((*pos)->find(&(mvpBond[k]->GetAtom1()))!=(*pos)->end())
3725  &&((*pos)->find(&(mvpBond[k]->GetAtom2()))!=(*pos)->end()) )
3726  {
3727  isRigidGroup=true;
3728  break;
3729  }
3730  }
3731  const float f=(mvpBond[k]->GetAtom1().GetOccupancy()+mvpBond[k]->GetAtom2().GetOccupancy())/2*this->GetOccupancy();
3732  const GLfloat colour_bondnonfree[]= { 0.2*fout, .2*fout, .2*fout, f*fout };
3733  const GLfloat colour_bondrigid[]= { 0.5*fout, .3*fout, .3*fout, f*fout };
3734  const GLfloat colour_bondfree[]= { 0.8*fout, .8*fout, .8*fout, f*fout };
3735  if(isRigidGroup)
3736  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colour_bondrigid);
3737  else
3738  {
3739  if(mvpBond[k]->IsFreeTorsion())
3740  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colour_bondfree);
3741  else
3742  glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colour_bondnonfree);
3743  }
3744  // Actually make the bond start/end at the surface of the spheres (matters when transparent)
3745  REAL x1=x(n1),y1=y(n1),z1=z(n1),
3746  x2=x(n2),y2=y(n2),z2=z(n2);
3747  REAL dx=x2-x1,dy=y2-y1,dz=z2-z1;
3748  const REAL r=sqrt(abs(dx*dx+dy*dy+dz*dz))+1e-6;
3749  const REAL r1=mvpAtom[n1]->GetScatteringPower().GetRadius()/3.0;
3750  const REAL r2=mvpAtom[n2]->GetScatteringPower().GetRadius()/3.0;
3751  x1+=dx/r*r1*sqrt(abs(1-0.1/r1));
3752  y1+=dy/r*r1*sqrt(abs(1-0.1/r1));
3753  z1+=dz/r*r1*sqrt(abs(1-0.1/r1));
3754  x2-=dx/r*r2*sqrt(abs(1-0.1/r2));
3755  y2-=dy/r*r2*sqrt(abs(1-0.1/r2));
3756  z2-=dz/r*r2*sqrt(abs(1-0.1/r2));
3757 
3758  glPushMatrix();
3759  glTranslatef(x1*en, y1, z1);
3760  GLUquadricObj *quadobj = gluNewQuadric();
3761  //glColor4f(1.0f,1.0f,1.0f,1.0);
3762  const REAL height= sqrt(abs( (x2-x1)*(x2-x1)
3763  +(y2-y1)*(y2-y1)
3764  +(z2-z1)*(z2-z1)));
3765  glRotatef(180,(x2-x1)*en,y2-y1,z2-z1+height);// ?!?!?!
3766  gluCylinder(quadobj,.1,.1,height,10,1 );
3767  gluDeleteQuadric(quadobj);
3768  glPopMatrix();
3769  }
3770  }
3771  }
3772  }//if in limits
3773  x=xSave;
3774  y=ySave;
3775  z=zSave;
3776  }//for translation
3777  VFN_DEBUG_EXIT("Molecule::GLInitDisplayList():Symmetric#"<<i,3)
3778  }//for symmetrics
3779  VFN_DEBUG_EXIT("Molecule::GLInitDisplayList():Show all symmetrics",3)
3780  }//else
3781  gluDeleteQuadric(pQuadric);
3782  VFN_DEBUG_EXIT("Molecule::GLInitDisplayList()",3)
3783  #endif //GLCryst
3784 }
3785 
3786 void Molecule::AddAtom(const REAL x, const REAL y, const REAL z,
3787  const ScatteringPower *pPow, const string &name,
3788  const bool updateDisplay)
3789 {
3790  VFN_DEBUG_ENTRY("Molecule::AddAtom():"<<name,5)
3791  const bool molnameasformula= this->GetName()==this->GetFormula();
3792 
3793  string thename=name;
3794  if(thename==string(""))
3795  {// This should not be needed, the atom will reset the parameters name when its name is set
3796  char buf[100];
3797  if(pPow!=0) sprintf(buf,"%s_%s_%lu",this->GetName().c_str(),pPow->GetName().c_str(),mvpAtom.size()+1);
3798  else sprintf(buf,"%s_X_%lu",this->GetName().c_str(),mvpAtom.size()+1);
3799  thename=buf;
3800  }
3801  mvpAtom.push_back(new MolAtom(x,y,z,pPow,thename,*this));
3802  mClockAtomPosition.Click();
3803  mClockAtomScattPow.Click();
3804  ++mScattCompList;
3805  {
3806  RefinablePar tmp(thename+"_x",&(mvpAtom.back()->X()),0.,1.,
3807  gpRefParTypeScattConformX,
3808  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
3809  tmp.AssignClock(mClockAtomPosition);
3810  tmp.SetGlobalOptimStep(0.05);
3811  tmp.SetDerivStep(1e-4);
3812  this->AddPar(tmp);
3813  }
3814  {
3815  RefinablePar tmp(thename+"_y",&(mvpAtom.back()->Y()),0.,1.,
3816  gpRefParTypeScattConformY,
3817  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
3818  tmp.AssignClock(mClockAtomPosition);
3819  tmp.SetGlobalOptimStep(0.05);
3820  tmp.SetDerivStep(1e-4);
3821  this->AddPar(tmp);
3822  }
3823  {
3824  RefinablePar tmp(thename+"_z",&(mvpAtom.back()->Z()),0.,1.,
3825  gpRefParTypeScattConformZ,
3826  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
3827  tmp.AssignClock(mClockAtomPosition);
3828  tmp.SetGlobalOptimStep(0.05);
3829  tmp.SetDerivStep(1e-4);
3830  this->AddPar(tmp);
3831  }
3832 
3834 
3835  if(molnameasformula || (this->GetName().size()==0))
3836  this->SetName(this->GetFormula());
3837 
3838  if(updateDisplay) this->UpdateDisplay();
3839  VFN_DEBUG_EXIT("Molecule::AddAtom()",5)
3840 }
3841 
3842 vector<MolAtom*>::iterator Molecule::RemoveAtom(MolAtom &atom, const bool del)
3843 {
3844  VFN_DEBUG_ENTRY("Molecule::RemoveAtom():"<<atom.GetName(),6)
3845  vector<MolAtom*>::iterator pos=find(mvpAtom.begin(),mvpAtom.end(),&atom);
3846  if(pos==mvpAtom.end())
3847  {
3848  throw ObjCrystException("Molecule::RemoveAtom():"+atom.GetName()
3849  +" is not in this Molecule:"+this->GetName());
3850  }
3851  const bool molnameasformula= this->GetName()==this->GetFormula();
3852  // Delete parameters
3853  this->RemovePar(&(this->GetPar(&(atom.X()))));
3854  this->RemovePar(&(this->GetPar(&(atom.Y()))));
3855  this->RemovePar(&(this->GetPar(&(atom.Z()))));
3856  // Delete relevant bonds, bond angles, dihedral angles...
3857  for(vector<MolBond*>::iterator posb=mvpBond.begin();posb!=mvpBond.end();)
3858  {
3859  if( (&atom==&((*posb)->GetAtom1())) || (&atom==&((*posb)->GetAtom2())) )
3860  {
3861  posb=this->RemoveBond(**posb, del);
3862  }
3863  else ++posb;
3864  }
3865  for(vector<MolBondAngle*>::iterator posb=mvpBondAngle.begin();posb!=mvpBondAngle.end();)
3866  {
3867  if( (&atom==&((*posb)->GetAtom1())) || (&atom==&((*posb)->GetAtom2()))
3868  ||(&atom==&((*posb)->GetAtom3())))
3869  {
3870  posb=this->RemoveBondAngle(**posb, del);
3871  }
3872  else ++posb;
3873  }
3874  for(vector<MolDihedralAngle*>::iterator posb=mvpDihedralAngle.begin();
3875  posb!=mvpDihedralAngle.end();)
3876  {
3877  if( (&atom==&((*posb)->GetAtom1())) || (&atom==&((*posb)->GetAtom2()))
3878  ||(&atom==&((*posb)->GetAtom3())) || (&atom==&((*posb)->GetAtom4())))
3879  posb=this->RemoveDihedralAngle(**posb, del);
3880  else ++posb;
3881  }
3882  mClockAtomList.Click();
3884 
3885  if(mpCenterAtom==*pos) mpCenterAtom=0;
3886  if(del) delete *pos;
3887  pos=mvpAtom.erase(pos);
3888  --mScattCompList;
3889 
3890  if(molnameasformula || (this->GetName().size()==0))
3891  this->SetName(this->GetFormula());
3892 
3893  this->UpdateDisplay();
3894  VFN_DEBUG_EXIT("Molecule::RemoveAtom()",6)
3895  return pos;
3896 }
3897 
3898 void Molecule::AddNonFlipAtom(MolAtom &atom)
3899 {
3900  VFN_DEBUG_ENTRY("Molecule::AddNonFlipAtom()",5)
3901  mvNonFlipAtom.push_back(&atom);
3902  //mvNonFlipAtom.push_back(new MolAtom(atom.x,y,z,pPow,thename,*this));
3903 
3904  mClockFlipGroup.Reset();
3905  this->UpdateDisplay();
3906  VFN_DEBUG_EXIT("Molecule::AddNonFlipAtom()",5)
3907 }
3908 void Molecule::removeNonFlipAtom(MolAtom &atom)
3909 {
3910  for(vector<MolAtom*>::iterator pos=mvNonFlipAtom.begin();pos!=mvNonFlipAtom.end();) {
3911  if(atom.GetName().compare((*pos)->GetName())==0) {
3912  pos = mvNonFlipAtom.erase(pos);
3913  break;
3914  } else {
3915  pos++;
3916  }
3917  }
3918 }
3919 vector<MolAtom*> Molecule::getNonFlipAtomList()
3920 {
3921  return mvNonFlipAtom;
3922 }
3923 void Molecule::AddBond(MolAtom &atom1, MolAtom &atom2,
3924  const REAL length, const REAL sigma, const REAL delta,
3925  const REAL bondOrder,
3926  const bool updateDisplay)
3927 {
3928  VFN_DEBUG_ENTRY("Molecule::AddBond()",5)
3929  mvpBond.push_back(new MolBond(atom1,atom2,length,sigma,delta,*this,bondOrder));
3930  this->AddRestraint(mvpBond.back());
3931  mClockBondList.Click();
3932  if(updateDisplay) this->UpdateDisplay();
3933  VFN_DEBUG_EXIT("Molecule::AddBond()",5)
3934 }
3935 
3936 vector<MolBond*>::iterator Molecule::RemoveBond(const MolBond &bond, const bool del)
3937 {
3938  VFN_DEBUG_ENTRY("Molecule::RemoveBond():"<<bond.GetName(),6)
3939  vector<MolBond*>::iterator pos=find(mvpBond.begin(),mvpBond.end(),&bond);
3940  if(pos==mvpBond.end())
3941  {
3942  throw ObjCrystException("Molecule::RemoveBond():"+bond.GetAtom1().GetName()
3943  +"-"+bond.GetAtom2().GetName()
3944  +" is not in this Molecule:"+this->GetName());
3945  }
3946  this->RemoveRestraint(*pos);
3947  mClockBondList.Click();
3948  if(del) delete *pos;
3949  pos= mvpBond.erase(pos);
3950  this->UpdateDisplay();
3951  VFN_DEBUG_EXIT("Molecule::RemoveBond():",6)
3952  return pos;
3953 }
3954 
3955 vector<MolBond*>::const_iterator Molecule::FindBond(const MolAtom &at1,const MolAtom &at2)const
3956 {
3957  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
3958  {
3959  if( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom2())==&at2))
3960  ||((&((*pos)->GetAtom1())==&at2)&&(&((*pos)->GetAtom2())==&at1)))
3961  return pos;
3962  }
3963  return mvpBond.end();
3964 }
3965 vector<MolBond*>::iterator Molecule::FindBond(const MolAtom &at1,const MolAtom &at2)
3966 {
3967  for(vector<MolBond*>::iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
3968  {
3969  if( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom2())==&at2))
3970  ||((&((*pos)->GetAtom1())==&at2)&&(&((*pos)->GetAtom2())==&at1)))
3971  return pos;
3972  }
3973  return mvpBond.end();
3974 }
3975 
3976 void Molecule::AddBondAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3,
3977  const REAL angle, const REAL sigma, const REAL delta,
3978  const bool updateDisplay)
3979 {
3980  VFN_DEBUG_ENTRY("Molecule::AddBondAngle()",5)
3981  mvpBondAngle.push_back(new MolBondAngle(atom1,atom2,atom3,angle,sigma,delta,*this));
3982  this->AddRestraint(mvpBondAngle.back());
3983  mClockBondAngleList.Click();
3984  if(updateDisplay) this->UpdateDisplay();
3985  VFN_DEBUG_EXIT("Molecule::AddBondAngle()",5)
3986 }
3987 
3988 vector<MolBondAngle*>::iterator Molecule::RemoveBondAngle(const MolBondAngle &angle, const bool del)
3989 {
3990  VFN_DEBUG_ENTRY("Molecule::RemoveBondAngle():"<<angle.GetName(),6)
3991  vector<MolBondAngle*>::iterator pos=find(mvpBondAngle.begin(),mvpBondAngle.end(),&angle);
3992  if(pos==mvpBondAngle.end())
3993  {
3994  throw ObjCrystException("Molecule::RemoveBondAngle():"+angle.GetAtom1().GetName()
3995  +"-"+angle.GetAtom2().GetName()+"-"+angle.GetAtom3().GetName()
3996  +" is not in this Molecule:"+this->GetName());
3997  }
3998  this->RemoveRestraint(*pos);
3999  mClockBondAngleList.Click();
4000  if(del) delete *pos;
4001  pos=mvpBondAngle.erase(pos);
4002  this->UpdateDisplay();
4003  VFN_DEBUG_EXIT("Molecule::RemoveBondAngle():",6)
4004  return pos;
4005 }
4006 
4007 vector<MolBondAngle*>::const_iterator Molecule::FindBondAngle(const MolAtom &at1,
4008  const MolAtom &at2,
4009  const MolAtom &at3)const
4010 {
4011  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();
4012  pos!=mvpBondAngle.end();++pos)
4013  {
4014  if( (&((*pos)->GetAtom2())==&at2)
4015  &&( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom3())==&at3))
4016  ||((&((*pos)->GetAtom1())==&at3)&&(&((*pos)->GetAtom3())==&at1))))
4017  return pos;
4018  }
4019  return mvpBondAngle.end();
4020 }
4021 
4023  MolAtom &atom3, MolAtom &atom4,
4024  const REAL angle, const REAL sigma, const REAL delta,
4025  const bool updateDisplay)
4026 {
4027  VFN_DEBUG_ENTRY("Molecule::AddDihedralAngle()",5)
4028  mvpDihedralAngle.push_back(new MolDihedralAngle(atom1,atom2,atom3,atom4,
4029  angle,sigma,delta,*this));
4030  this->AddRestraint(mvpDihedralAngle.back());
4031  mClockDihedralAngleList.Click();
4032  if(updateDisplay) this->UpdateDisplay();
4033  VFN_DEBUG_EXIT("Molecule::AddDihedralAngle()",5)
4034 }
4035 
4036 vector<MolDihedralAngle*>::iterator Molecule::RemoveDihedralAngle(const MolDihedralAngle &angle, const bool del)
4037 {
4038  VFN_DEBUG_ENTRY("Molecule::RemoveDihedralAngle():"<<angle.GetName(),6)
4039  vector<MolDihedralAngle*>::iterator pos=find(mvpDihedralAngle.begin(),
4040  mvpDihedralAngle.end(),&angle);
4041  if(pos==mvpDihedralAngle.end())
4042  {
4043  throw ObjCrystException("Molecule::RemoveDihedralAngle():"+angle.GetAtom1().GetName()
4044  +"-"+angle.GetAtom2().GetName()+"-"+angle.GetAtom3().GetName()
4045  +"-"+angle.GetAtom4().GetName()
4046  +" is not in this Molecule:"+this->GetName());
4047  }
4048  this->RemoveRestraint(*pos);
4049  mClockDihedralAngleList.Click();
4050  if(del) delete *pos;
4051  pos=mvpDihedralAngle.erase(pos);
4052  this->UpdateDisplay();
4053  VFN_DEBUG_ENTRY("Molecule::RemoveDihedralAngle():",6)
4054  return pos;
4055 }
4056 vector<MolDihedralAngle*>::const_iterator Molecule::FindDihedralAngle(const MolAtom &at1,
4057  const MolAtom &at2,
4058  const MolAtom &at3,
4059  const MolAtom &at4)const
4060 {
4061  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();
4062  pos!=mvpDihedralAngle.end();++pos)
4063  {
4064  if( ( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom2())==&at2))
4065  &&((&((*pos)->GetAtom3())==&at3)&&(&((*pos)->GetAtom4())==&at4)))
4066  ||( ((&((*pos)->GetAtom4())==&at1)&&(&((*pos)->GetAtom3())==&at2))
4067  &&((&((*pos)->GetAtom2())==&at3)&&(&((*pos)->GetAtom1())==&at4))))
4068  return pos;
4069  }
4070  return mvpDihedralAngle.end();
4071 }
4072 
4074  const bool updateDisplay)
4075 {
4076  mvRigidGroup.push_back(new RigidGroup(group));
4077  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
4078  char buf[50];
4079  const unsigned int i=mvRigidGroup.size();
4080  RigidGroup* p=this->GetRigidGroupList().back();
4081  p->mX=0;
4082  p->mY=0;
4083  p->mZ=0;
4084  p->mQuat.Q0()=1;
4085  p->mQuat.Q1()=0;
4086  p->mQuat.Q2()=0;
4087  p->mQuat.Q3()=0;
4088  {
4089  sprintf(buf,"RigidGroup%d_x",i);
4090  RefinablePar tmp(buf,&(p->mX),0.,1.,
4091  gpRefParTypeScattConformX,
4092  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
4093  tmp.AssignClock(mClockAtomPosition);
4094  tmp.SetGlobalOptimStep(0.05);
4095  tmp.SetDerivStep(1e-4);
4096  this->AddPar(tmp);
4097  }
4098  {
4099  sprintf(buf,"RigidGroup%d_y",i);
4100  RefinablePar tmp(buf,&(p->mY),0.,1.,
4101  gpRefParTypeScattConformY,
4102  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
4103  tmp.AssignClock(mClockAtomPosition);
4104  tmp.SetGlobalOptimStep(0.05);
4105  tmp.SetDerivStep(1e-4);
4106  this->AddPar(tmp);
4107  }
4108  {
4109  sprintf(buf,"RigidGroup%d_z",i);
4110  RefinablePar tmp(buf,&(p->mZ),0.,1.,
4111  gpRefParTypeScattConformZ,
4112  REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.);
4113  tmp.AssignClock(mClockAtomPosition);
4114  tmp.SetGlobalOptimStep(0.05);
4115  tmp.SetDerivStep(1e-4);
4116  this->AddPar(tmp);
4117  }
4118  {
4119  sprintf(buf,"RigidGroup%d_Q1",i);
4120  RefinablePar tmp(buf,&(p->mQuat.Q1()),-1,1.,
4121  gpRefParTypeScattConform,
4122  REFPAR_DERIV_STEP_ABSOLUTE,true,false,true,false,1.,1.);
4123  tmp.AssignClock(mClockAtomPosition);
4124  tmp.SetGlobalOptimStep(0.01);
4125  tmp.SetDerivStep(1e-4);
4126  this->AddPar(tmp);
4127  }
4128  {
4129  sprintf(buf,"RigidGroup%d_Q2",i);
4130  RefinablePar tmp(buf,&(p->mQuat.Q2()),-1,1.,
4131  gpRefParTypeScattConform,
4132  REFPAR_DERIV_STEP_ABSOLUTE,true,false,true,false,1.,1.);
4133  tmp.AssignClock(mClockAtomPosition);
4134  tmp.SetGlobalOptimStep(0.01);
4135  tmp.SetDerivStep(1e-4);
4136  this->AddPar(tmp);
4137  }
4138  {
4139  sprintf(buf,"RigidGroup%d_Q3",i);
4140  RefinablePar tmp(buf,&(p->mQuat.Q3()),-1,1.,
4141  gpRefParTypeScattConform,
4142  REFPAR_DERIV_STEP_ABSOLUTE,true,false,true,false,1.,1.);
4143  tmp.AssignClock(mClockAtomPosition);
4144  tmp.SetGlobalOptimStep(0.01);
4145  tmp.SetDerivStep(1e-4);
4146  this->AddPar(tmp);
4147  }
4148  #endif
4149  mClockRigidGroup.Click();
4150  if(updateDisplay) this->UpdateDisplay();
4151 }
4152 
4153 vector<RigidGroup*>::iterator Molecule::RemoveRigidGroup(const RigidGroup &g,const bool updateDisplay, const bool del)
4154 {
4155  vector<RigidGroup*>::iterator pos=find(mvRigidGroup.begin(),mvRigidGroup.end(),&g);
4156  if(pos==mvRigidGroup.end()) return pos;
4157  #ifdef RIGID_BODY_STRICT_EXPERIMENTAL
4158  // Remove the refinable parameters (even if del==False - used for python delayed deletion)
4159  // NOTE - this should only be done outside an optimization, since rigid group translationnal
4160  // and rotationnal parameters are resetted at the end of the optimization, and the atomic
4161  // parameters are directly the correct ones (thus deletion of the rigid group does not change
4162  // the final coordinates).
4163  this->RemovePar(&(this->GetPar(&((*pos)->mX))));
4164  this->RemovePar(&(this->GetPar(&((*pos)->mY))));
4165  this->RemovePar(&(this->GetPar(&((*pos)->mZ))));
4166  this->RemovePar(&(this->GetPar(&((*pos)->mQuat.Q1()))));
4167  this->RemovePar(&(this->GetPar(&((*pos)->mQuat.Q2()))));
4168  this->RemovePar(&(this->GetPar(&((*pos)->mQuat.Q3()))));
4169  #endif
4170  if(del) delete *pos;
4171  pos=mvRigidGroup.erase(pos);
4172  if(updateDisplay) this->UpdateDisplay();
4173  return pos;
4174 }
4175 
4176 MolAtom &Molecule::GetAtom(unsigned int i){return *mvpAtom[i];}
4177 
4178 const MolAtom &Molecule::GetAtom(unsigned int i)const{return *mvpAtom[i];}
4179 
4180 MolAtom &Molecule::GetAtom(const string &name){return **(this->FindAtom(name));}
4181 
4182 const MolAtom &Molecule::GetAtom(const string &name)const{return **(this->FindAtom(name));}
4183 
4184 void Molecule::OptimizeConformation(const long nbTrial,const REAL stopCost)
4185 {
4186  VFN_DEBUG_ENTRY("Molecule::OptimizeConformation()",5)
4187  MonteCarloObj globalOptObj(true);
4188  globalOptObj.AddRefinableObj(*this);
4189  globalOptObj.SetAlgorithmParallTempering(ANNEALING_EXPONENTIAL,10000.,1.,
4190  ANNEALING_EXPONENTIAL,10,.1);
4191 
4192  long nb=nbTrial;
4193  mIsSelfOptimizing=true;
4194  globalOptObj.Optimize(nb,false,stopCost);
4195  mIsSelfOptimizing=false;
4196  // Must rebuild Flip & Rotor group, in case they were tested with an absurd conformation
4197  mClockFlipGroup.Reset();
4198  mClockRotorGroup.Reset();
4199  VFN_DEBUG_EXIT("Molecule::OptimizeConformation()",5)
4200 }
4201 
4202 void Molecule::OptimizeConformationSteepestDescent(const REAL maxStep,const unsigned nbStep)
4203 {
4204  //cout<<"LLK="<<this->GetLogLikelihood()<<endl;
4205  for(unsigned i = 0; i < nbStep; ++i)
4206  {
4207  // Calc full gradient
4208  //Calculate & display gradient
4209  map<MolAtom*,XYZ> grad;
4210  for(vector<MolAtom*>::iterator pos=this->GetAtomList().begin();
4211  pos!=this->GetAtomList().end();++pos) grad[*pos]=XYZ(0,0,0);
4212 
4213  // :TODO: remove atoms that are in rigid groups ?
4214  for(vector<MolBond*>::iterator pos=this->GetBondList().begin();
4215  pos!=this->GetBondList().end();++pos) (*pos)->CalcGradient(grad);
4216 
4217  for(vector<MolBondAngle*>::iterator pos=this->GetBondAngleList().begin();
4218  pos!=this->GetBondAngleList().end();++pos) (*pos)->CalcGradient(grad);
4219 
4220  for(vector<MolDihedralAngle*>::iterator pos=this->GetDihedralAngleList().begin();
4221  pos!=this->GetDihedralAngleList().end();++pos) (*pos)->CalcGradient(grad);
4222 
4223  #if 0
4224  // Display gradient - for tests
4225  for(map<MolAtom*,XYZ>::const_iterator pos=grad.begin();pos!=grad.end();++pos)
4226  {
4227  char buf[100];
4228  sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)",
4229  pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z);
4230  cout<<buf<<endl;
4231  }
4232  #endif
4233  // Find maximum absolute value of gradient
4234  REAL f=0;
4235  for(map<MolAtom*,XYZ>::const_iterator pos=grad.begin();pos!=grad.end();++pos)
4236  {
4237  if(abs(pos->second.x)>f) f=abs(pos->second.x);
4238  if(abs(pos->second.y)>f) f=abs(pos->second.y);
4239  if(abs(pos->second.z)>f) f=abs(pos->second.z);
4240  }
4241  if(f>1e-6) f=maxStep/f;
4242  else break;//nothing to optimize ?
4243  // Average derivatives inside rigid groups
4244  //:TODO: still allow rotations of rigid groups ?
4245  //:TODO: Handle case when one atom belongs to several rigid groups...
4246  for(vector<RigidGroup *>::const_iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
4247  {
4248  if((*pos)->size()==0) continue; // Just in case...
4249  REAL dx=0,dy=0,dz=0;
4250  for(set<MolAtom *>::const_iterator at=(*pos)->begin();at!=(*pos)->end();++at)
4251  {
4252  dx+=(*at)->GetX();
4253  dy+=(*at)->GetY();
4254  dz+=(*at)->GetZ();
4255  }
4256  dx/=(*pos)->size();
4257  dy/=(*pos)->size();
4258  dz/=(*pos)->size();
4259  for(set<MolAtom *>::const_iterator at=(*pos)->begin();at!=(*pos)->end();++at)
4260  {
4261  grad[*at].x=dx;
4262  grad[*at].y=dy;
4263  grad[*at].z=dz;
4264  }
4265  }
4266  // Move according to max step to minimize LLK
4267  for(map<MolAtom*,XYZ>::const_iterator pos=grad.begin();pos!=grad.end();++pos)
4268  {
4269  pos->first->SetX(pos->first->GetX()-pos->second.x*f);
4270  pos->first->SetY(pos->first->GetY()-pos->second.y*f);
4271  pos->first->SetZ(pos->first->GetZ()-pos->second.z*f);
4272  }
4273  //this->RestraintStatus(cout);
4274  //cout<<"LLK="<<this->GetLogLikelihood()<<endl;
4275  }
4276 }
4277 
4278 void Molecule::MolecularDynamicsEvolve(map<MolAtom*,XYZ> &v0,const unsigned nbStep,const REAL dt,
4279  const vector<MolBond*> &vb,const vector<MolBondAngle*> &va,
4280  const vector<MolDihedralAngle*> &vd,
4281  map<RigidGroup*,std::pair<XYZ,XYZ> > &vr, REAL nrj0)
4282 {
4283  const vector<MolBond*> *pvb=&vb;
4284  const vector<MolBondAngle*> *pva=&va;
4285  const vector<MolDihedralAngle*> *pvd=&vd;
4286  map<RigidGroup*,std::pair<XYZ,XYZ> > *pvr=&vr;
4287  if((pvb->size()==0)&&(pva->size()==0)&&(pvd->size()==0))
4288  {
4289  pvb=&(this->GetBondList());
4290  pva=&(this->GetBondAngleList());
4291  pvd=&(this->GetDihedralAngleList());
4292  for(vector<RigidGroup *>::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos)
4293  (*pvr)[*pos]=make_pair(XYZ(0,0,0),XYZ(0,0,0));
4294  }
4295  const REAL m=500;// mass
4296  const REAL im=1./m;
4297 
4298  // Try to keep total energy constant
4299  REAL e_v,e_k,v_r=1.0;
4300  for(unsigned i = 0; i < nbStep; ++i)
4301  {
4302  // Calc full gradient
4303  map<MolAtom*,XYZ> grad;
4304  for(map<MolAtom*,XYZ>::iterator pos=v0.begin();pos!=v0.end();++pos) grad[pos->first]=XYZ(0,0,0);
4305 
4306  // :TODO: handle rigid groups ?
4307  e_v=0;
4308  for(vector<MolBond*>::const_iterator pos=pvb->begin();pos!=pvb->end();++pos)
4309  {
4310  (*pos)->CalcGradient(grad);
4311  e_v+=(*pos)->GetLogLikelihood(false,false);
4312  }
4313 
4314  for(vector<MolBondAngle*>::const_iterator pos=pva->begin();pos!=pva->end();++pos)
4315  {
4316  (*pos)->CalcGradient(grad);
4317  e_v+=(*pos)->GetLogLikelihood(false,false);
4318  }
4319 
4320  for(vector<MolDihedralAngle*>::const_iterator pos=pvd->begin();pos!=pvd->end();++pos)
4321  {
4322  (*pos)->CalcGradient(grad);
4323  e_v+=(*pos)->GetLogLikelihood(false,false);
4324  }
4325 
4326  //kinetic energy
4327  e_k=0;
4328  for(map<MolAtom*,XYZ>::const_iterator pos=v0.begin();pos!=v0.end();++pos)
4329  e_k += 0.5*m*(pos->second.x*pos->second.x + pos->second.y*pos->second.y + pos->second.z*pos->second.z);
4330 
4331  if(nrj0==0) nrj0=e_k+e_v;
4332  else
4333  {
4334  // Apply a coefficient to the speed to keep the overall energy constant
4335  const REAL de=e_k+e_v-nrj0;
4336  if(de<e_k) v_r=sqrt((e_k-de)/e_k);
4337  else v_r=0.0;
4338  }
4339 
4340  #if 0
4341  char buf[100];
4342  sprintf(buf,"(i) LLK + Ek = %10.3f + %10.3f =%10.3f (nrj0=%10.3f)",e_v,e_k,e_v+e_k,nrj0);
4343  cout<<buf<<endl;
4344 
4345  // Display gradient & speed - for tests
4346  for(map<MolAtom*,XYZ>::iterator pos=v0.begin();pos!=v0.end();++pos)
4347  {
4348  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)",
4349  pos->first->GetName().c_str(),
4350  pos->first->GetX(),pos->first->GetY(),pos->first->GetZ(),
4351  v0[*pos].x ,v0[*pos].y ,v0[*pos].z,
4352  -grad[*pos].x*im,-grad[*pos].y*im,-grad[*pos].z*im);
4353  //cout<<buf<<endl;
4354  }
4355  //cout<<endl<<endl;
4356  #endif
4357  // Move according to max step to minimize LLK
4358  for(map<MolAtom*,XYZ>::const_iterator pos=v0.begin();pos!=v0.end();++pos)
4359  {
4360  const XYZ *pa=&(grad[pos->first]);
4361  pos->first->SetX(pos->first->GetX()+pos->second.x*dt*v_r-0.5*im*dt*dt*pa->x);
4362  pos->first->SetY(pos->first->GetY()+pos->second.y*dt*v_r-0.5*im*dt*dt*pa->y);
4363  pos->first->SetZ(pos->first->GetZ()+pos->second.z*dt*v_r-0.5*im*dt*dt*pa->z);
4364  }
4365  // Compute new speed
4366  for(map<MolAtom*,XYZ>::iterator pos=v0.begin();pos!=v0.end();++pos)
4367  {
4368  const XYZ *pa=&(grad[pos->first]);
4369  pos->second.x = v_r*pos->second.x - pa->x*dt*im;
4370  pos->second.y = v_r*pos->second.y - pa->y*dt*im;
4371  pos->second.z = v_r*pos->second.z - pa->z*dt*im;
4372  }
4373  }
4374 }
4375 
4376 const vector<MolAtom*>& Molecule::GetAtomList()const{return mvpAtom;}
4377 const vector<MolBond*>& Molecule::GetBondList()const{return mvpBond;}
4378 const vector<MolBondAngle*>& Molecule::GetBondAngleList()const{return mvpBondAngle;}
4379 const vector<MolDihedralAngle*>& Molecule::GetDihedralAngleList()const{return mvpDihedralAngle;}
4380 
4381 vector<MolAtom*>& Molecule::GetAtomList(){return mvpAtom;}
4382 vector<MolBond*>& Molecule::GetBondList(){return mvpBond;}
4383 vector<MolBondAngle*>& Molecule::GetBondAngleList(){return mvpBondAngle;}
4384 vector<MolDihedralAngle*>& Molecule::GetDihedralAngleList(){return mvpDihedralAngle;}
4385 
4386 list<StretchModeBondLength>& Molecule::GetStretchModeBondLengthList(){return mvStretchModeBondLength;}
4387 list<StretchModeBondAngle>& Molecule::GetStretchModeBondAngleList(){return mvStretchModeBondAngle;}
4388 list<StretchModeTorsion>& Molecule::GetStretchModeTorsionList(){return mvStretchModeTorsion;}
4389 
4390 const list<StretchModeBondLength>& Molecule::GetStretchModeBondLengthList()const{return mvStretchModeBondLength;}
4391 const list<StretchModeBondAngle>& Molecule::GetStretchModeBondAngleList()const{return mvStretchModeBondAngle;}
4392 const list<StretchModeTorsion>& Molecule::GetStretchModeTorsionList()const{return mvStretchModeTorsion;}
4393 
4394 const std::vector<RigidGroup*>& Molecule::GetRigidGroupList()const{return mvRigidGroup;}
4395 std::vector<RigidGroup*>& Molecule::GetRigidGroupList() {return mvRigidGroup;}
4396 
4397 void Molecule::RotateAtomGroup(const MolAtom &at1,const MolAtom &at2,
4398  const set<MolAtom *> &atoms, const REAL angle,
4399  const bool keepCenter)
4400 {
4401  const REAL vx=at2.X()-at1.X();
4402  const REAL vy=at2.Y()-at1.Y();
4403  const REAL vz=at2.Z()-at1.Z();
4404  this->RotateAtomGroup(at1,vx,vy,vz,atoms,angle,keepCenter);
4405 }
4406 void Molecule::RotateAtomGroup(const MolAtom &at,const REAL vx,const REAL vy,const REAL vz,
4407  const set<MolAtom *> &atoms, const REAL angle,
4408  const bool keepCenter)
4409 {
4410  TAU_PROFILE("Molecule::RotateAtomGroup(MolAtom&,vx,vy,vz,...)","void (...)",TAU_DEFAULT);
4411  if(atoms.size()==0) return;
4412  const REAL x0=at.X();
4413  const REAL y0=at.Y();
4414  const REAL z0=at.Z();
4415  // :KLUDGE: ? Refuse to do anything if vector is not well defined
4416  if((fabs(vx)+fabs(vy)+fabs(vz))<1e-6) return;
4417  REAL dx=0.,dy=0.,dz=0.;
4418  bool keepc=keepCenter;
4419  if(keepc)
4420  if( (this->GetPar(mXYZ.data() ).IsFixed())
4421  ||(this->GetPar(mXYZ.data()+1).IsFixed())
4422  ||(this->GetPar(mXYZ.data()+2).IsFixed())) keepc=false;
4423  #if 0
4424  const REAL ca=cos(angle),sa=sin(angle);
4425  const REAL ca1=1-ca;
4426  const REAL vnorm=1/sqrt(vx*vx+vy*vy+vz*vz);
4427  const REAL ux=vx*vnorm,uy=vy*vnorm,uz=vz*vnorm;
4428  const REAL m00=ca+ux*ux*ca1;// See http://en.wikipedia.org/wiki/Rotation_matrix
4429  const REAL m01=ux*uy*ca1-uz*sa;
4430  const REAL m02=ux*uz*ca1+uy*sa;
4431  const REAL m10=uy*ux*ca1+uz*sa; // :TODO: Check formulas !
4432  const REAL m11=ca+uy*uy*ca1;
4433  const REAL m12=uy*uz*ca1-ux*sa;
4434  const REAL m20=uz*ux*ca1-uy*sa;
4435  const REAL m21=uz*uy*ca1+ux*sa;
4436  const REAL m22=ca+uz*uz*ca1;
4437  for(set<MolAtom *>::const_iterator pos=atoms.begin();pos!=atoms.end();++pos)
4438  {
4439  if(keepc)
4440  {
4441  dx -= (*pos)->X();
4442  dy -= (*pos)->Y();
4443  dz -= (*pos)->Z();
4444  }
4445  const REAL x=(*pos)->X() - x0;
4446  const REAL y=(*pos)->Y() - y0;
4447  const REAL z=(*pos)->Z() - z0;
4448 
4449  (*pos)->X() = m00*x+m01*y+m02*z+x0;
4450  (*pos)->Y() = m10*x+m11*y+m12*z+y0;
4451  (*pos)->Z() = m20*x+m21*y+m22*z+z0;
4452  if(keepc)
4453  {
4454  dx += (*pos)->X();
4455  dy += (*pos)->Y();
4456  dz += (*pos)->Z();
4457  }
4458  }
4459  #else
4460  const Quaternion quat=Quaternion::RotationQuaternion(angle,vx,vy,vz);
4461  for(set<MolAtom *>::const_iterator pos=atoms.begin();pos!=atoms.end();++pos)
4462  {
4463  if(keepc)
4464  {
4465  dx -= (*pos)->X();
4466  dy -= (*pos)->Y();
4467  dz -= (*pos)->Z();
4468  }
4469  (*pos)->X() -= x0;
4470  (*pos)->Y() -= y0;
4471  (*pos)->Z() -= z0;
4472  quat.RotateVector((*pos)->X(),(*pos)->Y(),(*pos)->Z());
4473  (*pos)->X() += x0;
4474  (*pos)->Y() += y0;
4475  (*pos)->Z() += z0;
4476  if(keepc)
4477  {
4478  dx += (*pos)->X();
4479  dy += (*pos)->Y();
4480  dz += (*pos)->Z();
4481  }
4482  }
4483  #endif
4484  // (dx,dy,dz) = vector of the translation of the center of the molecule due to the rotation
4485  if(keepc)
4486  {
4487  dx /= (REAL)(this->GetNbComponent());
4488  dy /= (REAL)(this->GetNbComponent());
4489  dz /= (REAL)(this->GetNbComponent());
4490  mQuat.RotateVector(dx,dy,dz);
4491  this->GetCrystal().OrthonormalToFractionalCoords(dx,dy,dz);
4492  mXYZ(0) += dx;
4493  mXYZ(1) += dy;
4494  mXYZ(2) += dz;
4495  }
4496  mClockAtomPosition.Click();
4498 }
4499 void Molecule::TranslateAtomGroup(const set<MolAtom *> &atoms,
4500  const REAL dx,const REAL dy,const REAL dz,
4501  const bool keepCenter)
4502 {
4503  for(set<MolAtom *>::const_iterator pos=atoms.begin();pos!=atoms.end();++pos)
4504  {
4505  (*pos)->X() += dx;
4506  (*pos)->Y() += dy;
4507  (*pos)->Z() += dz;
4508  }
4509  bool keepc=keepCenter;
4510  if(keepc)
4511  if( (this->GetPar(mXYZ.data() ).IsFixed())
4512  ||(this->GetPar(mXYZ.data()+1).IsFixed())
4513  ||(this->GetPar(mXYZ.data()+2).IsFixed())) keepc=false;
4514  if(keepc)
4515  {
4516  const REAL r= (REAL)(atoms.size())/(REAL)(this->GetNbComponent());
4517  REAL dxc=dx*r,dyc=dy*r,dzc=dz*r;
4518  this->GetCrystal().OrthonormalToFractionalCoords(dxc,dyc,dzc);
4519  mXYZ(0) += dxc;
4520  mXYZ(1) += dyc;
4521  mXYZ(2) += dzc;
4522  }
4523  mClockAtomPosition.Click();
4525 }
4526 void Molecule::RestraintExport(ostream &os)const
4527 {
4528  VFN_DEBUG_ENTRY("Molecule::RestraintExport()",5)
4529  os<<"BondName, IdealLength, Length, log(likelihood)"<<endl;
4530  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
4531  os <<(*pos)->GetName()
4532  <<", "<<(*pos)->GetLength0()
4533  <<", "<<(*pos)->GetLength()
4534  <<", "<<(*pos)->GetLogLikelihood()<<endl;
4535  os<<"BondAngle, IdealAngle, Angle, log(likelihood)"<<endl;
4536  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();
4537  pos!=mvpBondAngle.end();++pos)
4538  os <<(*pos)->GetName()
4539  <<", "<<(*pos)->Angle0()*180/M_PI
4540  <<", "<<(*pos)->GetAngle()*180/M_PI
4541  <<", "<<(*pos)->GetLogLikelihood()<<endl;
4542  os<<"DihedralAngle, IdealAngle, Angle, log(likelihood)"<<endl;
4543  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();
4544  pos!=mvpDihedralAngle.end();++pos)
4545  os <<(*pos)->GetName()
4546  <<", "<<(*pos)->Angle0()*180/M_PI
4547  <<", "<<(*pos)->GetAngle()*180/M_PI
4548  <<", "<<(*pos)->GetLogLikelihood()<<endl;
4549  VFN_DEBUG_EXIT("Molecule::RestraintExport()",5)
4550 }
4551 void Molecule::RestraintStatus(ostream &os)const
4552 {
4553  VFN_DEBUG_ENTRY("Molecule::RestraintStatus()",5)
4554  for(vector<MolBond*>::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
4555  cout <<"Bond "<<(*pos)->GetName()
4556  <<", IdealLength="<<(*pos)->GetLength0()
4557  <<", Length="<<(*pos)->GetLength()
4558  <<", log(likelihood)="<<(*pos)->GetLogLikelihood()<<endl;
4559  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();
4560  pos!=mvpBondAngle.end();++pos)
4561  cout <<"Bond Angle "<<(*pos)->GetName()
4562  <<", IdealAngle="<<(*pos)->Angle0()*180/M_PI
4563  <<", Angle="<<(*pos)->GetAngle()*180/M_PI
4564  <<", log(likelihood)="<<(*pos)->GetLogLikelihood()<<endl;
4565  for(vector<MolDihedralAngle*>::const_iterator pos=mvpDihedralAngle.begin();
4566  pos!=mvpDihedralAngle.end();++pos)
4567  cout <<"Dihedral Angle "<<(*pos)->GetName()
4568  <<", IdealAngle="<<(*pos)->Angle0()*180/M_PI
4569  <<", Angle="<<(*pos)->GetAngle()*180/M_PI
4570  <<", log(likelihood)="<<(*pos)->GetLogLikelihood()<<endl;
4571  VFN_DEBUG_EXIT("Molecule::RestraintStatus()",5)
4572 }
4573 
4574 const map<MolAtom *,set<MolAtom *> > &Molecule::GetConnectivityTable()
4575 {
4576  this->BuildConnectivityTable();
4577  return mConnectivityTable;
4578 }
4579 
4581 const RefinableObjClock& Molecule::GetBondListClock()const{return mClockBondList;}
4582 
4584 const RefinableObjClock& Molecule::GetAtomPositionClock()const{return mClockAtomPosition;}
4585 
4587 const RefinableObjClock& Molecule::GetRigidGroupClock()const{return mClockRigidGroup;}
4588 
4590 {
4591  this->BuildConnectivityTable();
4592  for(vector<MolBond*>::iterator bond=mvpBond.begin();bond!=mvpBond.end();++bond)
4593  {
4594  MolAtom* at2=&((*bond)->GetAtom1());
4595  MolAtom* at3=&((*bond)->GetAtom2());
4596  for(set<MolAtom *>::const_iterator c2=mConnectivityTable[at2].begin();
4597  c2!=mConnectivityTable[at2].end();++c2)
4598  {
4599  //MolAtom* at1=mvpAtom[*c2];
4600  if(*c2==at3) continue;
4601  if(GetBondAngle(**c2,*at2,*at3)<(10 *DEG2RAD)) continue;
4602  if(GetBondAngle(**c2,*at2,*at3)>(180*DEG2RAD)) continue;
4603  for(set<MolAtom*>::const_iterator c3=mConnectivityTable[at3].begin();
4604  c3!=mConnectivityTable[at3].end();++c3)
4605  {
4606  //MolAtom* at4=mvpAtom[*c3];
4607  if((*c3==at2)||(*c3==*c2)) continue;
4608  if(GetBondAngle(*at2,*at3,**c3)<(10 *DEG2RAD)) continue;
4609  if(GetBondAngle(*at2,*at3,**c3)>(180*DEG2RAD)) continue;
4610  if(this->FindDihedralAngle(**c2,*at2,*at3,**c3)==mvpDihedralAngle.end())
4611  {
4612  const REAL dihed=GetDihedralAngle(**c2,*at2,*at3,**c3);
4613  this->AddDihedralAngle(**c2,*at2,*at3,**c3,dihed,.01,.05,false);
4614  }
4615  }
4616  }
4617  }
4618  this->UpdateDisplay();
4619 }
4620 #if 0
4621 
4624 static const REAL svGaussianIntX[51]
4625  ={0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2,
4626  1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3,
4627  2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2, 3.3, 3.4,
4628  3.5, 3.6, 3.7, 3.8, 3.9, 4. , 4.1, 4.2, 4.3, 4.4, 4.5,
4629  4.6, 4.7, 4.8, 4.9, 5. };
4633 static const REAL svGaussianIntY[51]
4634  ={0.00000000e+00, 1.00285768e-01, 2.02498389e-01, 3.08782899e-01,
4635  4.21537858e-01, 5.43577677e-01, 6.78339751e-01, 8.30161516e-01,
4636  1.00466359e+00, 1.20929269e+00, 1.45410564e+00, 1.75292008e+00,
4637  2.12502806e+00, 2.59778353e+00, 3.21056320e+00, 4.02091257e+00,
4638  5.11421527e+00, 6.61911896e+00, 8.73249677e+00, 1.17604260e+01,
4639  1.61864569e+01, 2.27870547e+01, 3.28297946e+01, 4.84189023e+01,
4640  7.31071567e+01, 1.12996748e+02, 1.78751757e+02, 2.89337246e+02,
4641  4.79080996e+02, 8.11232960e+02, 1.40443983e+03, 2.48531490e+03,
4642  4.49461494e+03, 8.30539633e+03, 1.56790580e+04, 3.02354014e+04,
4643  5.95525189e+04, 1.19793234e+05, 2.46080284e+05, 5.16182008e+05,
4644  1.10556243e+06, 2.41765307e+06, 5.39775929e+06, 1.23033271e+07,
4645  2.86288375e+07, 6.80050408e+07, 1.64899866e+08, 4.08157783e+08,
4646  1.03122228e+09, 2.65938808e+09, 7.00012860e+09};
4650 static const CubicSpline sInvGaussianInt(svGaussianIntY,svGaussianIntX,51);
4651 
4652 REAL FlatGaussianProba(const REAL x, const REAL sigma, const REAL delta)
4653 {
4654  if(abs(x)<delta) return 1.0;
4655  const REAL z=(abs(x)-delta)/sigma;
4656  return exp(-z*z);
4657 }
4658 
4659 REAL FlatGaussianIntegral(const REAL x1,const REAL x2, const REAL sigma, const REAL delta)
4660 {
4661  static const REAL SPI2=0.88622692545275794;//sqrt(pi)/2
4662  if((x1<=-delta)&&(x2<=-delta)) return SPI2*sigma*(erf((x2+delta)/sigma)-erf((x1+delta)/sigma));
4663  if((x1<=-delta)&&(x2<= delta)) return (x2+delta)-SPI2*sigma*erf((x1+delta)/sigma);
4664  if(x1<=-delta) return 2*delta+SPI2*sigma*(erf((x2-delta)/sigma)-erf((x1+delta)/sigma));
4665  if((x1<= delta)&&(x2<= delta)) return x2-x1;
4666  if(x1<= delta) return SPI2*sigma*erf((x2-delta)/sigma)+(delta-x1);
4667  return SPI2*sigma*(erf((x2-delta)/sigma)-erf((x1-delta)/sigma));
4668 }
4669 #endif
4670 REAL FlatLorentzianProba(const REAL x, const REAL sigma, const REAL delta)
4671 {
4672  if(abs(x)<delta) return 1.0;
4673  const REAL z=(abs(x)-delta)/sigma;
4674  return 1/(1+z*z);
4675 }
4676 
4677 REAL FlatLorentzianIntegral(const REAL x1,const REAL x2, const REAL sigma, const REAL delta)
4678 {
4679  if((x1<=-delta)&&(x2<=-delta)) return atan((x2+delta)/sigma)-atan((x1+delta)/sigma);
4680  if((x1<=-delta)&&(x2<= delta)) return (x2+delta)-atan((x1+delta)/sigma);
4681  if(x1<=-delta) return 2*delta+atan((x2-delta)/sigma)-atan((x1+delta)/sigma);
4682  if((x1<= delta)&&(x2<= delta)) return x2-x1;
4683  if(x1<= delta) return atan((x2-delta)/sigma)+(delta-x1);
4684  return atan((x2-delta)/sigma)-atan((x1-delta)/sigma);
4685 }
4686 
4687 ofstream f;
4688 
4695 REAL LorentzianBiasedRandomMove(const REAL x0,const REAL sigma,const REAL delta,const REAL amplitude)
4696 {
4697  //static const REAL SPI2=0.88622692545275794;//sqrt(pi)/2
4698  REAL r=(REAL)rand()/(REAL)RAND_MAX;
4699  if(sigma<1e-6)
4700  {
4701  REAL x=x0+amplitude*(2*r-1.0);
4702  if(x> delta)x= delta;
4703  if(x<-delta)x=-delta;
4704  return x;
4705  }
4706  // Compute xmin and xmax around x0 so that:
4707  // (x0-xmin)/(xmax-x0)=Integral[xmin->x0](P(x)dx)/Integral[x0->xmax](P(x)dx)
4708  REAL xmin;
4709  REAL xmax;
4710  #if 1
4711  {
4712  REAL Pmax,Pmin;
4713  xmin=x0-amplitude;
4714  xmax=x0+amplitude;
4715  Pmin=FlatLorentzianProba((x0+xmin)/2,sigma,delta);
4716  Pmax=FlatLorentzianProba((x0+xmax)/2,sigma,delta);
4717  //Pmin=FlatLorentzianIntegral(xmin,x0,sigma,delta);
4718  //Pmax=FlatLorentzianIntegral(x0,xmax,sigma,delta);
4719  if(Pmin>Pmax)
4720  {
4721  for(int i=0;i<5;i++)
4722  {
4723  const REAL r=Pmax/Pmin;
4724  xmax=x0+r*amplitude;
4725  Pmax=FlatLorentzianProba((x0+xmax)/2,sigma,delta);
4726  //Pmax=FlatLorentzianIntegral(x0,xmax,sigma,delta);
4727  }
4728  }
4729  else
4730  {
4731  for(int i=0;i<5;i++)
4732  {
4733  const REAL r=Pmin/Pmax;
4734  xmin=x0-r*amplitude;
4735  Pmin=FlatLorentzianProba((x0+xmin)/2,sigma,delta);
4736  //Pmin=FlatLorentzianIntegral(xmin,x0,sigma,delta);
4737  }
4738  }
4739  }
4740  #else
4741  if(abs(x0)<=delta)
4742  {
4743  xmin=x0-amplitude;
4744  xmax=x0+amplitude;
4745  }
4746  else
4747  {
4748  REAL d=(abs(x0)-delta)/sigma;
4749  d=2*d*exp(-d*d);
4750  d=(1-amplitude*d/2)/(1+amplitude*d/2);//d<1
4751  if(x0>0)
4752  {
4753  xmin=x0-amplitude*2/(1+d);
4754  xmax=x0+amplitude*2*d/(1+d);
4755  }
4756  else
4757  {
4758  xmax=x0+amplitude*2/(1+d);
4759  xmin=x0-amplitude*2*d/(1+d);
4760  }
4761  }
4762  #endif
4763  //xmin=x0-amplitude;
4764  //xmax=x0+amplitude;
4765  //Now get the biased move...
4766  if(xmax<=-delta)
4767  {
4768  REAL ymin=(abs(xmin)-delta)/sigma;
4769  ymin=atan(ymin);
4770  REAL ymax=(abs(xmax)-delta)/sigma;
4771  ymax=atan(ymax);
4772  const REAL y=ymin+(ymax-ymin)*r;
4773  return -tan(y)*sigma-delta;
4774  }
4775  if(xmin<=-delta)
4776  {
4777  if(xmax<=delta)
4778  {
4779  //probability of being in [xmin;-delta] rather than [-delta;xmax]
4780  REAL p0=atan((abs(xmin)-delta)/sigma)*sigma;
4781  REAL p1=xmax+delta;
4782  const REAL n=p0+p1;
4783  if(r<p0/n)
4784  {
4785  REAL ymin=(abs(xmin)-delta)/sigma;
4786  ymin=atan(ymin);
4787  const REAL y=ymin*(REAL)rand()/(REAL)RAND_MAX;
4788  return -delta-tan(y)*sigma;
4789  }
4790  else
4791  {
4792  return -delta+(REAL)rand()/(REAL)RAND_MAX*(xmax+delta);
4793  }
4794  }
4795  else //xmax>delta && xmin <= -delta
4796  {
4797  REAL p0=atan((abs(xmin)-delta)/sigma)*sigma;//probability of being in [xmin;-delta]
4798  REAL p1=2*delta;//probability of being in [-delta;delta]
4799  REAL p2=atan((xmax-delta)/sigma)*sigma;//probability of being in [delta;xmax]
4800  const REAL n=p0+p1+p2;
4801  if(r<(p0/n))
4802  {
4803  REAL ymin=(abs(xmin)-delta)/sigma;
4804  ymin=atan(ymin);//exp(ymin*ymin);
4805  const REAL y=ymin*(REAL)rand()/(REAL)RAND_MAX;
4806  const REAL x=-delta-tan(y)*sigma;
4807  return x;
4808  }
4809  if(r<(p0+p1)/n)
4810  {
4811  const REAL x=-delta+(REAL)rand()/(REAL)RAND_MAX*2*delta;
4812  return x;
4813  }
4814 
4815  REAL ymax=(xmax-delta)/sigma;
4816  ymax=atan(ymax);
4817  const REAL y=ymax*(REAL)rand()/(REAL)RAND_MAX;
4818  const REAL x=delta+tan(y)*sigma;
4819  return x;
4820  }
4821  }
4822  if(xmin<delta)
4823  {
4824  if(xmax<delta)
4825  {
4826  return xmin+r*(xmax-xmin);
4827  }
4828 
4829  const REAL p0=delta-xmin;//relative probability of being in [xmin;delta]
4830  const REAL p1=atan((xmax-delta)/sigma)*sigma;// proba in[delta;xmax]
4831  if(r<(p0/(p0+p1)))
4832  {
4833  return xmin+(REAL)rand()/(REAL)RAND_MAX*(delta-xmin);
4834  }
4835 
4836  REAL ymax=(xmax-delta)/sigma;
4837  ymax=atan(ymax);
4838  const REAL y=ymax*(REAL)rand()/(REAL)RAND_MAX;
4839  return delta+tan(y)*sigma;
4840  }
4841  //xmin>delta
4842  REAL ymin=(xmin-delta)/sigma;
4843  ymin=atan(ymin);
4844  REAL ymax=(xmax-delta)/sigma;
4845  ymax=atan(ymax);
4846  const REAL y=ymin+(ymax-ymin)*r;
4847  return tan(y)*sigma+delta;
4848 }
4849 
4850 void TestLorentzianBiasedRandomMove()
4851 {
4852  srand(time(NULL));
4853  REAL x=0,sigma=0.1,delta=0.5,amplitude=0.05;
4854  f.open("test.dat");
4855  for(long i=0;i<400000;i++)
4856  {
4857  f<<x<<endl;
4858  x=LorentzianBiasedRandomMove(x,sigma,delta,amplitude);
4859  }
4860  f.close();
4861  exit(0);
4862  //#Histogram in Python
4863  //from scipy import *
4864  //
4865  //def histogram(y,n=100):
4866  // ymin=min(y)
4867  // ymax=max(y)
4868  // step=(ymax-ymin)/n
4869  // hx=arange(ymin,ymax+step,step)
4870  // hy=arange(ymin,ymax+step,step)
4871  // for i in xrange(n-1):
4872  // hy[i]=sum((y>hx[i])*(y<(hx[i]+step)))
4873  // return hx,hy
4874  //
4875  //
4876  //f=open("test.dat",'r')
4877  //ll=f.readlines()
4878  //f.close()
4879  //y=zeros(len(ll),Float)
4880  //for i in xrange(len(ll)):
4881  // y[i]=float(ll[i])
4882  //
4883  //hx,hy=histogram(y)
4884  //gplt.plot(hx,hy)
4885 }
4886 
4887 REAL Molecule::BondLengthRandomChange(const StretchModeBondLength& mode, const REAL amplitude,
4888  const bool respectRestraint)
4889 {
4890  REAL dx=mode.mpAtom1->GetX()-mode.mpAtom0->GetX();
4891  REAL dy=mode.mpAtom1->GetY()-mode.mpAtom0->GetY();
4892  REAL dz=mode.mpAtom1->GetZ()-mode.mpAtom0->GetZ();
4893  const REAL l=sqrt(dx*dx+dy*dy+dz*dz+1e-7);
4894  REAL change=0.0;
4895  if(l<1e-6) return change;// :KLUDGE:
4896  if(respectRestraint && mode.mpBond!=0)
4897  {
4898  const REAL d0=l-mode.mpBond->GetLength0();
4899  const REAL sigma=mode.mpBond->GetLengthSigma();
4900  const REAL delta=mode.mpBond->GetLengthDelta();
4901  const REAL max=delta+sigma*5.0;
4902  if(sigma<1e-6)
4903  {
4904  REAL d1=d0+(REAL)(2*rand()-RAND_MAX)/(REAL)RAND_MAX*amplitude*0.1;
4905  if(d1> delta)d1= delta;
4906  if(d1<-delta)d1=-delta;
4907  change=d1-d0;
4908  }
4909  else change=LorentzianBiasedRandomMove(d0,sigma,delta,amplitude*0.1)-d0;
4910  if((d0+change)>max) change=max-d0;
4911  else if((d0+change)<(-max)) change=-max-d0;
4912  #if 0
4913  if(rand()%10000==0)
4914  {
4915  cout<<"BOND LENGTH change("<<change<<"):"
4916  <<mode.mpAtom0->GetName()<<"-"
4917  <<mode.mpAtom1->GetName()
4918  <<"(Restraint="<<l-d0<<"s"<<sigma<<"d"<<delta<<"):"
4919  <<l<<"->"<<l+change<<endl;
4920  }
4921  #endif
4922  }
4923  else change=(2.*(REAL)rand()-(REAL)RAND_MAX)/(REAL)RAND_MAX*amplitude*0.1;
4924  dx*=change/l;
4925  dy*=change/l;
4926  dz*=change/l;
4927  this->TranslateAtomGroup(mode.mvTranslatedAtomList,dx,dy,dz,true);
4928  return change;
4929 }
4930 
4931 REAL Molecule::BondAngleRandomChange(const StretchModeBondAngle& mode, const REAL amplitude,
4932  const bool respectRestraint)
4933 {
4934  REAL dx10=mode.mpAtom0->GetX()-mode.mpAtom1->GetX();
4935  REAL dy10=mode.mpAtom0->GetY()-mode.mpAtom1->GetY();
4936  REAL dz10=mode.mpAtom0->GetZ()-mode.mpAtom1->GetZ();
4937  REAL dx12=mode.mpAtom2->GetX()-mode.mpAtom1->GetX();
4938  REAL dy12=mode.mpAtom2->GetY()-mode.mpAtom1->GetY();
4939  REAL dz12=mode.mpAtom2->GetZ()-mode.mpAtom1->GetZ();
4940 
4941  const REAL vx=dy10*dz12-dz10*dy12;
4942  const REAL vy=dz10*dx12-dx10*dz12;
4943  const REAL vz=dx10*dy12-dy10*dx12;
4944 
4945  REAL change=0.0;
4946  if((abs(vx)+abs(vy)+abs(vz))<1e-6) return change;// :KLUDGE:
4947  REAL angle0;
4948  if(respectRestraint && mode.mpBondAngle!=0)
4949  {
4950  const REAL norm= sqrt( (dx10*dx10+dy10*dy10+dz10*dz10)*(dx12*dx12+dy12*dy12+dz12*dz12)+1e-6);
4951  angle0=(dx10*dx12+dy10*dy12+dz10*dz12)/norm;
4952  if(angle0>=1) angle0=0;
4953  else
4954  {
4955  if(angle0<=-1) angle0=M_PI;
4956  else angle0= acos(angle0);
4957  }
4958 
4959  const REAL a0=angle0-mode.mpBondAngle->GetAngle0();
4960  const REAL sigma=mode.mpBondAngle->GetAngleSigma();
4961  const REAL delta=mode.mpBondAngle->GetAngleDelta();
4962  if(sigma<1e-6)
4963  {
4964  REAL a1=a0+(REAL)(2*rand()-RAND_MAX)/(REAL)RAND_MAX*amplitude*mode.mBaseAmplitude;
4965  if(a1> delta)a1= delta;
4966  if(a1<-delta)a1=-delta;
4967  change=a1-a0;
4968  }
4969  else change=LorentzianBiasedRandomMove(a0,sigma,delta,amplitude*mode.mBaseAmplitude)-a0;
4970  if((a0+change)>(delta+sigma*5.0)) change= delta+sigma*5.0-a0;
4971  else if((a0+change)<(-delta-sigma*5.0)) change=-delta-sigma*5.0-a0;
4972  #if 0
4973  if(rand()%1==0)
4974  {
4975  cout<<"ANGLE change("<<change*RAD2DEG<<"):"
4976  <<mode.mpAtom0->GetName()<<"-"
4977  <<mode.mpAtom1->GetName()<<"-"
4978  <<mode.mpAtom2->GetName()
4979  <<"(Restraint="<<(angle0-a0)*RAD2DEG<<"s"<<sigma*RAD2DEG<<"d"<<delta*RAD2DEG<<"):"
4980  <<angle0*RAD2DEG<<"->"<<(angle0+change)*RAD2DEG<<endl;
4981  }
4982  #endif
4983  }
4984  else change=(2.*(REAL)rand()-(REAL)RAND_MAX)/(REAL)RAND_MAX*mode.mBaseAmplitude*amplitude;
4985  this->RotateAtomGroup(*(mode.mpAtom1),vx,vy,vz,mode.mvRotatedAtomList,change,true);
4986  return change;
4987 }
4988 REAL Molecule::DihedralAngleRandomChange(const StretchModeTorsion& mode, const REAL amplitude,
4989  const bool respectRestraint)
4990 {
4991  const REAL dx=mode.mpAtom2->GetX()-mode.mpAtom1->GetX();
4992  const REAL dy=mode.mpAtom2->GetY()-mode.mpAtom1->GetY();
4993  const REAL dz=mode.mpAtom2->GetZ()-mode.mpAtom1->GetZ();
4994  REAL change=0.0;
4995  if((abs(dx)+abs(dy)+abs(dz))<1e-6) return change;// :KLUDGE:
4996  if(respectRestraint && mode.mpDihedralAngle!=0)
4997  {
4998  const REAL angle0=mode.mpDihedralAngle->GetAngle();
4999  const REAL a0=angle0-mode.mpDihedralAngle->GetAngle0();
5000  const REAL sigma=mode.mpDihedralAngle->GetAngleSigma();
5001  const REAL delta=mode.mpDihedralAngle->GetAngleDelta();
5002  if(sigma<1e-6)
5003  {
5004  REAL a1=a0+(REAL)(2*rand()-RAND_MAX)/(REAL)RAND_MAX*amplitude*mode.mBaseAmplitude;
5005  if(a1> delta)a1= delta;
5006  if(a1<-delta)a1=-delta;
5007  change=a1-a0;
5008  }
5009  else change=LorentzianBiasedRandomMove(a0,sigma,delta,amplitude*mode.mBaseAmplitude)-a0;
5010  if((a0+change)>(delta+sigma*5.0)) change= delta+sigma*5.0-a0;
5011  else if((a0+change)<(-delta-sigma*5.0)) change=-delta-sigma*5.0-a0;
5012  #if 0
5013  if(rand()%1==0)
5014  {
5015  cout<<"TORSION change ("
5016  <<mode.mpAtom1->GetName()<<"-"<<mode.mpAtom2->GetName()<<"):"<<endl
5017  <<" initial angle="<<angle0*RAD2DEG
5018  <<" (Restraint("<<mode.mpDihedralAngle->GetName()<<")="
5019  <<(angle0-a0)*RAD2DEG<<"s"<<sigma*RAD2DEG<<"d"<<delta*RAD2DEG<<"):"
5020  <<endl<<" New angle:"<<(angle0+change)*RAD2DEG<<", change="<<change*RAD2DEG<<endl;
5021  }
5022  #endif
5023  }
5024  else change=(REAL)(2.*rand()-RAND_MAX)/(REAL)RAND_MAX*mode.mBaseAmplitude*amplitude;
5025  this->RotateAtomGroup(*(mode.mpAtom1),*(mode.mpAtom2),mode.mvRotatedAtomList,change,true);
5026  return change;
5027 }
5028 
5030 {
5031  return mpCenterAtom;
5032 }
5033 
5035 {
5036  mpCenterAtom=&at;
5037  mClockAtomPosition.Click();
5038  this->UpdateDisplay();
5039 }
5040 
5041 void BuildZMatrixRecursive(long &z,const long curr,
5042  const vector<MolAtom*> &vpAtom,
5043  const map<MolAtom *, set<MolAtom *> > &connT,
5044  vector<MolZAtom> &zmatrix,
5045  const map<const MolAtom*,long> &vIndex,
5046  vector<long> &vZIndex,
5047  vector<long> &vrZIndex)
5048 {
5049  zmatrix[z].mpPow=&(vpAtom[curr]->GetScatteringPower());
5050  vZIndex[curr]=z;
5051  vrZIndex[z]=curr;
5052  // Get the list of connected atoms and sort them
5053  map<MolAtom *, set<MolAtom *> >::const_iterator pConn=connT.find(vpAtom[curr]);
5054  const long nc=pConn->second.size();
5055  vector<long> conn(nc);
5056  vector<long> zconn(nc);
5057  vector<long>::iterator pos=conn.begin();
5058  vector<long>::iterator zpos=zconn.begin();
5059  for(set<MolAtom *>::const_iterator pos1=pConn->second.begin();pos1!=pConn->second.end();++pos1)
5060  {
5061  *pos = vIndex.find(*pos1)->second;
5062  *zpos = vZIndex[*pos];
5063  cout<<(*pos1)->GetName()<<"("<<*pos<<","<<*zpos<<")"<<endl;
5064  zpos++;pos++;
5065  }
5066  sort(conn.begin(),conn.end());
5067  sort(zconn.begin(),zconn.end());
5068  if(z>0)
5069  {
5070  // Use the most recent atom in the z-matrix
5071  const long b=zconn[nc-1];
5072  zmatrix[z].mBondAtom=b;
5073  zmatrix[z].mBondLength=GetBondLength(*vpAtom[vrZIndex[b]],*vpAtom[curr]);
5074  if(z>1)
5075  {
5076  const long a=zmatrix[b].mBondAtom;
5077  zmatrix[z].mBondAngleAtom=a;
5078  zmatrix[z].mBondAngle=GetBondAngle(*vpAtom[vrZIndex[a]],*vpAtom[vrZIndex[b]],*vpAtom[curr]);
5079  if(z>2)
5080  {
5081  const long d=zmatrix[b].mBondAngleAtom;
5082  zmatrix[z].mDihedralAtom=d;
5083  zmatrix[z].mDihedralAngle=fmod(GetDihedralAngle(*vpAtom[vrZIndex[d]],*vpAtom[vrZIndex[a]],
5084  *vpAtom[vrZIndex[b]],*vpAtom[curr])+2*M_PI,
5085  2*M_PI);
5086  }
5087  else
5088  {
5089  zmatrix[z].mDihedralAtom=0;
5090  zmatrix[z].mDihedralAngle=0;
5091  }
5092  }
5093  else
5094  {
5095  zmatrix[z].mBondAngleAtom=0;
5096  zmatrix[z].mBondAngle=0;
5097  }
5098  }
5099  else
5100  {
5101  zmatrix[z].mBondAtom=0;
5102  zmatrix[z].mBondLength=0;
5103  }
5104  z++;
5105  // Continue filling up the zmatrix, beginning from thz first atoms not already in the zmatrix
5106  for(pos=conn.begin();pos!=conn.end();++pos)
5107  {
5108  if(*pos!=-1)
5109  {
5110  if(vZIndex[*pos]==-1)
5111  BuildZMatrixRecursive(z,*pos,vpAtom,connT,zmatrix,vIndex,vZIndex,vrZIndex);
5112  }
5113  }
5114 }
5115 
5116 const vector<MolZAtom>& Molecule::AsZMatrix(const bool keeporder)const
5117 {
5118  this->BuildConnectivityTable();
5119  const long n=mvpAtom.size();
5120  // index of the atoms in the list
5121  map<const MolAtom*,long> vIndex;
5122  {
5123  long i=0;
5124  for(vector<MolAtom*>::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
5125  vIndex[*pos]=i++;
5126  }
5127  mAsZMatrix.resize(n);
5128  if(keeporder)
5129  {
5130  for(long i=0;i<n;++i)
5131  {
5132  mAsZMatrix[i].mpPow=&(mvpAtom[i]->GetScatteringPower());
5133  if(i>0)
5134  {
5135  const set<MolAtom *> *pConn=&(mConnectivityTable.find(mvpAtom[i])->second);
5136  // Find a connected atom already in the mAsZMatrix, prefereably the most recent
5137  long b=-1;
5138  for(set<MolAtom *>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5139  if((vIndex[*pos]<i)&&(vIndex[*pos]>b)) b=vIndex[*pos];
5140  // Did not find a connected atom already in the z-matrix ? Take the last one
5141  if(b==-1) b=i-1;
5142  mAsZMatrix[i].mBondAtom=b;
5143  mAsZMatrix[i].mBondLength=GetBondLength(*mvpAtom[b],*mvpAtom[i]);
5144  if(i>1)
5145  {
5146  const long a= (b==0)?1 : mAsZMatrix[b].mBondAtom;
5147  mAsZMatrix[i].mBondAngleAtom=a;
5148  mAsZMatrix[i].mBondAngle=GetBondAngle(*mvpAtom[a],*mvpAtom[b],*mvpAtom[i]);
5149  if(i>2)
5150  {
5151  long d= mAsZMatrix[a].mBondAtom;
5152  if(d==b)
5153  {// Dihedral atom is already bond atom, find another connected to angle atom
5154  d=-1;
5155  const set<MolAtom *> *pConn=&(mConnectivityTable.find(mvpAtom[a])->second);
5156  // Find a connected atom already in the mAsZMatrix, prefereably the most recent
5157  for(set<MolAtom *>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5158  if((vIndex[*pos]<i) && (vIndex[*pos]!=b) && (vIndex[*pos]>d)) d=vIndex[*pos];
5159  }
5160  if(d==-1)
5161  {// Can't find an angle connected to angle atom, so find another with bond atom
5162  const set<MolAtom *> *pConn=&(mConnectivityTable.find(mvpAtom[b])->second);
5163  // Find a connected atom already in the mAsZMatrix, prefereably the most recent
5164  for(set<MolAtom *>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5165  if((vIndex[*pos]<i) && (vIndex[*pos]!=a) && (vIndex[*pos]>d)) d=vIndex[*pos];
5166  }
5167  if(d==-1)
5168  {// Maybe another connected to this atom ??
5169  const set<MolAtom *> *pConn=&(mConnectivityTable.find(mvpAtom[i])->second);
5170  // Find a connected atom already in the mAsZMatrix, prefereably the most recent
5171  for(set<MolAtom *>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5172  if( (vIndex[*pos]<i) && (vIndex[*pos]!=a)
5173  &&(vIndex[*pos]!=b) && (vIndex[*pos]>d)) d=vIndex[*pos];
5174  }
5175  if(d==-1)
5176  {// OK, pick *any* (can this happen ? Really ?)
5177  for(long j=0;j<i;++j)
5178  if((j!=a) &&(j!=b) && (j>d)) d=j;
5179  }
5180  mAsZMatrix[i].mDihedralAtom=d;
5181  mAsZMatrix[i].mDihedralAngle=fmod(GetDihedralAngle(*mvpAtom[d],
5182  *mvpAtom[a],
5183  *mvpAtom[b],
5184  *mvpAtom[i])+2*M_PI,
5185  2*M_PI);
5186  }
5187  }
5188  }
5189  }
5190  }
5191  else
5192  {
5193  // vZIndex[i] tells where mvpAtom[i] is in the z-matrix
5194  vector<long> vZIndex(n);
5195  // vrZIndex[i] tells where which index in vpAtom is ZAtom #i
5196  vector<long> vrZIndex(n);
5197  for(long i=0;i<n;++i)
5198  {
5199  vZIndex [i]=-1;
5200  vrZIndex[i]=-1;
5201  }
5202  long z=0;
5203  BuildZMatrixRecursive(z,0,mvpAtom,mConnectivityTable,mAsZMatrix,vIndex,vZIndex,vrZIndex);
5204  }
5205  return mAsZMatrix;
5206 }
5207 
5209 {
5210 }
5211 
5221 void BuildRingRecursive(MolAtom * currentAtom,
5222  MolAtom * previousAtom,
5223  const map<MolAtom *, set<MolAtom *> > &connect,
5224  list<MolAtom *> &atomlist,
5225  map<set<MolAtom *>,list<MolAtom *> > &ringlist)
5226 {
5227  list<MolAtom *>::const_iterator f=find(atomlist.begin(),atomlist.end(),currentAtom);
5228  if(f!=atomlist.end())
5229  {// This atom was already in the list ! We have found a ring !
5230  #ifdef __DEBUG__
5231  cout<<currentAtom->GetName()<<" was already in the list : ring found !"<<endl;
5232  for(list<MolAtom *>::const_iterator atom=atomlist.begin();atom!=atomlist.end();++atom)
5233  cout<<(*atom)->GetName()<<" ";
5234  cout<<endl;
5235  #endif
5236  set<MolAtom *> ring1;
5237  list<MolAtom *> ring2;
5238  for(list<MolAtom *>::const_iterator pos=f;pos!=atomlist.end();++pos)
5239  {
5240  ring1.insert(*pos);
5241  ring2.push_back(*pos);
5242  }
5243  ringlist.insert(make_pair(ring1,ring2));
5244  }
5245  else
5246  {
5247  atomlist.push_back(currentAtom);
5248  map<MolAtom *,set<MolAtom *> >::const_iterator c=connect.find(currentAtom);
5249  set<MolAtom *>::const_iterator pos;
5250  for(pos=c->second.begin();pos!=c->second.end();++pos)
5251  {
5252  if(*pos==previousAtom) continue;
5253  BuildRingRecursive(*pos,currentAtom,connect,atomlist,ringlist);
5254  }
5255  atomlist.pop_back(); //??
5256  }
5257 }
5258 
5260 {
5261  this->BuildConnectivityTable();
5262  if(mClockRingList>mClockConnectivityTable) return;
5263  VFN_DEBUG_ENTRY("Molecule::BuildRingList()",7)
5264  for(vector<MolAtom*>::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
5265  (*pos)->SetIsInRing(false);
5266  list<MolAtom *> atomlist;
5267  // Use a map with a set for key to eliminate duplicate rings
5268  map<set<MolAtom *>,list<MolAtom *> > ringlist;
5269  for(unsigned long i=0;i<mvpAtom.size();i++)
5270  {
5271  atomlist.clear();
5272  BuildRingRecursive(mvpAtom[i],mvpAtom[i],mConnectivityTable,atomlist,ringlist);
5273  }
5274  for(map<set<MolAtom *>,list<MolAtom *> >::const_iterator pos0=ringlist.begin();pos0!=ringlist.end();pos0++)
5275  {
5276  mvRing.resize(mvRing.size()+1);
5277  std::list<MolAtom*> *pList=&(mvRing.back().GetAtomList());
5278  #if 1//def __DEBUG__
5279  cout<<"Found ring:";
5280  #endif
5281  for(list<MolAtom *>::const_iterator atom=pos0->second.begin();atom!=pos0->second.end();++atom)
5282  {
5283  pList->push_back(*atom);
5284  (*atom)->SetIsInRing(true);
5285  #if 1//def __DEBUG__
5286  cout<<(*atom)->GetName()<<" ";
5287  #endif
5288  }
5289  #if 1//def __DEBUG__
5290  cout<<endl;
5291  #endif
5292  }
5293 
5294  cout<<"Rings found :"<<ringlist.size()<<", "<<mvRing.size()<<" unique."<<endl;
5295  mClockRingList.Click();
5296  VFN_DEBUG_EXIT("Molecule::BuildRingList()",7)
5297 }
5298 
5300 {
5301  if( (mClockConnectivityTable>mClockBondList)
5302  &&(mClockConnectivityTable>mClockAtomList)) return;
5303  VFN_DEBUG_ENTRY("Molecule::BuildConnectivityTable()",5)
5304  TAU_PROFILE("Molecule::BuildConnectivityTable()","void ()",TAU_DEFAULT);
5305  mConnectivityTable.clear();
5306  for(unsigned long i=0;i<mvpBond.size();++i)
5307  {
5308  mConnectivityTable[&(mvpBond[i]->GetAtom1())].insert(&(mvpBond[i]->GetAtom2()));
5309  mConnectivityTable[&(mvpBond[i]->GetAtom2())].insert(&(mvpBond[i]->GetAtom1()));
5310  }
5311 
5312  #ifdef __DEBUG__
5313  {
5314  map<MolAtom *,set<MolAtom *> >::const_iterator pos;
5315  for(pos=mConnectivityTable.begin();pos!=mConnectivityTable.end();++pos)
5316  {
5317  cout<<"Atom "<<pos->first->GetName()<<" is connected to atoms: ";
5318  set<MolAtom *>::const_iterator pos1;
5319  for(pos1=pos->second.begin();pos1!=pos->second.end();++pos1)
5320  {
5321  cout<<(*pos1)->GetName()<<" ";
5322  }
5323  cout<<endl;
5324  if(pos->second.size()>24)
5325  throw ObjCrystException("Molecule: one atom ("+pos->first->GetName()+") has more than 24 bonds !");
5326  }
5327  }
5328  #endif
5329  mClockConnectivityTable.Click();
5330  VFN_DEBUG_EXIT("Molecule::BuildConnectivityTable()",5)
5331 }
5332 
5334 mpAtom1(&at1),mpAtom2(&at2),mBaseRotationAmplitude(M_PI*0.04)
5335 {}
5336 
5338 {
5339  if( (mClockRotorGroup>mClockBondList)
5340  &&(mClockRotorGroup>mClockAtomList)
5341  &&(mClockRotorGroup>mClockBondAngleList)
5342  &&(mClockRotorGroup>mClockDihedralAngleList)) return;
5343  VFN_DEBUG_ENTRY("Molecule::BuildRotorGroup()",5)
5344  TAU_PROFILE("Molecule::BuildRotorGroup()","void ()",TAU_DEFAULT);
5345  this->BuildConnectivityTable();
5346  mvRotorGroupTorsion.clear();
5348  mvRotorGroupInternal.clear();
5349 
5350  // Build Rotation groups around bonds
5351  for(unsigned long i=0;i<mvpBond.size();++i)
5352  {
5353  if((mFlexModel.GetChoice()!=0)&&(false==mvpBond[i]->IsFreeTorsion())) continue;
5354  MolAtom *const atom1=&(mvpBond[i]->GetAtom1()),
5355  *const atom2=&(mvpBond[i]->GetAtom2());
5356  for(unsigned int j=1;j<=2;++j)
5357  {
5358  const set<MolAtom*> *pConn;
5359  if(j==1) pConn=&(mConnectivityTable[atom1]);
5360  else pConn=&(mConnectivityTable[atom2]);
5361 
5362  mvRotorGroupTorsion.push_back(RotorGroup(mvpBond[i]->GetAtom1(),
5363  mvpBond[i]->GetAtom2()));
5364  mvRotorGroupTorsion.back().mvRotatedAtomList.insert(atom1);
5365  mvRotorGroupTorsion.back().mvRotatedAtomList.insert(atom2);
5366 
5367  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5368  {
5369  if((j==1)&&(*pos==atom2)) continue;
5370  if((j==2)&&(*pos==atom1)) continue;
5372  mvRotorGroupTorsion.back().mvRotatedAtomList);
5373  if(pConn->size()>2)
5374  {
5375  mvRotorGroupTorsionSingleChain.push_back(RotorGroup(mvpBond[i]->GetAtom1(),
5376  mvpBond[i]->GetAtom2()));
5377  mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.insert(atom1);
5378  mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.insert(atom2);
5380  mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList);
5381  mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.erase(atom1);
5382  mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.erase(atom2);
5383 
5384  if( (mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2))
5385  ||(mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.size()==0))
5386  mvRotorGroupTorsionSingleChain.pop_back();
5387  }
5388  }
5389  mvRotorGroupTorsion.back().mvRotatedAtomList.erase(atom1);
5390  mvRotorGroupTorsion.back().mvRotatedAtomList.erase(atom2);
5391  if( (mvRotorGroupTorsion.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2))
5392  ||(mvRotorGroupTorsion.back().mvRotatedAtomList.size()==0))
5393  mvRotorGroupTorsion.pop_back();
5394  }
5395  }
5396  #if 1
5397  // Build 'internal' rotation groups between random atoms
5398  //:TODO: This should be tried for *random* configuration of free torsion angles...
5399  if(mFlexModel.GetChoice()==0)
5400  {
5401  for(vector<MolAtom*>::const_iterator atom1=this->GetAtomList().begin();
5402  atom1!=this->GetAtomList().end();++atom1)
5403  {
5404  const set<MolAtom*> *pConn=&(mConnectivityTable[*atom1]);
5405  vector<MolAtom*>::const_iterator atom2=atom1;
5406  atom2++;
5407  for(;atom2!=this->GetAtomList().end();++atom2)
5408  {
5409  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5410  {
5411  if(*pos==*atom2) continue;
5412  mvRotorGroupInternal.push_back(RotorGroup(**atom1,**atom2));
5413  mvRotorGroupInternal.back().mvRotatedAtomList.insert(*atom1);
5415  mvRotorGroupInternal.back().mvRotatedAtomList,
5416  *atom2);
5417  //Check if this chains leads to atom2
5418  set<MolAtom*>::const_iterator check
5419  =find(mvRotorGroupInternal.back().mvRotatedAtomList.begin(),
5420  mvRotorGroupInternal.back().mvRotatedAtomList.end(),*atom2);
5421  if( (check==mvRotorGroupInternal.back().mvRotatedAtomList.end())
5422  ||(mvRotorGroupInternal.back().mvRotatedAtomList.size()<3)
5423  ||(mvRotorGroupInternal.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2)))
5424  {
5425  mvRotorGroupInternal.pop_back();
5426  }
5427  else
5428  {
5429  mvRotorGroupInternal.back().mvRotatedAtomList.erase(*atom1);
5430  mvRotorGroupInternal.back().mvRotatedAtomList.erase(*atom2);
5431  }
5432  }
5433  }
5434  }
5435  }
5436  #endif
5437 
5438  // Remove identical groups
5439  for(unsigned int i=1;i<=3;++i)
5440  {
5441  list<RotorGroup> *pRotorGroup1;
5442  switch(i)
5443  {
5444  case 1: pRotorGroup1=&mvRotorGroupTorsion;break;
5445  case 2: pRotorGroup1=&mvRotorGroupTorsionSingleChain;break;
5446  case 3: pRotorGroup1=&mvRotorGroupInternal;break;
5447  }
5448  for(list<RotorGroup>::iterator pos1=pRotorGroup1->begin();
5449  pos1!=pRotorGroup1->end();++pos1)
5450  {
5451  for(unsigned int j=i;j<=3;++j)
5452  {
5453  list<RotorGroup> *pRotorGroup2;
5454  switch(j)
5455  {
5456  case 1: pRotorGroup2=&mvRotorGroupTorsion;break;
5457  case 2: pRotorGroup2=&mvRotorGroupTorsionSingleChain;break;
5458  case 3: pRotorGroup2=&mvRotorGroupInternal;break;
5459  }
5460  for(list<RotorGroup>::iterator pos2=pRotorGroup2->begin();
5461  pos2!=pRotorGroup2->end();)
5462  {
5463  if(pos2==pos1) {++pos2;continue;}
5464  if(( ((pos1->mpAtom1 == pos2->mpAtom1) && (pos1->mpAtom2 == pos2->mpAtom2))
5465  ||((pos1->mpAtom2 == pos2->mpAtom1) && (pos1->mpAtom1 == pos2->mpAtom2)))
5466  &&pos1->mvRotatedAtomList.size() == pos2->mvRotatedAtomList.size())
5467  {
5468  bool ident=true;
5469  for(set<MolAtom*>::const_iterator pos=pos1->mvRotatedAtomList.begin();
5470  pos!=pos1->mvRotatedAtomList.end();++pos)
5471  {
5472  set<MolAtom*>::const_iterator tmp=pos2->mvRotatedAtomList.find(*pos);
5473  if(tmp == pos2->mvRotatedAtomList.end())
5474  {
5475  ident=false;
5476  break;
5477  }
5478  }
5479  if(ident)
5480  {
5481  #if 0
5482  cout<<"Identical groups:"<<endl;
5483  cout<<" G1:"
5484  <<pos1->mpAtom1->GetName()<<"-"
5485  <<pos1->mpAtom2->GetName()<<" : ";
5486  for(set<MolAtom*>::iterator pos=pos1->mvRotatedAtomList.begin();
5487  pos!=pos1->mvRotatedAtomList.end();++pos)
5488  cout<<(*pos)->GetName()<<" ";
5489  cout<<endl;
5490  cout<<" G2:"
5491  <<pos2->mpAtom1->GetName()<<"-"
5492  <<pos2->mpAtom2->GetName()<<" : ";
5493  for(set<MolAtom*>::iterator pos=pos2->mvRotatedAtomList.begin();
5494  pos!=pos2->mvRotatedAtomList.end();++pos)
5495  cout<<(*pos)->GetName()<<" ";
5496  cout<<endl;
5497  #endif
5498  pos2=pRotorGroup2->erase(pos2);
5499  }
5500  else ++pos2;
5501  }
5502  else ++pos2;
5503  }
5504  }
5505  }
5506  }
5507  // Remove all rotations which break restraints and therefore are not "free torsion"
5508  this->SaveParamSet(mLocalParamSet);
5509  const REAL llk0=this->GetLogLikelihood();
5510  for(unsigned int i=1;i<=3;++i)
5511  {
5512  list<RotorGroup> *pRotorGroup1;
5513  switch(i)
5514  {
5515  case 1: pRotorGroup1=&mvRotorGroupTorsion;break;
5516  case 2: pRotorGroup1=&mvRotorGroupTorsionSingleChain;break;
5517  case 3: pRotorGroup1=&mvRotorGroupInternal;break;
5518  }
5519  for(list<RotorGroup>::iterator pos=pRotorGroup1->begin();
5520  pos!=pRotorGroup1->end();)
5521  {
5522  REAL llk=0;
5523  for(unsigned int j=0;j<36;++j)
5524  {
5525  const REAL angle=(REAL)j*M_PI/36.;
5526  this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),
5527  pos->mvRotatedAtomList,angle);
5528  // use fabs in case we are not starting from the minimum of a restraint..
5529  llk += fabs(this->GetLogLikelihood() - llk0);
5530  this->RestoreParamSet(mLocalParamSet);
5531  }
5532  #ifdef __DEBUG__
5533  switch(i)
5534  {
5535  case 1: cout<<"Rotation Group around bond :";break;
5536  case 2: cout<<"Rotation Group (single chain) around bond :";break;
5537  case 3: cout<<"Rotation Group (internal) between :";break;
5538  }
5539  cout <<pos->mpAtom1->GetName()<<"-"
5540  <<pos->mpAtom2->GetName()<<" : ";
5541  for(set<MolAtom *>::iterator pos1=pos->mvRotatedAtomList.begin();
5542  pos1!=pos->mvRotatedAtomList.end();++pos1)
5543  cout<<(*pos1)->GetName()<<" ";
5544  cout<<" <d(LLK)>="<< llk/36.;
5545  #endif
5546  if((llk/50.)>100.)
5547  {
5548  pos = pRotorGroup1->erase(pos);
5549  //cout <<" -> NOT a free torsion"<<endl;
5550  }
5551  else ++pos;
5552  //else
5553  // cout <<" -> free torsion"<<endl;
5554  }
5555  }
5556  //cout<<endl;
5557 
5558  // Label free torsions
5559  for(vector<MolBond*>::iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos)
5560  (*pos)->SetFreeTorsion(false);
5561  for(list<RotorGroup>::iterator pos=mvRotorGroupTorsion.begin();
5562  pos!=mvRotorGroupTorsion.end();++pos)
5563  {
5564  vector<MolBond*>::iterator bd=this->FindBond((*pos->mpAtom1),(*pos->mpAtom2));
5565  if(bd!=mvpBond.end()) (*bd)->SetFreeTorsion(true);
5566  }
5567 
5568  mClockRotorGroup.Click();
5569  VFN_DEBUG_EXIT("Molecule::BuildRotorGroup()",5)
5570 }
5571 
5573 {
5574  #if 0
5575  if( (mClockStretchModeBondLength>mClockBondList)
5576  &&(mClockStretchModeBondLength>mClockAtomList)
5577  &&(mClockStretchModeBondLength>mClockBondAngleList)
5578  &&(mClockStretchModeBondLength>mClockDihedralAngleList)) return;
5579  #endif
5580  VFN_DEBUG_ENTRY("Molecule::BuildStretchModeBondLength()",7)
5581  this->BuildConnectivityTable();
5582  TAU_PROFILE("Molecule::BuildStretchModeBondLength()","void ()",TAU_DEFAULT);
5583  TAU_PROFILE_TIMER(timer1,"Molecule::BuildStretchModeBondLength 1","", TAU_FIELD);
5584  TAU_PROFILE_TIMER(timer2,"Molecule::BuildStretchModeBondLength 2","", TAU_FIELD);
5585  TAU_PROFILE_TIMER(timer3,"Molecule::BuildStretchModeBondLength 3","", TAU_FIELD);
5586  TAU_PROFILE_TIMER(timer4,"Molecule::BuildStretchModeBondLength 4","", TAU_FIELD);
5587  TAU_PROFILE_TIMER(timer5,"Molecule::BuildStretchModeBondLength 5","", TAU_FIELD);
5588  mvStretchModeBondLength.clear();
5589  // Build list of atoms moved when stretching a bond length. Only keep the group
5590  // of atoms on the smaller side.
5591  TAU_PROFILE_START(timer1);
5592  for(unsigned long i=0;i<mvpBond.size();++i)
5593  {
5594  //if((mFlexModel.GetChoice()!=0)&&(false==mvpBond[i]->IsFreeTorsion())) continue;
5595  MolAtom* const atom1=&(mvpBond[i]->GetAtom1());
5596  MolAtom* const atom2=&(mvpBond[i]->GetAtom2());
5597  for(unsigned int j=1;j<=2;++j)
5598  {
5599  const set<MolAtom*> *pConn;
5600  if(j==1) pConn=&(mConnectivityTable[atom1]);
5601  else pConn=&(mConnectivityTable[atom2]);
5602 
5603  if(j==1)
5604  mvStretchModeBondLength.push_back(StretchModeBondLength(mvpBond[i]->GetAtom2(),
5605  mvpBond[i]->GetAtom1(),
5606  mvpBond[i]));
5607  else
5608  mvStretchModeBondLength.push_back(StretchModeBondLength(mvpBond[i]->GetAtom1(),
5609  mvpBond[i]->GetAtom2(),
5610  mvpBond[i]));
5611  if(j==1) mvStretchModeBondLength.back().mvTranslatedAtomList.insert(atom1);
5612  if(j==2) mvStretchModeBondLength.back().mvTranslatedAtomList.insert(atom2);
5613 
5614  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5615  {
5616  if((j==1)&&(*pos==atom2)) continue;
5617  if((j==2)&&(*pos==atom1)) continue;
5619  mvStretchModeBondLength.back().mvTranslatedAtomList);
5620  }
5621  const unsigned long ct1=mvStretchModeBondLength.back().mvTranslatedAtomList.count(atom1),
5622  ct2=mvStretchModeBondLength.back().mvTranslatedAtomList.count(atom2);
5623  if( ((j==1)&&(ct2>0)) || ((j==2)&&(ct1>0)) )
5624  {
5625  // We have found a ring. No use looking at the other side.
5626  // :TODO: handle this properly..
5627  mvStretchModeBondLength.pop_back();
5628  break;
5629  }
5630  if( (mvStretchModeBondLength.back().mvTranslatedAtomList.size()>((mvpAtom.size()+1)/2))
5631  ||(mvStretchModeBondLength.back().mvTranslatedAtomList.size()==0))
5632  {
5633  #ifdef __DEBUG__
5634  cout<<"Rejecting StretchModeBondLength ";mvStretchModeBondLength.back().Print(cout);cout<<endl;
5635  #endif
5636  mvStretchModeBondLength.pop_back();
5637  }
5638  else if(mvStretchModeBondLength.back().mvTranslatedAtomList.size()==((mvpAtom.size()+1)/2))
5639  break;//we translate exactly half of the atoms, so skip the other half
5640  }
5641  }
5642  TAU_PROFILE_STOP(timer1);
5643 
5644  // find rigid groups broken by each mode
5645  for(list<StretchModeBondLength>::iterator pos=mvStretchModeBondLength.begin();
5646  pos!=mvStretchModeBondLength.end();)
5647  {
5648  TAU_PROFILE_START(timer5);
5649  bool keep=true;
5650  for(vector<RigidGroup*>::const_iterator group=mvRigidGroup.begin();
5651  group!=mvRigidGroup.end();++group)
5652  {
5653  unsigned long ct=0;
5654  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
5655  ct += pos->mvTranslatedAtomList.count(*at);
5656  if((ct>0)&&(ct!=(*group)->size()))
5657  {
5658  keep=false;
5659  #ifdef __DEBUG__
5660  cout<<" Breaks Rigid Group:";
5661  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
5662  cout<<(*at)->GetName()<<" ";
5663  cout<<endl;
5664  #endif
5665  break;
5666  }
5667  }
5668  if(keep) ++pos;
5669  else pos=mvStretchModeBondLength.erase(pos);
5670  TAU_PROFILE_STOP(timer5);
5671  }
5672  // Generate 5 completely random atomic positions
5673  this->SaveParamSet(mLocalParamSet);
5674  unsigned long paramSetRandom[5];
5675  for(unsigned long i=0;i<5;++i)
5676  {
5677  for(vector<MolAtom*>::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
5678  {
5679  (*pos)->SetX(100.*rand()/(REAL) RAND_MAX);
5680  (*pos)->SetY(100.*rand()/(REAL) RAND_MAX);
5681  (*pos)->SetZ(100.*rand()/(REAL) RAND_MAX);
5682  }
5683  paramSetRandom[i]=this->CreateParamSet();
5684  }
5685  // find bond lengths broken by each mode
5686  for(list<StretchModeBondLength>::iterator pos=mvStretchModeBondLength.begin();
5687  pos!=mvStretchModeBondLength.end();)
5688  {
5689  TAU_PROFILE_START(timer2);
5690  bool keep=true;
5691  pos->mvpBrokenBond.clear();
5692  for(vector<MolBond*>::const_iterator r=mvpBond.begin();r!=mvpBond.end();++r)
5693  {
5694  unsigned int ct=0;
5695  for(set<MolAtom *>::const_iterator at=pos->mvTranslatedAtomList.begin();
5696  at!=pos->mvTranslatedAtomList.end();++at)
5697  {
5698  if(*at==&((*r)->GetAtom1())) ct++;
5699  if(*at==&((*r)->GetAtom2())) ct++;
5700  }
5701  // If we moved either both or non of the bond atom, the bond length is unchanged.
5702  if((ct!=0)&&(ct !=2)) pos->mvpBrokenBond.insert(make_pair(*r,0));
5703  }
5704  if(mFlexModel.GetChoice()==2)
5705  {
5706  int nb=pos->mvpBrokenBond.size();
5707  if(pos->mpBond!=0) nb -= 1;
5708  if(nb>0) keep=false;
5709  }
5710  if(keep) ++pos;
5711  else pos=mvStretchModeBondLength.erase(pos);
5712  TAU_PROFILE_STOP(timer2);
5713  }
5714  // find bond angles broken by each mode
5715  for(list<StretchModeBondLength>::iterator pos=mvStretchModeBondLength.begin();
5716  pos!=mvStretchModeBondLength.end();)
5717  {
5718  TAU_PROFILE_START(timer3);
5719  bool keep=true;
5720  pos->mvpBrokenBondAngle.clear();
5721  for(vector<MolBondAngle*>::const_iterator r=mvpBondAngle.begin();r!=mvpBondAngle.end();++r)
5722  {
5723  unsigned int ct=0;
5724  for(set<MolAtom *>::const_iterator at=pos->mvTranslatedAtomList.begin();
5725  at!=pos->mvTranslatedAtomList.end();++at)
5726  {
5727  if(*at==&((*r)->GetAtom1())) ct++;
5728  if(*at==&((*r)->GetAtom2())) ct++;
5729  if(*at==&((*r)->GetAtom3())) ct++;
5730  }
5731  bool broken=true;
5732  if((ct==0)||(ct==3)) broken=false;
5733  if(broken)
5734  {// Make sure with derivatives
5735  REAL d=0;
5736  for(unsigned long i=0;i<5;++i)
5737  {
5738  this->RestoreParamSet(paramSetRandom[i]);
5739  pos->CalcDeriv(false);
5740  (*r)->GetLogLikelihood(true,true);
5741  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
5742  if(d>0.01) break;
5743  }
5744  if(abs(d)<=0.01) broken=false;
5745  }
5746  if(broken) pos->mvpBrokenBondAngle.insert(make_pair(*r,0));
5747  }
5748  if(mFlexModel.GetChoice()==2)
5749  {
5750  if(pos->mvpBrokenBondAngle.size()>0) keep=false;
5751  }
5752  if(keep) ++pos;
5753  else pos=mvStretchModeBondLength.erase(pos);
5754  TAU_PROFILE_STOP(timer3);
5755  }
5756  // find dihedral angles broken by each mode
5757  for(list<StretchModeBondLength>::iterator pos=mvStretchModeBondLength.begin();
5758  pos!=mvStretchModeBondLength.end();)
5759  {
5760  TAU_PROFILE_START(timer4);
5761  bool keep=true;
5762  pos->mvpBrokenDihedralAngle.clear();
5763  for(vector<MolDihedralAngle*>::const_iterator r=mvpDihedralAngle.begin();r!=mvpDihedralAngle.end();++r)
5764  {
5765  unsigned int ct=0;
5766  for(set<MolAtom *>::const_iterator at=pos->mvTranslatedAtomList.begin();
5767  at!=pos->mvTranslatedAtomList.end();++at)
5768  {
5769  if(*at==&((*r)->GetAtom1())) ct++;
5770  if(*at==&((*r)->GetAtom2())) ct++;
5771  if(*at==&((*r)->GetAtom3())) ct++;
5772  if(*at==&((*r)->GetAtom4())) ct++;
5773  }
5774  bool broken=true;
5775  if((ct==0)||(ct==4)) broken=false;
5776  if(broken)
5777  {// Make sure with derivatives
5778  REAL d=0;
5779  for(unsigned long i=0;i<5;++i)
5780  {
5781  this->RestoreParamSet(paramSetRandom[i]);
5782  pos->CalcDeriv(false);
5783  (*r)->GetLogLikelihood(true,true);
5784  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
5785  if(d>0.01) break;
5786  }
5787  if(abs(d)<=0.01) broken=false;
5788  }
5789  if(broken) pos->mvpBrokenDihedralAngle.insert(make_pair(*r,0));
5790  }
5791  if(mFlexModel.GetChoice()==2)
5792  {
5793  if(pos->mvpBrokenDihedralAngle.size()>0) keep=false;
5794  }
5795  if(keep) ++pos;
5796  else pos=mvStretchModeBondLength.erase(pos);
5797  TAU_PROFILE_STOP(timer4);
5798  }
5799  this->RestoreParamSet(mLocalParamSet);
5800  for(unsigned long i=0;i<5;++i) this->ClearParamSet(paramSetRandom[i]);
5801  #if 1//def __DEBUG__
5802  cout<<"List of Bond Length stretch modes"<<endl;
5803  for(list<StretchModeBondLength>::const_iterator pos=mvStretchModeBondLength.begin();
5804  pos!=mvStretchModeBondLength.end();++pos)
5805  {
5806  cout<<" Bond:"<<pos->mpAtom0->GetName()<<"-"<<pos->mpAtom1->GetName()<<", Translated Atoms: ";
5807  for(set<MolAtom*>::const_iterator atom=pos->mvTranslatedAtomList.begin();
5808  atom!=pos->mvTranslatedAtomList.end();++atom)
5809  {
5810  cout<<(*atom)->GetName()<<",";
5811  }
5812  if(pos->mpBond!=0) cout<< " ; restrained to length="<<pos->mpBond->GetLength0()
5813  <<", sigma="<<pos->mpBond->GetLengthSigma()
5814  <<", delta="<<pos->mpBond->GetLengthDelta();
5815  if(pos->mvpBrokenBond.size()>0)
5816  {
5817  cout<<endl<<" Broken bonds:";
5818  for(map<const MolBond*,REAL>::const_iterator bond=pos->mvpBrokenBond.begin();
5819  bond!=pos->mvpBrokenBond.end();++bond)
5820  cout<<bond->first->GetName()<<", ";
5821  }
5822  if(pos->mvpBrokenBondAngle.size()>0)
5823  {
5824  cout<<endl<<" Broken bond angles:";
5825  for(map<const MolBondAngle*,REAL>::const_iterator angle=pos->mvpBrokenBondAngle.begin();
5826  angle!=pos->mvpBrokenBondAngle.end();++angle)
5827  cout<<angle->first->GetName()<<", ";
5828  }
5829  if(pos->mvpBrokenDihedralAngle.size()>0)
5830  {
5831  cout<<endl<<" Broken dihedral angles:";
5832  for(map<const MolDihedralAngle*,REAL>::const_iterator
5833  angle=pos->mvpBrokenDihedralAngle.begin();
5834  angle!=pos->mvpBrokenDihedralAngle.end();++angle)
5835  cout<<angle->first->GetName()<<", ";
5836  }
5837  cout<<endl;
5838  }
5839  #endif
5840  mClockStretchModeBondLength.Click();
5841  VFN_DEBUG_EXIT("Molecule::BuildStretchModeBondLength()",7)
5842 }
5843 
5845 {
5846  #if 0
5847  if( (mClockStretchModeBondAngle>mClockBondList)
5848  &&(mClockStretchModeBondAngle>mClockAtomList)
5849  &&(mClockStretchModeBondAngle>mClockBondAngleList)
5850  &&(mClockStretchModeBondAngle>mClockDihedralAngleList)) return;
5851  #endif
5852  VFN_DEBUG_ENTRY("Molecule::BuildStretchModeBondAngle()",10)
5853  this->BuildConnectivityTable();
5854  TAU_PROFILE("Molecule::BuildStretchModeBondAngle()","void ()",TAU_DEFAULT);
5855  TAU_PROFILE_TIMER(timer1,"Molecule::BuildStretchModeBondAngle 1","", TAU_FIELD);
5856  TAU_PROFILE_TIMER(timer2,"Molecule::BuildStretchModeBondAngle 2","", TAU_FIELD);
5857  TAU_PROFILE_TIMER(timer3,"Molecule::BuildStretchModeBondAngle 3","", TAU_FIELD);
5858  TAU_PROFILE_TIMER(timer4,"Molecule::BuildStretchModeBondAngle 4","", TAU_FIELD);
5859  TAU_PROFILE_TIMER(timer5,"Molecule::BuildStretchModeBondAngle 5","", TAU_FIELD);
5860  mvStretchModeBondAngle.clear();
5861  // Build list of atoms moved when stretching a bond angle. Only keep the group
5862  // of atoms on the smaller side.
5863  TAU_PROFILE_START(timer1);
5864  for(unsigned long i=0;i<mvpAtom.size();++i)
5865  {
5866  //if((mFlexModel.GetChoice()!=0)&&(false==mvpBond[i]->IsFreeTorsion())) continue;
5867  set<MolAtom*> *pConn0=&(mConnectivityTable[mvpAtom[i]]);
5868  if(pConn0->size()<2) continue;
5869  for(set<MolAtom*>::const_iterator pos1=pConn0->begin();pos1!=pConn0->end();++pos1)
5870  {
5871  set<MolAtom*>::const_iterator pos2=pos1;
5872  pos2++;
5873  for(;pos2!=pConn0->end();++pos2)
5874  {
5875  VFN_DEBUG_MESSAGE("Molecule::BuildStretchModeBondAngle():"<<i<<","<<*pos1<<","<<*pos2,10)
5876  //Do we have a bond angle restraint corresponding to these atoms ?
5877  MolBondAngle *pMolBondAngle=0;
5878  for(vector<MolBondAngle*>::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos)
5879  {
5880  if(&((*pos)->GetAtom2())==mvpAtom[i])
5881  {
5882  if( ((&((*pos)->GetAtom1())==*pos1)&&(&((*pos)->GetAtom3())==*pos2))
5883  ||((&((*pos)->GetAtom1())==*pos2)&&(&((*pos)->GetAtom3())==*pos1)))
5884  {
5885  pMolBondAngle=*pos;
5886  break;
5887  }
5888  }
5889  }
5890  for(unsigned int j=1;j<=2;++j)
5891  {
5892  const set<MolAtom*> *pConn;
5893  if(j==1)
5894  {
5895  pConn=&(mConnectivityTable[*pos1]);
5897  *mvpAtom[i],
5898  **pos1,
5899  pMolBondAngle));
5900  mvStretchModeBondAngle.back().mvRotatedAtomList.insert(*pos1);
5901  }
5902  else
5903  {
5904  pConn=&(mConnectivityTable[*pos2]);
5906  *mvpAtom[i],
5907  **pos2,
5908  pMolBondAngle));
5909  mvStretchModeBondAngle.back().mvRotatedAtomList.insert(*pos2);
5910  }
5911  mvStretchModeBondAngle.back().mvRotatedAtomList.insert(mvpAtom[i]);
5912 
5913  for(set<MolAtom*>::const_iterator pos=pConn->begin();pos!=pConn->end();++pos)
5914  {
5915  if(*pos==mvpAtom[i]) continue;
5917  mvStretchModeBondAngle.back().mvRotatedAtomList);
5918  }
5919  //if(j==1)mvStretchModeBondAngle.back().mvRotatedAtomList.erase(*pos2);
5920  //if(j==2)mvStretchModeBondAngle.back().mvRotatedAtomList.erase(*pos1);
5921  mvStretchModeBondAngle.back().mvRotatedAtomList.erase(mvpAtom[i]);
5922 
5923  if( (mvStretchModeBondAngle.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2))
5924  ||(mvStretchModeBondAngle.back().mvRotatedAtomList.size()==0))
5925  {
5926  #ifdef __DEBUG__
5927  cout<<"Rejecting StretchModeBondAngle ";mvStretchModeBondAngle.back().Print(cout);cout<<endl;
5928  #endif
5929  mvStretchModeBondAngle.pop_back();
5930  }
5931  else
5932  {
5933  if((j==1) &&(mvStretchModeBondAngle.back().mvRotatedAtomList.find(*pos2)
5934  !=mvStretchModeBondAngle.back().mvRotatedAtomList.end()))
5935  {
5936  #if 1//def __DEBUG__
5937  cout<<"Rejecting StretchModeBondAngle (ring) ";mvStretchModeBondAngle.back().Print(cout);cout<<endl;
5938  #endif
5939  mvStretchModeBondAngle.pop_back();
5940  }
5941  if((j==2) &&(mvStretchModeBondAngle.back().mvRotatedAtomList.find(*pos1)
5942  !=mvStretchModeBondAngle.back().mvRotatedAtomList.end()))
5943  {
5944  #if 1//def __DEBUG__
5945  cout<<"Rejecting StretchModeBondAngle (ring) ";mvStretchModeBondAngle.back().Print(cout);cout<<endl;
5946  #endif
5947  mvStretchModeBondAngle.pop_back();
5948  }
5949  }
5950 
5951  }
5952  }
5953  }
5954  }
5955  TAU_PROFILE_STOP(timer1);
5956  // find rigid groups broken by each mode
5957  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
5958  pos!=mvStretchModeBondAngle.end();)
5959  {
5960  TAU_PROFILE_START(timer5);
5961  bool keep=true;
5962  for(vector<RigidGroup*>::const_iterator group=mvRigidGroup.begin();
5963  group!=mvRigidGroup.end();++group)
5964  {
5965  unsigned long ct=0;
5966  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
5967  ct += pos->mvRotatedAtomList.count(*at);
5968  if(ct>0)
5969  {
5970  // Add the origin atom, which does not move relatively to the rotated atoms
5971  ct += (*group)->count(pos->mpAtom1);
5972  if(ct!=(*group)->size())
5973  {
5974  keep=false;
5975  #ifdef __DEBUG__
5976  pos->Print(cout);
5977  cout<<" Breaks Rigid Group:";
5978  for(set<MolAtom *>::const_iterator at=(*group)->begin();at!=(*group)->end();++at)
5979  cout<<(*at)->GetName()<<" ";
5980  cout<<endl;
5981  #endif
5982  break;
5983  }
5984  }
5985  }
5986  if(keep) ++pos;
5987  else pos=mvStretchModeBondAngle.erase(pos);
5988  TAU_PROFILE_STOP(timer5);
5989  }
5990  // Generate 5 completely random atomic positions
5991  this->SaveParamSet(mLocalParamSet);
5992  unsigned long paramSetRandom[5];
5993  for(unsigned long i=0;i<5;++i)
5994  {
5995  for(vector<MolAtom*>::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos)
5996  {
5997  (*pos)->SetX(100.*rand()/(REAL) RAND_MAX);
5998  (*pos)->SetY(100.*rand()/(REAL) RAND_MAX);
5999  (*pos)->SetZ(100.*rand()/(REAL) RAND_MAX);
6000  }
6001  paramSetRandom[i]=this->CreateParamSet();
6002  }
6003  // find bond lengths broken by each mode
6004  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
6005  pos!=mvStretchModeBondAngle.end();)
6006  {
6007  TAU_PROFILE_START(timer2);
6008  bool keep=true;
6009  pos->mvpBrokenBond.clear();
6010  for(vector<MolBond*>::const_iterator r=mvpBond.begin();r!=mvpBond.end();++r)
6011  {
6012  unsigned int ct=0;
6013  for(set<MolAtom *>::const_iterator at=pos->mvRotatedAtomList.begin();
6014  at!=pos->mvRotatedAtomList.end();++at)
6015  {
6016  if(*at==&((*r)->GetAtom1())) ct++;
6017  if(*at==&((*r)->GetAtom2())) ct++;
6018  }
6019  bool broken=true;
6020  // If we moved either both or non of the bond atom, the bond length is unchanged.
6021  if((ct==0)||(ct==2)) broken=false;
6022  if(broken)
6023  {// Make sure with derivatives
6024  REAL d=0;
6025  for(unsigned long i=0;i<5;++i)
6026  {
6027  this->RestoreParamSet(paramSetRandom[i]);
6028  pos->CalcDeriv(false);
6029  (*r)->GetLogLikelihood(true,true);
6030  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6031  if(d>0.01) break;
6032  }
6033  if(abs(d)<=0.01) broken=false;
6034  }
6035  if(broken) pos->mvpBrokenBond.insert(make_pair(*r,0));
6036  }
6037  if(mFlexModel.GetChoice()==2)
6038  {
6039  if(pos->mvpBrokenBond.size()>0) keep=false;
6040  }
6041  if(keep) ++pos;
6042  else pos=mvStretchModeBondAngle.erase(pos);
6043  TAU_PROFILE_STOP(timer2);
6044  }
6045  // find bond angles broken by each mode
6046  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
6047  pos!=mvStretchModeBondAngle.end();)
6048  {
6049  TAU_PROFILE_START(timer3);
6050  bool keep=true;
6051  pos->mvpBrokenBondAngle.clear();
6052  for(vector<MolBondAngle*>::const_iterator r=mvpBondAngle.begin();r!=mvpBondAngle.end();++r)
6053  {
6054  unsigned int ct=0;
6055  for(set<MolAtom *>::const_iterator at=pos->mvRotatedAtomList.begin();
6056  at!=pos->mvRotatedAtomList.end();++at)
6057  {
6058  if(*at==&((*r)->GetAtom1())) ct++;
6059  if(*at==&((*r)->GetAtom2())) ct++;
6060  if(*at==&((*r)->GetAtom3())) ct++;
6061  }
6062  bool broken=true;
6063  if(ct==0) broken=false;
6064  if(ct==3) broken=false;
6065  if(broken)
6066  {// Make sure with derivatives
6067  REAL d=0;
6068  for(unsigned long i=0;i<5;++i)
6069  {
6070  this->RestoreParamSet(paramSetRandom[i]);
6071  pos->CalcDeriv(false);
6072  (*r)->GetLogLikelihood(true,true);
6073  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6074  if(d>0.01) break;
6075  }
6076  if(abs(d)<=0.01) broken=false;
6077  }
6078  if(broken) pos->mvpBrokenBondAngle.insert(make_pair(*r,0));
6079  }
6080  if(mFlexModel.GetChoice()==2)
6081  {
6082  int nb=pos->mvpBrokenBond.size();
6083  if(pos->mpBondAngle!=0) nb -= 1;
6084  if(nb>0) keep=false;
6085  }
6086  if(keep) ++pos;
6087  else pos=mvStretchModeBondAngle.erase(pos);
6088  TAU_PROFILE_STOP(timer3);
6089  }
6090  // find dihedral angles broken by each mode
6091  for(list<StretchModeBondAngle>::iterator pos=mvStretchModeBondAngle.begin();
6092  pos!=mvStretchModeBondAngle.end();)
6093  {
6094  TAU_PROFILE_START(timer4);
6095  bool keep=true;
6096  pos->mvpBrokenDihedralAngle.clear();
6097  for(vector<MolDihedralAngle*>::const_iterator r=mvpDihedralAngle.begin();r!=mvpDihedralAngle.end();++r)
6098  {
6099  unsigned int ct=0;
6100  for(set<MolAtom *>::const_iterator at=pos->mvRotatedAtomList.begin();
6101  at!=pos->mvRotatedAtomList.end();++at)
6102  {
6103  if(*at==&((*r)->GetAtom1())) ct++;
6104  if(*at==&((*r)->GetAtom2())) ct++;
6105  if(*at==&((*r)->GetAtom3())) ct++;
6106  if(*at==&((*r)->GetAtom4())) ct++;
6107  }
6108  bool broken=true;
6109  if(ct==0) broken=false;
6110  if(ct==4) broken=false;
6111  if(broken)
6112  {// Make sure with derivatives
6113  REAL d=0;
6114  for(unsigned long i=0;i<5;++i)
6115  {
6116  this->RestoreParamSet(paramSetRandom[i]);
6117  pos->CalcDeriv(false);
6118  (*r)->GetLogLikelihood(true,true);
6119  d += abs((*r)->GetDeriv(pos->mDerivXYZ));
6120  if(d>0.01) break;
6121  }
6122  if(abs(d)<=0.01) broken=false;
6123  }
6124  if(broken) pos->mvpBrokenDihedralAngle.insert(make_pair(*r,0));
6125  }
6126  if(mFlexModel.GetChoice()==2)
6127  {
6128  if(pos->mvpBrokenDihedralAngle.size()>0) keep=false;
6129  }
6130  if(keep) ++pos;
6131  else pos=mvStretchModeBondAngle.erase(pos);
6132  TAU_PROFILE_STOP(timer4);
6133  }
6134  this->RestoreParamSet(mLocalParamSet);
6135  for(unsigned long i=0;i<5;++i) this->ClearParamSet(paramSetRandom[i]);
6136  #ifdef __DEBUG__
6137  cout<<"List of Bond Angle stretch modes"<<endl;
6138  for(list<StretchModeBondAngle>::const_iterator pos=mvStretchModeBondAngle.begin();
6139  pos!=mvStretchModeBondAngle.end();++pos)
6140  {
6141  cout<<" Angle:"<<pos->mpAtom0->GetName()<<"-"
6142  <<pos->mpAtom1->GetName()<<"-"
6143  <<pos->mpAtom2->GetName()<<", Rotated Atoms: ";
6144  for(set<MolAtom*>::const_iterator atom=pos->mvRotatedAtomList.begin();
6145  atom!=pos->mvRotatedAtomList.end();++atom)
6146  {
6147  cout<<(*atom)->GetName()<<",";
6148  }
6149  if(pos->mpBondAngle!=0) cout<< " ; restrained to angle="<<pos->mpBondAngle->GetAngle0()*RAD2DEG
6150  <<"�, sigma="<<pos->mpBondAngle->GetAngleSigma()*RAD2DEG
6151  <<"�, delta="<<pos->mpBondAngle->GetAngleDelta()*RAD2DEG<<"�";
6152  if(pos->mvpBrokenBond.size()>0)
6153  {
6154  cout<<endl<<" Broken bonds:";
6155  for(map<const MolBond*,REAL>::const_iterator bond=pos->mvpBrokenBond.begin();