1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2013-2021 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 "StoreDataVessel.h"
23 
24 namespace PLMD {
25 namespace vesselbase {
26 
registerKeywords(Keywords & keys)27 void StoreDataVessel::registerKeywords( Keywords& keys ) {
28   Vessel::registerKeywords(keys); keys.remove("LABEL");
29 }
30 
StoreDataVessel(const VesselOptions & da)31 StoreDataVessel::StoreDataVessel( const VesselOptions& da ):
32   Vessel(da),
33   max_lowmem_stash(3),
34   vecsize(0),
35   nspace(0)
36 {
37   ActionWithValue* myval=dynamic_cast<ActionWithValue*>( getAction() );
38   if( !myval ) hasderiv=false;
39   else hasderiv=!myval->doNotCalculateDerivatives();
40 }
41 
addActionThatUses(ActionWithVessel * actionThatUses)42 void StoreDataVessel::addActionThatUses( ActionWithVessel* actionThatUses ) {
43   userActions.push_back( actionThatUses );
44 }
45 
resize()46 void StoreDataVessel::resize() {
47   if( getAction()->lowmem || !getAction()->derivativesAreRequired() ) {
48     nspace = 1;
49     active_der.resize( max_lowmem_stash * ( 1 + getAction()->getNumberOfDerivatives() ) );
50   } else {
51     if( getAction()->getNumberOfDerivatives()>getAction()->maxderivatives ) {
52       error("not enough memory to store derivatives for action " + getAction()->getLabel() + " use LOWMEM option");
53     }
54     nspace = 1 + getAction()->maxderivatives;
55     active_der.resize( getNumberOfStoredValues() * ( 1 + getAction()->maxderivatives ) );
56   }
57   vecsize=getAction()->getNumberOfQuantities();
58   plumed_dbg_assert( vecsize>0 );
59   resizeBuffer( getNumberOfStoredValues()*vecsize*nspace );
60   local_buffer.resize( getNumberOfStoredValues()*vecsize*nspace );
61 }
62 
storeValues(const unsigned & myelem,MultiValue & myvals,std::vector<double> & buffer) const63 void StoreDataVessel::storeValues( const unsigned& myelem, MultiValue& myvals, std::vector<double>& buffer ) const {
64   plumed_dbg_assert( vecsize>0 );
65   unsigned jelem = getAction()->getPositionInCurrentTaskList( myelem ); plumed_dbg_assert( jelem<getNumberOfStoredValues() );
66   unsigned ibuf = bufstart + jelem * vecsize * nspace;
67   for(unsigned icomp=0; icomp<vecsize; ++icomp) {
68     buffer[ibuf] += myvals.get(icomp); ibuf+=nspace;
69   }
70 }
71 
storeDerivatives(const unsigned & myelem,MultiValue & myvals,std::vector<double> & buffer,std::vector<unsigned> & der_list) const72 void StoreDataVessel::storeDerivatives( const unsigned& myelem, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const {
73   plumed_dbg_assert( vecsize>0 && getAction()->derivativesAreRequired() && myelem<getAction()->getFullNumberOfTasks() );
74   unsigned jelem = getAction()->getPositionInCurrentTaskList( myelem );
75 
76   if( getAction()->getFullNumberOfTasks()==getNumberOfStoredValues() ) {
77     der_list[jelem]=myvals.getNumberActive();
78     unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 );
79     for(unsigned j=0; j<myvals.getNumberActive(); ++j) { der_list[kder] = myvals.getActiveIndex(j); kder++; }
80   } else {
81     // This ensures that active indices are gathered correctly if
82     // we have multiple tasks contributing to a stored quantity
83     unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 );
84     for(unsigned j=0; j<myvals.getNumberActive(); ++j) {
85       bool found=false; unsigned jder = myvals.getActiveIndex(j);
86       for(unsigned k=0; k<der_list[jelem]; ++k) {
87         if( der_list[kder+k]==jder ) { found=true; break; }
88       }
89       if(!found) { der_list[kder+der_list[jelem]]=jder; der_list[jelem]++; }
90     }
91   }
92 
93   // Store the values of the components and the derivatives
94   for(unsigned icomp=0; icomp<vecsize; ++icomp) {
95     unsigned ibuf = bufstart + jelem * ( vecsize*nspace ) + icomp*nspace + 1;
96     for(unsigned j=0; j<myvals.getNumberActive(); ++j) {
97       unsigned jder=myvals.getActiveIndex(j);
98       buffer[ibuf] += myvals.getDerivative( icomp, jder ); ibuf++;
99     }
100   }
101 }
102 
retrieveSequentialValue(const unsigned & jelem,const bool & normed,std::vector<double> & values) const103 void StoreDataVessel::retrieveSequentialValue( const unsigned& jelem, const bool& normed, std::vector<double>& values ) const {
104   plumed_dbg_assert( values.size()==vecsize );
105   unsigned ibuf = jelem * vecsize * nspace;
106   for(unsigned i=0; i<vecsize; ++i) { values[i]=local_buffer[ibuf]; ibuf+=nspace; }
107   if( normed && values.size()>2 ) getAction()->normalizeVector( values );
108 }
109 
retrieveValueWithIndex(const unsigned & myelem,const bool & normed,std::vector<double> & values) const110 void StoreDataVessel::retrieveValueWithIndex( const unsigned& myelem, const bool& normed, std::vector<double>& values ) const {
111   plumed_dbg_assert( values.size()==vecsize );
112   unsigned jelem = getStoreIndex( myelem );
113   retrieveSequentialValue( jelem, normed, values );
114 }
115 
retrieveWeightWithIndex(const unsigned & myelem) const116 double StoreDataVessel::retrieveWeightWithIndex( const unsigned& myelem ) const {
117   plumed_dbg_assert( vecsize>0 );
118   unsigned jelem = getStoreIndex( myelem ); unsigned ibuf = jelem * vecsize * nspace; return local_buffer[ibuf];
119 }
120 
retrieveDerivatives(const unsigned & myelem,const bool & normed,MultiValue & myvals)121 void StoreDataVessel::retrieveDerivatives( const unsigned& myelem, const bool& normed, MultiValue& myvals ) {
122   plumed_dbg_assert( myvals.getNumberOfValues()==vecsize && myvals.getNumberOfDerivatives()==getAction()->getNumberOfDerivatives() );
123 
124   myvals.clearAll();
125   if( getAction()->lowmem ) {
126     recalculateStoredQuantity( myelem, myvals );
127     if( normed ) getAction()->normalizeVectorDerivatives( myvals );
128   } else {
129     unsigned jelem = getAction()->getPositionInCurrentTaskList( myelem );
130     // Retrieve the derivatives for elements 0 and 1 - weight and norm
131     for(unsigned icomp=0; icomp<vecsize; ++icomp) {
132       unsigned ibuf = jelem * ( vecsize*nspace ) + icomp*nspace + 1;
133       unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 );
134       for(unsigned j=0; j<active_der[jelem]; ++j) {
135         myvals.addDerivative( icomp, active_der[kder], local_buffer[ibuf] );
136         kder++; ibuf++;
137       }
138     }
139     if( normed ) getAction()->normalizeVectorDerivatives( myvals );
140     // Now ensure appropriate parts of list are activated
141     myvals.emptyActiveMembers();
142     unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 );
143     for(unsigned j=0; j<active_der[jelem]; ++j) { myvals.putIndexInActiveArray( active_der[kder] ); kder++; }
144     myvals.sortActiveList();
145   }
146 }
147 
calculate(const unsigned & current,MultiValue & myvals,std::vector<double> & buffer,std::vector<unsigned> & der_list) const148 void StoreDataVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const {
149 
150   if( myvals.get(0)>epsilon ) {
151     storeValues( current, myvals, buffer );
152     if( !(getAction()->lowmem) && getAction()->derivativesAreRequired() ) storeDerivatives( current, myvals, buffer, der_list );
153   }
154 
155   return;
156 }
157 
finish(const std::vector<double> & buffer)158 void StoreDataVessel::finish( const std::vector<double>& buffer ) {
159   // Store the buffer locally
160   for(unsigned i=0; i<local_buffer.size(); ++i) local_buffer[i]=buffer[bufstart+i];
161 }
162 
163 
setActiveValsAndDerivatives(const std::vector<unsigned> & der_index)164 void StoreDataVessel::setActiveValsAndDerivatives( const std::vector<unsigned>& der_index ) {
165   if( !getAction()->lowmem && getAction()->derivativesAreRequired() ) {
166     for(unsigned i=0; i<der_index.size(); ++i) active_der[i]=der_index[i];
167   }
168 }
169 
resizeTemporyMultiValues(const unsigned & nvals)170 void StoreDataVessel::resizeTemporyMultiValues( const unsigned& nvals ) {
171   for(unsigned i=0; i<nvals; ++i) my_tmp_vals.push_back( MultiValue(0,0) );
172 }
173 
getTemporyMultiValue(const unsigned & ind)174 MultiValue& StoreDataVessel::getTemporyMultiValue( const unsigned& ind ) {
175   plumed_dbg_assert( ind<my_tmp_vals.size() ); return my_tmp_vals[ind];
176 }
177 
178 }
179 }
180