double NumberOfLinks::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { if( getBaseMultiColvar(0)->getNumberOfQuantities()<3 ) return 1.0; unsigned ncomp=getBaseMultiColvar(0)->getNumberOfQuantities(); std::vector<double> orient0( ncomp ), orient1( ncomp ); getVectorForTask( myatoms.getIndex(0), true, orient0 ); getVectorForTask( myatoms.getIndex(1), true, orient1 ); double dot=0; for(unsigned k=2;k<orient0.size();++k){ dot+=orient0[k]*orient1[k]; } if( !doNotCalculateDerivatives() ){ unsigned nder=myatoms.getNumberOfDerivatives(); //getNumberOfDerivatives(); MultiValue myder0(ncomp,nder), myder1(ncomp,nder); getVectorDerivatives( myatoms.getIndex(0), true, myder0 ); mergeVectorDerivatives( 1, 2, orient1.size(), myatoms.getIndex(0), orient1, myder0, myatoms ); getVectorDerivatives( myatoms.getIndex(1), true, myder1 ); mergeVectorDerivatives( 1, 2, orient0.size(), myatoms.getIndex(1), orient0, myder1, myatoms ); } return dot; }
double InterMolecularTorsions::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const { Vector v1, v2, dv1, dv2, dconn, conn = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); // Retrieve vectors std::vector<double> orient0( 5 ), orient1( 5 ); getInputData( 0, true, myatoms, orient0 ); getInputData( 1, true, myatoms, orient1 ); for(unsigned i=0; i<3; ++i) { v1[i]=orient0[2+i]; v2[i]=orient1[2+i]; } if( getBaseMultiColvar(0)->getNumberOfQuantities()<3 ) return 1.0; // Evaluate angle Torsion t; double angle = t.compute( v1, conn, v2, dv1, dconn, dv2 ); for(unsigned i=0; i<3; ++i) { orient0[i+2]=dv1[i]; orient1[i+2]=dv2[i]; } // And accumulate derivatives if( !doNotCalculateDerivatives() ) { MultiValue& myder0=getInputDerivatives( 0, true, myatoms ); mergeInputDerivatives( 1, 2, orient1.size(), 0, orient0, myder0, myatoms ); MultiValue& myder1=getInputDerivatives( 1, true, myatoms ); mergeInputDerivatives( 1, 2, orient0.size(), 1, orient1, myder1, myatoms ); addAtomDerivatives( 1, 0, -dconn, myatoms ); addAtomDerivatives( 1, 1, dconn, myatoms ); myatoms.addBoxDerivatives( 1, -extProduct( conn, dconn ) ); } return angle; }
OrientationSphere::OrientationSphere(const ActionOptions&ao): Action(ao), MultiColvarFunction(ao) { // Resize everything that stores a vector now that we know the // number of components unsigned ncomponents=getBaseMultiColvar(0)->getNumberOfQuantities() - 5; catom_orient.resize( ncomponents ); catom_der.resize( ncomponents ); this_orient.resize( ncomponents ); // Weight of this does not have derivatives weightHasDerivatives=false; // Read in the switching function std::string sw, errors; parse("SWITCH",sw); if(sw.length()>0){ switchingFunction.set(sw,errors); } else { double r_0=-1.0, d_0; int nn, mm; parse("NN",nn); parse("MM",mm); parse("R_0",r_0); parse("D_0",d_0); if( r_0<0.0 ) error("you must set a value for R_0"); switchingFunction.set(nn,mm,r_0,d_0); } log.printf(" degree of overlap in orientation between central molecule and those within %s\n",( switchingFunction.description() ).c_str() ); // Set the link cell cutoff setLinkCellCutoff( 2.*switchingFunction.inverse( getTolerance() ) ); // Finish the setup of the object buildSymmetryFunctionLists(); // And check everything has been read in correctly checkRead(); }
void ClusteringBase::turnOnDerivatives() { // Check base multicolvar isn't density probably other things shouldn't be allowed here as well if( (getAdjacencyVessel()->getMatrixAction())->getNumberOfBaseMultiColvars()>0 ) { if( getBaseMultiColvar(0)->isDensity() ) error("DFS clustering cannot be differentiated if base multicolvar is DENSITY"); } // Ensure that derivatives are turned on in base classes ActionWithInputMatrix::turnOnDerivatives(); }
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 OrientationSphere::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const { // Make sure derivatives for central atom are only calculated once VectorMultiColvar* vv = dynamic_cast<VectorMultiColvar*>( getBaseMultiColvar(0) ); vv->firstcall=true; double d2, sw, value=0, denom=0, dot, f_dot, dot_df, dfunc; unsigned ncomponents=getBaseMultiColvar(0)->getNumberOfQuantities(); unsigned nder=myatoms.getNumberOfDerivatives(); std::vector<double> catom_orient( ncomponents ), this_orient( ncomponents ), catom_der( ncomponents ); Vector catom_pos = myatoms.getPosition(0); getVectorForTask( myatoms.getIndex(0), true, catom_orient ); multicolvar::CatomPack atom0; MultiValue myder0(0,0), myder1(0,0); if( !doNotCalculateDerivatives() ){ myder0.resize( ncomponents,nder ); myder1.resize(ncomponents,nder); atom0=getCentralAtomPackFromInput( myatoms.getIndex(0) ); getVectorDerivatives( myatoms.getIndex(0), true, myder0 ); } for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){ Vector& distance=myatoms.getPosition(i); if ( (d2=distance[0]*distance[0])<rcut2 && (d2+=distance[1]*distance[1])<rcut2 && (d2+=distance[2]*distance[2])<rcut2) { sw = switchingFunction.calculateSqr( d2, dfunc ); getVectorForTask( myatoms.getIndex(i), true, this_orient ); // Calculate the dot product wrt to this position dot=0; for(unsigned k=2;k<catom_orient.size();++k) dot+=catom_orient[k]*this_orient[k]; f_dot = transformDotProduct( dot, dot_df ); if( !doNotCalculateDerivatives() ){ // N.B. We are assuming here that the imaginary part of the dot product is zero for(unsigned k=2;k<catom_orient.size();++k){ this_orient[k]*=sw*dot_df; catom_der[k]=sw*dot_df*catom_orient[k]; } getVectorDerivatives( myatoms.getIndex(i), true, myder1 ); mergeVectorDerivatives( 1, 2, this_orient.size(), myatoms.getIndex(0), this_orient, myder0, myatoms ); mergeVectorDerivatives( 1, 2, catom_der.size(), myatoms.getIndex(i), catom_der, myder1, myatoms ); myatoms.addComDerivatives( 1, f_dot*(-dfunc)*distance, atom0 ); addAtomDerivatives( 1, i, f_dot*(dfunc)*distance, myatoms ); myatoms.addBoxDerivatives( 1, (-dfunc)*f_dot*Tensor(distance,distance) ); myder1.clearAll(); myatoms.addComDerivatives( -1, (-dfunc)*distance, atom0 ); addAtomDerivatives( -1, i, (dfunc)*distance, myatoms ); myatoms.addTemporyBoxDerivatives( (-dfunc)*Tensor(distance,distance) ); } value += sw*f_dot; denom += sw; } } double rdenom, df2, pref=calculateCoordinationPrefactor( denom, df2 ); if( fabs(denom)>epsilon ){ rdenom = 1.0 / denom; } else { plumed_assert(fabs(value)<epsilon); rdenom=1.0; } // Now divide everything double rdenom2=rdenom*rdenom; updateActiveAtoms( myatoms ); MultiValue& myvals=myatoms.getUnderlyingMultiValue(); for(unsigned i=0;i<myvals.getNumberActive();++i){ unsigned ider=myvals.getActiveIndex(i); double dgd=myvals.getTemporyDerivative(ider); myvals.setDerivative( 1, ider, rdenom*(pref*myvals.getDerivative(1,ider)+value*df2*dgd) - (value*pref*dgd)*rdenom2 ); } return pref*rdenom*value; }