Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2014-2023 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : #include "vesselbase/VesselRegister.h" 23 : #include "vesselbase/FunctionVessel.h" 24 : #include "vesselbase/ActionWithVessel.h" 25 : #include "multicolvar/ActionVolume.h" 26 : #include "VectorMultiColvar.h" 27 : #include "Gradient.h" 28 : 29 : namespace PLMD { 30 : namespace crystallization { 31 : 32 : class GradientVessel : public vesselbase::FunctionVessel { 33 : private: 34 : bool isdens; 35 : size_t nweights, ncomponents; 36 : std::vector<unsigned> starts; 37 : public: 38 : static void registerKeywords( Keywords& keys ); 39 : static void reserveKeyword( Keywords& keys ); 40 : explicit GradientVessel( const vesselbase::VesselOptions& da ); 41 : std::string value_descriptor(); 42 : void resize(); 43 : void calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const ; 44 : void finish( const std::vector<double>& buffer ); 45 : }; 46 : 47 13787 : PLUMED_REGISTER_VESSEL(GradientVessel,"GRADIENT") 48 : 49 2 : void GradientVessel::registerKeywords( Keywords& keys ) { 50 2 : vesselbase::FunctionVessel::registerKeywords(keys); 51 2 : } 52 : 53 4595 : void GradientVessel::reserveKeyword( Keywords& keys ) { 54 9190 : keys.reserve("vessel","GRADIENT","calculate the gradient"); 55 9190 : keys.addOutputComponent("gradient","GRADIENT","the gradient"); 56 4595 : } 57 : 58 2 : GradientVessel::GradientVessel( const vesselbase::VesselOptions& da ) : 59 2 : FunctionVessel(da) { 60 2 : Gradient* vg=dynamic_cast<Gradient*>( getAction() ); 61 2 : plumed_assert( vg ); 62 2 : isdens=(vg->getPntrToMultiColvar())->isDensity(); 63 2 : nweights = vg->nbins[0] + vg->nbins[1] + vg->nbins[2]; 64 2 : if( (vg->getPntrToMultiColvar())->getNumberOfQuantities()>2 ) { 65 0 : ncomponents = (vg->getPntrToMultiColvar())->getNumberOfQuantities() - 2; 66 : } else { 67 2 : ncomponents = 1; 68 : } 69 : 70 2 : starts.push_back(0); 71 2 : if( vg->nbins[0]>0 ) { 72 2 : starts.push_back( vg->nbins[0] ); 73 2 : if( vg->nbins[1]>0 ) { 74 0 : starts.push_back( vg->nbins[0] + vg->nbins[1] ); 75 0 : if( vg->nbins[2]>0 ) { 76 0 : starts.push_back( nweights ); 77 : } 78 2 : } else if( vg->nbins[2]>0 ) { 79 0 : starts.push_back( nweights ); 80 : } 81 0 : } else if( vg->nbins[1]>0 ) { 82 0 : starts.push_back( vg->nbins[1] ); 83 0 : if( vg->nbins[2]>0 ) { 84 0 : starts.push_back( nweights ); 85 : } 86 0 : } else if( vg->nbins[2]>0 ) { 87 0 : starts.push_back( nweights ); 88 : } 89 2 : } 90 : 91 2 : std::string GradientVessel::value_descriptor() { 92 2 : return "the gradient"; 93 : } 94 : 95 4 : void GradientVessel::resize() { 96 4 : if( getAction()->derivativesAreRequired() ) { 97 2 : unsigned nder=getAction()->getNumberOfDerivatives(); 98 2 : resizeBuffer( (1+nder)*(ncomponents+1)*nweights ); 99 2 : getFinalValue()->resizeDerivatives( nder ); 100 : } else { 101 2 : resizeBuffer( (ncomponents+1)*nweights ); 102 : } 103 4 : } 104 : 105 11600 : void GradientVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const { 106 : unsigned nder; 107 11600 : if( getAction()->derivativesAreRequired() ) { 108 11600 : nder=getAction()->getNumberOfDerivatives(); 109 : } else { 110 : nder=0; 111 : } 112 : unsigned wstart, cstart; 113 11600 : if( ncomponents==1 ) { 114 : cstart=1; 115 : wstart=2; 116 : } else { 117 : cstart=2; 118 0 : wstart=2+ncomponents; 119 : } 120 : 121 58000 : for(unsigned iw=0; iw<nweights; ++iw) { 122 46400 : unsigned xx = (ncomponents+1)*iw; 123 46400 : double weight=myvals.get(wstart+iw); 124 46400 : buffer[bufstart+xx*(nder+1)] += weight; 125 46400 : myvals.chainRule( wstart + iw, xx, 1, 0, 1.0, bufstart, buffer ); 126 92800 : for(unsigned jc=0; jc<ncomponents; ++jc) { 127 46400 : double colvar=myvals.get( cstart + jc ); 128 46400 : buffer[bufstart+(xx+1+jc)*(nder+1) ] += weight*colvar; 129 46400 : myvals.chainRule( cstart + jc, xx + 1 + jc, 1, 0, weight, bufstart, buffer ); 130 46400 : myvals.chainRule( wstart + iw, xx + 1 + jc, 1, 0, colvar, bufstart, buffer ); 131 : } 132 : } 133 11600 : } 134 : 135 232 : void GradientVessel::finish( const std::vector<double>& buffer ) { 136 232 : std::vector<double> val_interm( ncomponents*nweights ); 137 : unsigned nder; 138 232 : if( getAction()->derivativesAreRequired() ) { 139 232 : nder=getAction()->getNumberOfDerivatives(); 140 : } else { 141 : nder=0; 142 : } 143 232 : Matrix<double> der_interm( ncomponents*nweights, nder ); 144 : der_interm=0; 145 : 146 232 : if( isdens ) { 147 580 : for(unsigned iw=0; iw<nweights; ++iw) { 148 464 : val_interm[iw] = buffer[bufstart + 2*iw*(1+nder)]; 149 464 : if( getAction()->derivativesAreRequired() ) { 150 464 : unsigned wstart = bufstart + 2*iw*(nder+1) + 1; 151 75632 : for(unsigned jder=0; jder<nder; ++jder) { 152 75168 : der_interm( iw, jder ) += buffer[ wstart + jder ]; 153 : } 154 : } 155 : } 156 : } else { 157 580 : for(unsigned iw=0; iw<nweights; ++iw) { 158 464 : unsigned xx = (ncomponents+1)*iw; 159 464 : double ww=buffer[bufstart + xx*(1+nder)]; 160 928 : for(unsigned jc=0; jc<ncomponents; ++jc) { 161 464 : val_interm[ iw*ncomponents + jc ] = buffer[bufstart + (xx+1+jc)*(1+nder)] / ww; 162 : } 163 464 : if( getAction()->derivativesAreRequired() ) { 164 464 : unsigned wstart = bufstart + xx*(nder+1) + 1; 165 928 : for(unsigned jc=0; jc<ncomponents; ++jc) { 166 464 : unsigned bstart = bufstart + ( xx + 1 + jc )*(nder+1) + 1; 167 464 : double val = buffer[bufstart + (nder+1)*(xx+1+jc)]; 168 75632 : for(unsigned jder=0; jder<nder; ++jder) { 169 75168 : der_interm( iw*ncomponents + jc, jder ) = (1.0/ww)*buffer[bstart + jder] - (val/(ww*ww))*buffer[wstart + jder]; 170 : } 171 : } 172 : } 173 : } 174 : } 175 : 176 : double tmp, diff2=0.0; 177 : 178 232 : if( getAction()->derivativesAreRequired() ) { 179 : Value* fval=getFinalValue(); 180 464 : for(unsigned j=0; j<starts.size()-1; ++j) { 181 1160 : for(unsigned bin=starts[j]; bin<starts[j+1]; ++bin) { 182 1856 : for(unsigned jc=0; jc<ncomponents; ++jc) { 183 928 : if( bin==starts[j] ) { 184 232 : tmp=val_interm[(starts[j+1]-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; 185 37816 : for(unsigned jder=0; jder<nder; ++jder) { 186 37584 : fval->addDerivative( jder, +2.0*tmp*der_interm( (starts[j+1]-1)*ncomponents + jc, jder) ); 187 37584 : fval->addDerivative( jder, -2.0*tmp*der_interm( bin*ncomponents + jc, jder ) ); 188 : } 189 : } else { 190 696 : tmp=val_interm[(bin-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; 191 113448 : for(unsigned jder=0; jder<nder; ++jder) { 192 112752 : fval->addDerivative( jder, +2.0*tmp*der_interm( (bin-1)*ncomponents + jc, jder) ); 193 112752 : fval->addDerivative( jder, -2.0*tmp*der_interm( bin*ncomponents + jc, jder ) ); 194 : } 195 : } 196 928 : diff2+=tmp*tmp; 197 : } 198 : } 199 : } 200 : } else { 201 0 : for(unsigned j=0; j<starts.size()-1; ++j) { 202 0 : for(unsigned bin=starts[j]; bin<starts[j+1]; ++bin) { 203 0 : for(unsigned jc=0; jc<ncomponents; ++jc) { 204 0 : if( bin==starts[j] ) { 205 0 : tmp=val_interm[(starts[j+1]-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; 206 : } else { 207 0 : tmp=val_interm[(bin-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; 208 : } 209 0 : diff2+=tmp*tmp; 210 : } 211 : } 212 : } 213 : } 214 : setOutputValue( diff2 ); 215 232 : } 216 : 217 : } 218 : }