def Energy(self, coordinates3, gradients3=None): """Calculate the energy.""" # . Displacements. v12 = coordinates3.Displacement(self.point1, self.point2) v32 = coordinates3.Displacement(self.point3, self.point2) v34 = coordinates3.Displacement(self.point3, self.point4) # . Get m and n. m = Clone(v12) m.Cross(v32) n = Clone(v32) n.Cross(v34) # . Get the sizes of m and n. msize = m.Norm2() nsize = n.Norm2() # . Normalize m and n. m.Scale(1.0 / msize) n.Scale(1.0 / nsize) # . Get the dot-product. dotfac = m.Dot(n) if dotfac > 1.0: dotfac = 1.0 elif dotfac < -1.0: dotfac = -1.0 # . Get the sign of the angle. sgnfac = 1.0 if v12.Dot(n) < 0.0: sgnfac = -1.0 # . Determine the dihedral. value = sgnfac * math.acos(dotfac) * UNITS_ANGLE_RADIANS_TO_DEGREES # . Get the energy. (f, df) = self.energyModel.Energy(value) # . Derivatives. if gradients3 is not None: df *= UNITS_ANGLE_RADIANS_TO_DEGREES # . Calculate r32. r32 = v32.Norm2() # . Calculate dedi and dedl in m and n respectively. m.Scale(df * r32 / msize) n.Scale(-df * r32 / nsize) # . Calculate some additional factors. fact12 = v12.Dot(v32) / (r32 * r32) fact34 = v34.Dot(v32) / (r32 * r32) # . Gradients for i and l. gradients3.Increment(self.point1, m) gradients3.Increment(self.point4, n) # . Calculate dedj and dedk in v12 and v32 respectively. m.CopyTo(v12) v12.Scale(fact12 - 1.0) v12.AddScaledVector3(-fact34, n) n.CopyTo(v32) v32.Scale(fact34 - 1.0) v32.AddScaledVector3(-fact12, m) # . calculate the gradients. gradients3.Increment(self.point2, v12) gradients3.Increment(self.point3, v32) return (f, value)
def AddLinearConstraint ( self, constraint ): """Add a linear constraint.""" if len ( constraint ) != self.nvariables: raise ValueError ( "Invalid linear constraint length." ) # . Orthogonalize to existing constraints. if self.linearVectors is not None: constraint = Clone ( constraint ) self.linearVectors.ProjectOutOfArray ( constraint ) # . Check to see if the constraint is valid. cnorm2 = constraint.Norm2 ( ) if cnorm2 > 1.0e-10: constraint.Scale ( 1.0 / cnorm2 ) # . Allocate space for new constraints. ncolumns = 1 if self.linearVectors is not None: ncolumns += self.linearVectors.columns newconstraints = Real2DArray.WithExtents ( len ( constraint ), ncolumns ) # . Copy over constraints. if self.linearVectors is not None: for r in range ( self.linearVectors.rows ): for c in range ( self.linearVectors.columns ): newconstraints[r,c] = self.linearVectors[r,c] for r in range ( len ( constraint ) ): newconstraints[r,ncolumns-1] = constraint[r] self.linearVectors = newconstraints # . Determine the linear scalars. self.linearScalars = Real1DArray.WithExtent ( self.linearVectors.columns ) reference = Real1DArray.WithExtent ( self.linearVectors.rows ) if self.rtReference is None: self.system.coordinates3.CopyToArray ( reference ) else: self.rtReference.CopyToArray ( reference ) self.linearVectors.VectorMultiply ( reference, self.linearScalars, 1.0, 0.0, transpose = True ) # . Reset the number of degrees of freedom. self.degreesOfFreedom = self.nvariables - len ( self.linearScalars )