double MultiDomainRMSD::calculate( const std::vector<Vector>& pos, const Pbc& pbc, const bool& squared ){ clearDerivatives(); double totd=0.; Tensor tvirial; std::vector<Vector> mypos; for(unsigned i=0;i<domains.size();++i){ // Must extract appropriate positions here mypos.resize( blocks[i+1] - blocks[i] + 1 ); unsigned n=0; for(unsigned j=blocks[i];j<blocks[i+1];++j){ mypos[n]=pos[j]; n++; } // This actually does the calculation totd += weights[i]*domains[i]->calculate( mypos, pbc, true ); // Must extract derivatives here n=0; for(unsigned j=blocks[i];j<blocks[i+1];++j){ addAtomicDerivatives( j, weights[i]*domains[i]->getAtomDerivative(n) ); n++; } if( domains[i]->getVirial( tvirial ) ){ addBoxDerivatives( weights[i]*tvirial ); } } if( !squared ){ totd=sqrt(totd); double xx=0.5/totd; for(unsigned iat=0;iat<atom_ders.size();iat++) atom_ders[iat]*=xx; if( virialWasSet ) virial*=xx; } return totd; }
double VolumeCavity::calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives ){ // Calculate distance of atom from origin of new coordinate frame Vector datom=pbcDistance( origin, cpos ); double ucontr, uder, vcontr, vder, wcontr, wder; // Calculate contribution from integral along bi bead.set( 0, len_bi, sigma ); double upos=dotProduct( datom, bi ); ucontr=bead.calculate( upos, uder ); double udlen=bead.uboundDerivative( upos ); double uder2 = bead.lboundDerivative( upos ) - udlen; // Calculate contribution from integral along cross bead.set( 0, len_cross, sigma ); double vpos=dotProduct( datom, cross ); vcontr=bead.calculate( vpos, vder ); double vdlen=bead.uboundDerivative( vpos ); double vder2 = bead.lboundDerivative( vpos ) - vdlen; // Calculate contribution from integral along perp bead.set( 0, len_perp, sigma ); double wpos=dotProduct( datom, perp ); wcontr=bead.calculate( wpos, wder ); double wdlen=bead.uboundDerivative( wpos ); double wder2 = bead.lboundDerivative( wpos ) - wdlen; Vector dfd; dfd[0]=uder*vcontr*wcontr; dfd[1]=ucontr*vder*wcontr; dfd[2]=ucontr*vcontr*wder; derivatives[0] = (dfd[0]*bi[0]+dfd[1]*cross[0]+dfd[2]*perp[0]); derivatives[1] = (dfd[0]*bi[1]+dfd[1]*cross[1]+dfd[2]*perp[1]); derivatives[2] = (dfd[0]*bi[2]+dfd[1]*cross[2]+dfd[2]*perp[2]); double tot = ucontr*vcontr*wcontr*jacob_det; // Add reference atom derivatives std::vector<Vector> rderiv(4); dfd[0]=uder2*vcontr*wcontr; dfd[1]=ucontr*vder2*wcontr; dfd[2]=ucontr*vcontr*wder2; Vector dfld; dfld[0]=udlen*vcontr*wcontr; dfld[1]=ucontr*vdlen*wcontr; dfld[2]=ucontr*vcontr*wdlen; rderiv[0] = dfd[0]*matmul(datom,dbi[0]) + dfd[1]*matmul(datom,dcross[0]) + dfd[2]*matmul(datom,dperp[0]) + dfld[0]*dlbi[0] + dfld[1]*dlcross[0] + dfld[2]*dlperp[0] - derivatives; rderiv[1] = dfd[0]*matmul(datom,dbi[1]) + dfd[1]*matmul(datom,dcross[1]) + dfd[2]*matmul(datom,dperp[1]) + dfld[0]*dlbi[1] + dfld[1]*dlcross[1] + dfld[2]*dlperp[1]; rderiv[2] = dfd[0]*matmul(datom,dbi[2]) + dfd[1]*matmul(datom,dcross[2]) + dfd[2]*matmul(datom,dperp[2]) + dfld[0]*dlbi[2] + dfld[1]*dlcross[2] + dfld[2]*dlperp[2]; rderiv[3] = dfld[0]*dlbi[3] + dfld[1]*dlcross[3] + dfld[2]*dlperp[3]; Tensor vir; vir.zero(); vir-=Tensor( cpos,derivatives ); for(unsigned i=0;i<4;++i){ vir -= Tensor( getPosition(i), rderiv[i] ); addReferenceAtomDerivatives( i, rderiv[i] ); } addBoxDerivatives( vir ); return tot; }
double OrientationSphere::compute(){ // Make sure derivatives for central atom are only calculated once VectorMultiColvar* vv = dynamic_cast<VectorMultiColvar*>( getBaseMultiColvar(0) ); vv->firstcall=true; weightHasDerivatives=true; // The weight has no derivatives really double sw, value=0, denom=0, dot, f_dot, dot_df, dfunc; Vector distance; getVectorForBaseTask(0, catom_orient ); for(unsigned i=1;i<getNAtoms();++i){ distance=getSeparation( getPositionOfCentralAtom(0), getPositionOfCentralAtom(i) ); sw = switchingFunction.calculateSqr( distance.modulo2(), dfunc ); if( sw>=getTolerance() ){ getVectorForBaseTask( i, this_orient ); // Calculate the dot product wrt to this position dot=0; for(unsigned k=0;k<catom_orient.size();++k) dot+=catom_orient[k]*this_orient[k]; f_dot = transformDotProduct( dot, dot_df ); // N.B. We are assuming here that the imaginary part of the dot product is zero for(unsigned k=0;k<catom_orient.size();++k){ this_orient[k]*=sw*dot_df; catom_der[k]=sw*dot_df*catom_orient[k]; } // Set the derivatives wrt of the numerator addOrientationDerivatives( 0, this_orient ); addOrientationDerivatives( i, catom_der ); addCentralAtomsDerivatives( 0, 0, f_dot*(-dfunc)*distance ); addCentralAtomsDerivatives( i, 0, f_dot*(dfunc)*distance ); addBoxDerivatives( f_dot*(-dfunc)*Tensor(distance,distance) ); value += sw*f_dot; // Set the derivatives wrt to the numerator addCentralAtomsDerivatives( 0, 1, (-dfunc)*distance ); addCentralAtomsDerivatives( i, 1, (dfunc)*distance ); addBoxDerivativesOfWeight( (-dfunc)*Tensor(distance,distance) ); denom += sw; } } // Now divide everything unsigned nder = getNumberOfDerivatives(); for(unsigned i=0;i<nder;++i){ setElementDerivative( i, getElementDerivative(i)/denom - (value*getElementDerivative(nder+i))/(denom*denom) ); setElementDerivative( nder + i, 0.0 ); } weightHasDerivatives=false; // Weight has no derivatives we just use the holder for weight to store some stuff return value / denom; }
double DRMSD::calc( const std::vector<Vector>& pos, const Pbc& pbc, const bool& squared ){ plumed_dbg_assert( !targets.empty() ); Vector distance; double drmsd=0.; for(std::map< std::pair <unsigned,unsigned> , double>::const_iterator it=targets.begin();it!=targets.end();++it){ unsigned i=getAtomIndex( it->first.first ); unsigned j=getAtomIndex( it->first.second ); if(nopbc){ distance=delta( pos[i] , pos[j] ); } else{ distance=pbc.distance( pos[i] , pos[j] ); } double len = distance.modulo(); double diff = len - it->second; drmsd += diff * diff; addAtomicDerivatives( i, -( diff / len ) * distance ); addAtomicDerivatives( j, ( diff / len ) * distance ); addBoxDerivatives( -( diff / len ) * Tensor(distance,distance) ); } double npairs = static_cast<double>(targets.size()); double idrmsd; if(squared){ drmsd = drmsd / npairs; idrmsd = 2.0 / npairs; } else { drmsd = sqrt( drmsd / npairs ); idrmsd = 1.0/( drmsd * npairs ); } virial *= idrmsd; for(unsigned i=0;i<getNumberOfAtoms();++i){atom_ders[i] *= idrmsd;} return drmsd; }
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); }