void Steinhardt::calculateVector( multicolvar::AtomValuePack& myatoms ) const { double dfunc, dpoly_ass, md, tq6, itq6, real_z, imag_z; Vector dz, myrealvec, myimagvec, real_dz, imag_dz; // The square root of -1 std::complex<double> ii( 0.0, 1.0 ), dp_x, dp_y, dp_z; unsigned ncomp=2*tmom+1; double sw, poly_ass, d2, dlen, nbond=0.0; std::complex<double> powered; for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){ Vector& distance=myatoms.getPosition(i); // getSeparation( myatoms.getPosition(0), myatoms.getPosition(i) ); if ( (d2=distance[0]*distance[0])<rcut2 && (d2+=distance[1]*distance[1])<rcut2 && (d2+=distance[2]*distance[2])<rcut2) { dlen = sqrt(d2); sw = switchingFunction.calculate( dlen, dfunc ); nbond += sw; // Accumulate total number of bonds double dlen3 = d2*dlen; // Store derivatives of weight addAtomDerivatives( -1, 0, (-dfunc)*distance, myatoms ); addAtomDerivatives( -1, i, (+dfunc)*distance, myatoms ); myatoms.addTemporyBoxDerivatives( (-dfunc)*Tensor( distance,distance ) ); // Do stuff for m=0 poly_ass=deriv_poly( 0, distance[2]/dlen, dpoly_ass ); // Derivatives of z/r wrt x, y, z dz = -( distance[2] / dlen3 )*distance; dz[2] += (1.0 / dlen); // Derivative wrt to the vector connecting the two atoms myrealvec = (+sw)*dpoly_ass*dz + poly_ass*(+dfunc)*distance; // Accumulate the derivatives addAtomDerivatives( 2 + tmom, 0, -myrealvec, myatoms ); addAtomDerivatives( 2 + tmom, i, myrealvec, myatoms); myatoms.addBoxDerivatives( 2 + tmom, Tensor( -myrealvec,distance ) ); // And store the vector function myatoms.addValue( 2 + tmom, sw*poly_ass ); // The complex number of which we have to take powers std::complex<double> com1( distance[0]/dlen ,distance[1]/dlen ); // Do stuff for all other m values for(unsigned m=1;m<=tmom;++m){ // Calculate Legendre Polynomial poly_ass=deriv_poly( m, distance[2]/dlen, dpoly_ass ); // Calculate powe of complex number powered=pow(com1,m-1); md=static_cast<double>(m); // Real and imaginary parts of z real_z = real(com1*powered); imag_z = imag(com1*powered ); // Calculate steinhardt parameter tq6=poly_ass*real_z; // Real part of steinhardt parameter itq6=poly_ass*imag_z; // Imaginary part of steinhardt parameter // Derivatives wrt ( x/r + iy )^m dp_x = md*powered*( (1.0/dlen)-(distance[0]*distance[0])/dlen3-ii*(distance[0]*distance[1])/dlen3 ); dp_y = md*powered*( ii*(1.0/dlen)-(distance[0]*distance[1])/dlen3-ii*(distance[1]*distance[1])/dlen3 ); dp_z = md*powered*( -(distance[0]*distance[2])/dlen3-ii*(distance[1]*distance[2])/dlen3 ); // Derivatives of real and imaginary parts of above real_dz[0] = real( dp_x ); real_dz[1] = real( dp_y ); real_dz[2] = real( dp_z ); imag_dz[0] = imag( dp_x ); imag_dz[1] = imag( dp_y ); imag_dz[2] = imag( dp_z ); // Complete derivative of steinhardt parameter myrealvec = (+sw)*dpoly_ass*real_z*dz + (+dfunc)*distance*tq6 + (+sw)*poly_ass*real_dz; myimagvec = (+sw)*dpoly_ass*imag_z*dz + (+dfunc)*distance*itq6 + (+sw)*poly_ass*imag_dz; // Real part myatoms.addValue( 2+tmom+m, sw*tq6 ); addAtomDerivatives( 2+tmom+m, 0, -myrealvec, myatoms ); addAtomDerivatives( 2+tmom+m, i, myrealvec, myatoms ); myatoms.addBoxDerivatives( 2+tmom+m, Tensor( -myrealvec,distance ) ); // Imaginary part myatoms.addValue( 2+ncomp+tmom+m, sw*itq6 ); addAtomDerivatives( 2+ncomp+tmom+m, 0, -myimagvec, myatoms ); addAtomDerivatives( 2+ncomp+tmom+m, i, myimagvec, myatoms ); myatoms.addBoxDerivatives( 2+ncomp+tmom+m, Tensor( -myimagvec,distance ) ); // Store -m part of vector double pref=pow(-1.0,m); // -m part of vector is just +m part multiplied by (-1.0)**m and multiplied by complex // conjugate of Legendre polynomial // Real part myatoms.addValue( 2+tmom-m, pref*sw*tq6 ); addAtomDerivatives( 2+tmom-m, 0, -pref*myrealvec, myatoms ); addAtomDerivatives( 2+tmom-m, i, pref*myrealvec, myatoms ); myatoms.addBoxDerivatives( 2+tmom-m, pref*Tensor( -myrealvec,distance ) ); // Imaginary part myatoms.addValue( 2+ncomp+tmom-m, -pref*sw*itq6 ); addAtomDerivatives( 2+ncomp+tmom-m, 0, pref*myimagvec, myatoms ); addAtomDerivatives( 2+ncomp+tmom-m, i, -pref*myimagvec, myatoms ); myatoms.addBoxDerivatives( 2+ncomp+tmom-m, pref*Tensor( myimagvec,distance ) ); } } } // Normalize updateActiveAtoms( myatoms ); for(unsigned i=0;i<getNumberOfComponentsInVector();++i) myatoms.getUnderlyingMultiValue().quotientRule( 2+i, nbond, 2+i ); }
void Steinhardt::calculateVector(){ double dfunc, dpoly_ass, md, tq6, itq6, real_z, imag_z; Vector distance, dz, myrealvec, myimagvec, real_dz, imag_dz; // The square root of -1 std::complex<double> ii( 0.0, 1.0 ), dp_x, dp_y, dp_z; double sw, poly_ass, dlen, nbond=0.0; std::complex<double> powered; for(unsigned i=1;i<getNAtoms();++i){ distance=getSeparation( getPosition(0), getPosition(i) ); dlen=distance.modulo(); sw = switchingFunction.calculate( dlen, dfunc ); if( sw>=getTolerance() ){ nbond += sw; // Accumulate total number of bonds double dlen3 = dlen*dlen*dlen; // Store derivatives of weight MultiColvarBase::addAtomsDerivatives( 0, getAtomIndex(0), (-dfunc)*distance ); MultiColvarBase::addAtomsDerivatives( 0, getAtomIndex(i), (+dfunc)*distance ); MultiColvarBase::addBoxDerivatives( 0, (-dfunc)*Tensor( distance,distance ) ); // Do stuff for m=0 poly_ass=deriv_poly( 0, distance[2]/dlen, dpoly_ass ); // Derivatives of z/r wrt x, y, z dz = -( distance[2] / dlen3 )*distance; dz[2] += (1.0 / dlen); // Derivative wrt to the vector connecting the two atoms myrealvec = (+sw)*dpoly_ass*dz + poly_ass*(+dfunc)*distance; // Accumulate the derivatives addAtomsDerivative( tmom, 0, -myrealvec ); addAtomsDerivative( tmom, i, myrealvec ); addBoxDerivatives( tmom, Tensor( -myrealvec,distance ) ); // And store the vector function addComponent( tmom, sw*poly_ass ); // The complex number of which we have to take powers std::complex<double> com1( distance[0]/dlen ,distance[1]/dlen ); // Do stuff for all other m values for(unsigned m=1;m<=tmom;++m){ // Calculate Legendre Polynomial poly_ass=deriv_poly( m, distance[2]/dlen, dpoly_ass ); // Calculate powe of complex number powered=pow(com1,m-1); md=static_cast<double>(m); // Real and imaginary parts of z real_z = real(com1*powered); imag_z = imag(com1*powered ); // Calculate steinhardt parameter tq6=poly_ass*real_z; // Real part of steinhardt parameter itq6=poly_ass*imag_z; // Imaginary part of steinhardt parameter // Derivatives wrt ( x/r + iy )^m dp_x = md*powered*( (1.0/dlen)-(distance[0]*distance[0])/dlen3-ii*(distance[0]*distance[1])/dlen3 ); dp_y = md*powered*( ii*(1.0/dlen)-(distance[0]*distance[1])/dlen3-ii*(distance[1]*distance[1])/dlen3 ); dp_z = md*powered*( -(distance[0]*distance[2])/dlen3-ii*(distance[1]*distance[2])/dlen3 ); // Derivatives of real and imaginary parts of above real_dz[0] = real( dp_x ); real_dz[1] = real( dp_y ); real_dz[2] = real( dp_z ); imag_dz[0] = imag( dp_x ); imag_dz[1] = imag( dp_y ); imag_dz[2] = imag( dp_z ); // Complete derivative of steinhardt parameter myrealvec = (+sw)*dpoly_ass*real_z*dz + (+dfunc)*distance*tq6 + (+sw)*poly_ass*real_dz; myimagvec = (+sw)*dpoly_ass*imag_z*dz + (+dfunc)*distance*itq6 + (+sw)*poly_ass*imag_dz; // Real part addComponent( tmom+m, sw*tq6 ); addAtomsDerivative( tmom+m, 0, -myrealvec ); addAtomsDerivative( tmom+m, i, myrealvec ); addBoxDerivatives( tmom+m, Tensor( -myrealvec,distance ) ); // Imaginary part addImaginaryComponent( tmom+m, sw*itq6 ); addImaginaryAtomsDerivative( tmom+m, 0, -myimagvec ); addImaginaryAtomsDerivative( tmom+m, i, myimagvec ); addImaginaryBoxDerivatives( tmom+m, Tensor( -myimagvec,distance ) ); // Store -m part of vector double pref=pow(-1.0,m); // -m part of vector is just +m part multiplied by (-1.0)**m and multiplied by complex // conjugate of Legendre polynomial // Real part addComponent( tmom-m, pref*sw*tq6 ); addAtomsDerivative( tmom-m, 0, -pref*myrealvec ); addAtomsDerivative( tmom-m, i, pref*myrealvec ); addBoxDerivatives( tmom-m, pref*Tensor( -myrealvec,distance ) ); // Imaginary part addImaginaryComponent( tmom-m, -pref*sw*itq6 ); addImaginaryAtomsDerivative( tmom-m, 0, pref*myimagvec ); addImaginaryAtomsDerivative( tmom-m, i, -pref*myimagvec ); addImaginaryBoxDerivatives( tmom-m, pref*Tensor( myimagvec,distance ) ); } } else { removeAtomRequest( i, sw ); } } // Normalize setElementValue(0, nbond ); updateActiveAtoms(); for(unsigned i=0;i<2*getNumberOfComponentsInVector();++i) quotientRule( 5+i, 0, 5+i ); // Clear tempory stuff clearDerivativesAfterTask(0); }