double ContactAlignedMatrix::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const { double f_dot, dot_df; std::vector<double> orient0(ncomp), orient1(ncomp); getOrientationVector( myatoms.getIndex(0), true, orient0 ); getOrientationVector( myatoms.getIndex(1), true, orient1 ); double dot=0; for(unsigned k=2;k<orient0.size();++k) dot+=orient0[k]*orient1[k]; f_dot=0.5*( 1 + dot ); dot_df=0.5; // Retrieve the weight of the connection double weight = myatoms.getValue(0); myatoms.setValue(0,1.0); if( !doNotCalculateDerivatives() ){ Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).calculate( distance.modulo(), dfunc ); addAtomDerivatives( 1, 0, (-dfunc)*f_dot*distance, myatoms ); addAtomDerivatives( 1, 1, (+dfunc)*f_dot*distance, myatoms ); myatoms.addBoxDerivatives( 1, (-dfunc)*f_dot*Tensor(distance,distance) ); // Add derivatives of orientation for(unsigned k=2;k<orient0.size();++k){ orient0[k]*=sw*dot_df; orient1[k]*=sw*dot_df; } addOrientationDerivatives( 1, 0, orient1, myatoms ); addOrientationDerivatives( 1, 1, orient0, myatoms ); } return weight*f_dot; }
double ContactMatrix::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const { Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) - ncol_t ).calculate( distance.modulo(), dfunc ); if( !doNotCalculateDerivatives() ) { Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) - ncol_t ).calculate( distance.modulo(), dfunc ); addAtomDerivatives( 1, 0, (-dfunc)*distance, myatoms ); addAtomDerivatives( 1, 1, (+dfunc)*distance, myatoms ); myatoms.addBoxDerivatives( 1, (-dfunc)*Tensor(distance,distance) ); } return sw; }
double TopologyMatrix::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const { HistogramBead bead; bead.isNotPeriodic(); bead.setKernelType( kerneltype ); // Initialise to zero density on all bins for(unsigned bin=0; bin<maxbins; ++bin) myatoms.setValue(bin+1,0); // Calculate whether or not atoms 1 and 2 are within cutoff (can use delta here as pbc are done in atom setup) Vector d1 = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); double d1_len = d1.modulo(); d1 = d1 / d1_len; // Convert vector into director AtomNumber a1 = myatoms.getAbsoluteIndex( 0 ); AtomNumber a2 = myatoms.getAbsoluteIndex( 1 ); for(unsigned i=2; i<myatoms.getNumberOfAtoms(); ++i) { AtomNumber a3 = myatoms.getAbsoluteIndex( i ); if( a3!=a1 && a3!=a2 ) calculateForThreeAtoms( i, d1, d1_len, bead, myatoms ); } // std::vector<double> binvals( 1+maxbins ); for(unsigned i=1;i<maxbins;++i) binvals[i]=myatoms.getValue(i); // unsigned ii; double fdf; //std::cout<<"HELLO DENSITY "<<myatoms.getIndex(0)<<" "<<myatoms.getIndex(1)<<" "<<transformStoredValues( binvals, ii, fdf )<<std::endl; // Now find the element for which the density is maximal unsigned vout=2; double max=myatoms.getValue( 2 ); for(unsigned i=3; i<myatoms.getUnderlyingMultiValue().getNumberOfValues()-1; ++i) { if( myatoms.getValue(i)>max ) { max=myatoms.getValue(i); vout=i; } } // Calculate value and derivative of switching function between atoms 1 and 2 double dfuncl, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).calculate( d1_len, dfuncl ); // Transform the density double df, tsw = threshold_switch.calculate( max, df ); if( !doNotCalculateDerivatives() ) { // Factor of d1_len is required here because d1 is normalized d1 *= d1_len; addAtomDerivatives( 2+maxbins, 0, -dfuncl*d1, myatoms ); addAtomDerivatives( 2+maxbins, 1, dfuncl*d1, myatoms ); myatoms.addBoxDerivatives( 2+maxbins, (-dfuncl)*Tensor(d1,d1) ); // Update active atoms so that next bit works updateActiveAtoms( myatoms ); // Now finish caclulation of derivatives MultiValue& myvals=myatoms.getUnderlyingMultiValue(); for(unsigned jd=0; jd<myvals.getNumberActive(); ++jd) { unsigned ider=myvals.getActiveIndex(jd); myvals.addDerivative( 1, ider, sw*df*max*myvals.getDerivative( vout, ider ) + tsw*myvals.getDerivative( 2+maxbins, ider ) ); } } return sw*tsw; }
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; }
void ContactAlignedMatrix::calculateWeight( const unsigned& taskCode, multicolvar::AtomValuePack& myatoms ) const { Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).calculate( distance.modulo(), dfunc ); myatoms.setValue(0,sw); }
double ContactMatrix::calculateWeight( const unsigned& taskCode, const double& weight, multicolvar::AtomValuePack& myatoms ) const { Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); if( distance.modulo2()<switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) - ncol_t ).get_dmax2() ) return 1.0; return 0.0; }
void TopologyMatrix::calculateForThreeAtoms( const unsigned& iat, const Vector& d1, const double& d1_len, HistogramBead& bead, multicolvar::AtomValuePack& myatoms ) const { // Calculate if there are atoms in the cylinder (can use delta here as pbc are done in atom setup) Vector d2 = getSeparation( myatoms.getPosition(0), myatoms.getPosition(iat) ); // Now calculate projection of d2 on d1 double proj=dotProduct(d2,d1); // This tells us if we are outside the end of the cylinder double excess = proj - d1_len; // Return if we are outside of the cylinder as calculated based on excess if( excess>low_sf( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).get_dmax() ) return; // Find the length of the cylinder double binw = binw_mat( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ); double lcylinder = (std::floor( d1_len / binw ) + 1)*binw; // Return if the projection is outside the length of interest if( proj<-bead.getCutoff() || proj>(lcylinder+bead.getCutoff()) ) return; // Calculate the excess swiching function double edf, eval = low_sf( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).calculate( excess, edf ); // Calculate the projection on the perpendicular distance from the center of the tube double cm = d2.modulo2() - proj*proj; // Now calculate the density in the cylinder if( cm<cylinder_sw( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).get_dmax2() ) { double dfuncr, val = cylinder_sw( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).calculateSqr( cm, dfuncr ); double cellv = cell_volume( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ); Vector dc1, dc2, dc3, dd1, dd2, dd3, de1, de2, de3; if( !doNotCalculateDerivatives() ) { Tensor d1_a1; // Derivative of director connecting atom1 - atom2 wrt the position of atom 1 d1_a1(0,0) = ( -(d1[1]*d1[1]+d1[2]*d1[2])/d1_len ); // dx/dx d1_a1(0,1) = ( d1[0]*d1[1]/d1_len ); // dx/dy d1_a1(0,2) = ( d1[0]*d1[2]/d1_len ); // dx/dz d1_a1(1,0) = ( d1[1]*d1[0]/d1_len ); // dy/dx d1_a1(1,1) = ( -(d1[0]*d1[0]+d1[2]*d1[2])/d1_len ); // dy/dy d1_a1(1,2) = ( d1[1]*d1[2]/d1_len ); d1_a1(2,0) = ( d1[2]*d1[0]/d1_len ); d1_a1(2,1) = ( d1[2]*d1[1]/d1_len ); d1_a1(2,2) = ( -(d1[1]*d1[1]+d1[0]*d1[0])/d1_len ); // Calculate derivatives of dot product dd1 = matmul(d2, d1_a1) - d1; dd2 = matmul(d2, -d1_a1); dd3 = d1; // Calculate derivatives of cross product dc1 = dfuncr*( -d2 - proj*dd1 ); dc2 = dfuncr*( -proj*dd2 ); dc3 = dfuncr*( d2 - proj*dd3 ); // Calculate derivatives of excess de1 = edf*excess*( dd1 + d1 ); de2 = edf*excess*( dd2 - d1 ); de3 = edf*excess*dd3; } Vector pos1 = myatoms.getPosition(0) + d1_len*d1; Vector pos2 = myatoms.getPosition(0) + d2; Vector g1derivf,g2derivf,lderivf; Tensor vir; for(unsigned bin=0; bin<maxbins; ++bin) { bead.set( bin*binw, (bin+1)*binw, sigma ); if( proj<(bin*binw-bead.getCutoff()) || proj>binw*(bin+1)+bead.getCutoff() ) continue; double der, contr=bead.calculateWithCutoff( proj, der ) / cellv; der /= cellv; myatoms.addValue( 2+bin, contr*val*eval ); if( !doNotCalculateDerivatives() ) { g1derivf=contr*eval*dc1 + val*eval*der*dd1 + contr*val*de1; addAtomDerivatives( 2+bin, 0, g1derivf, myatoms ); g2derivf=contr*eval*dc2 + val*eval*der*dd2 + contr*val*de2; addAtomDerivatives( 2+bin, 1, g2derivf, myatoms ); lderivf=contr*eval*dc3 + val*eval*der*dd3 + contr*val*de3; addAtomDerivatives( 2+bin, iat, lderivf, myatoms ); // Virial vir = -Tensor( myatoms.getPosition(0), g1derivf ) - Tensor( pos1, g2derivf ) - Tensor( pos2, lderivf ); myatoms.addBoxDerivatives( 2+bin, vir ); } } } }