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 #ifndef __PLUMED_vesselbase_StoreDataVessel_h
23 #define __PLUMED_vesselbase_StoreDataVessel_h
24 
25 #include <string>
26 #include <cstring>
27 #include <vector>
28 #include "Vessel.h"
29 
30 namespace PLMD {
31 namespace vesselbase {
32 
33 /**
34 \ingroup TOOLBOX
35 Objects that inherit from FunctionVessel can be used (in tandem with PLMD::vesselbase::ActionWithVessel)
36 to store values and derivatives for a set of scalars or vectors that are calculated by a
37 PLMD::vesselbase::ActionWithVessel.  Functions of these stored quantities can then be calculated in a
38 second step.
39 */
40 
41 class StoreDataVessel : public Vessel {
42   friend class Moments;
43 private:
44 /// Do the quantities being stored in here need derivatives
45   bool hasderiv;
46 /// What is the maximum number of vectors we are going to
47 /// have to store when using lowmem option
48   unsigned max_lowmem_stash;
49 /// The size of the vector we are computing
50   unsigned vecsize;
51 /// The amount of data per vector element
52   unsigned nspace;
53 /// The currently active values
54 //  std::vector<unsigned> active_val;
55 /// The active derivative elements
56   std::vector<unsigned> active_der;
57 /// The buffer
58   std::vector<double> local_buffer;
59 /// The actions that are going to use the stored data
60   std::vector<ActionWithVessel*> userActions;
61 /// We create a vector of tempory MultiValues here so as to avoid
62 /// lots of vector resizing
63   unsigned tmp_index;
64   std::vector<MultiValue> my_tmp_vals;
65 protected:
66 /// Is the weight differentiable
67   bool weightHasDerivatives();
68 /// Are we using low mem option
69   bool usingLowMem();
70 /// Finish the setup of the storage object by setting how much
71 /// data has to be stored
72   void completeSetup( const unsigned&, const unsigned& );
73 /// Return value of nspace
74   unsigned getNumberOfDerivativeSpacesPerComponent() const ;
75 /// Retrieve the values from the underlying ActionWithVessel
76   void storeValues( const unsigned&, MultiValue&, std::vector<double>& ) const ;
77 /// This stores the data we get from the calculation
78   void storeDerivatives( const unsigned&, MultiValue& myvals, std::vector<double>&, std::vector<unsigned>& ) const ;
79 /// Get the ibuf'th local derivative value
80   double getLocalDerivative( const unsigned& ibuf );
81 /// Set the ibuf'th local derivative value
82   void setLocalDerivative( const unsigned& ibuf, const double& val );
83 public:
84   static void registerKeywords( Keywords& keys );
85   explicit StoreDataVessel( const VesselOptions& );
86 /// Get the number of values that have been stored
87   virtual unsigned getNumberOfStoredValues() const ;
88 /// Get the index to store a particular index inside
89   unsigned getStoreIndex( const unsigned& ) const ;
90 /// Get the true index of a quantity from the index it is stored in
91   unsigned getTrueIndex( const unsigned& ) const ;
92 /// Recalculate one of the base quantities
93   void recalculateStoredQuantity( const unsigned& myelm, MultiValue& myvals );
94 /// Set a hard cutoff on the weight of an element
95   void setHardCutoffOnWeight( const double& mytol );
96 /// Add an action that uses this data
97   void addActionThatUses( ActionWithVessel* actionThatUses );
98 /// Return the number of components in the vector
getNumberOfComponents()99   unsigned getNumberOfComponents() const { return vecsize; }
100 /// Get the values of all the components in the vector
101   void retrieveSequentialValue( const unsigned& myelem, const bool& normed, std::vector<double>& values ) const ;
102   void retrieveValueWithIndex( const unsigned& myelem, const bool& normed, std::vector<double>& values ) const ;
103   double retrieveWeightWithIndex( const unsigned& myelem ) const ;
104 /// Get the derivatives for one of the components in the vector
105   void retrieveDerivatives( const unsigned& myelem, const bool& normed, MultiValue& myvals );
106 /// Do all resizing of data
107   void resize() override;
108 ///
description()109   std::string description() override { return ""; }
110 /// Get the number of derivatives for the ith value
111   unsigned getNumberOfDerivatives( const unsigned& );
112 /// Get the size of the derivative list
113   unsigned getSizeOfDerivativeList() const ;
114 /// This stores the data when not using lowmem
115   void calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_index ) const override;
116 /// Final step in gathering data
117   void finish( const std::vector<double>& buffer ) override;
118 /// Is a particular stored value active at the present time
119   bool storedValueIsActive( const unsigned& iatom ) const ;
120 /// Set the active values
121   void setActiveValsAndDerivatives( const std::vector<unsigned>& der_index );
122 /// Activate indexes (this is used at end of chain rule)
activateIndices(ActionWithVessel *)123   virtual void activateIndices( ActionWithVessel* ) {}
124 /// Forces on vectors should always be applied elsewhere
applyForce(std::vector<double> &)125   bool applyForce(std::vector<double>&) override { return false; }
126 ///  Get the number of data users
127   unsigned getNumberOfDataUsers() const ;
128 /// Get one of the ith data user
129   ActionWithVessel* getDataUser( const unsigned& );
130 /// Set the number of tempory multivalues we need
131   void resizeTemporyMultiValues( const unsigned& nvals );
132 /// Return a tempory multi value - we do this so as to avoid vector resizing
133   MultiValue& getTemporyMultiValue( const unsigned& ind );
134 };
135 
136 inline
weightHasDerivatives()137 bool StoreDataVessel::weightHasDerivatives() {
138   return getAction()->weightHasDerivatives;
139 }
140 
141 inline
usingLowMem()142 bool StoreDataVessel::usingLowMem() {
143   return getAction()->lowmem;
144 }
145 
146 inline
getNumberOfDerivativeSpacesPerComponent()147 unsigned StoreDataVessel::getNumberOfDerivativeSpacesPerComponent() const {
148   return nspace;
149 }
150 
151 inline
storedValueIsActive(const unsigned & iatom)152 bool StoreDataVessel::storedValueIsActive( const unsigned& iatom ) const {
153   if( !getAction()->taskIsCurrentlyActive( iatom ) ) return false;
154   unsigned jatom = getStoreIndex( iatom );
155   plumed_dbg_assert( jatom<getNumberOfStoredValues() );
156   return local_buffer[jatom*vecsize*nspace]>epsilon;
157 }
158 
159 inline
getSizeOfDerivativeList()160 unsigned StoreDataVessel::getSizeOfDerivativeList() const {
161   return active_der.size();
162 }
163 
164 inline
getNumberOfStoredValues()165 unsigned StoreDataVessel::getNumberOfStoredValues() const {
166   return getAction()->nactive_tasks;
167 }
168 
169 inline
getStoreIndex(const unsigned & ind)170 unsigned StoreDataVessel::getStoreIndex( const unsigned& ind ) const {
171   if( getAction()->nactive_tasks==getAction()->getFullNumberOfTasks() ) return ind;
172 
173   // Binary search for required element - faster scaling than sequential search
174   unsigned l=0, r=getAction()->nactive_tasks-1;
175   for(unsigned i=0; i<getAction()->nactive_tasks; ++i) {
176     plumed_assert( l<=r );
177     unsigned m = std::floor( (l + r)/2 );
178     if( ind==getAction()->indexOfTaskInFullList[m] ) return m;
179     else if( getAction()->indexOfTaskInFullList[m]<ind ) l=m+1;
180     else if( getAction()->indexOfTaskInFullList[m]>ind ) r=m-1;
181   }
182   plumed_merror("requested task is not active");
183 }
184 
185 inline
getTrueIndex(const unsigned & ind)186 unsigned StoreDataVessel::getTrueIndex( const unsigned& ind ) const {
187   return getAction()->indexOfTaskInFullList[ind];
188 }
189 
190 inline
recalculateStoredQuantity(const unsigned & myelem,MultiValue & myvals)191 void StoreDataVessel::recalculateStoredQuantity( const unsigned& myelem, MultiValue& myvals ) {
192   getAction()->performTask( myelem, getAction()->getTaskCode(myelem), myvals );
193 }
194 
195 inline
getNumberOfDataUsers()196 unsigned StoreDataVessel::getNumberOfDataUsers() const {
197   return userActions.size();
198 }
199 
200 inline
getDataUser(const unsigned & idata)201 ActionWithVessel* StoreDataVessel::getDataUser( const unsigned& idata ) {
202   plumed_dbg_assert( idata<userActions.size() ); return userActions[idata];
203 }
204 
205 }
206 }
207 #endif
208 
209 
210