/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 2013-2021 The plumed team (see the PEOPLE file at the root of the distribution for a list of names) See http://www.plumed.org for more information. This file is part of plumed, version 2. plumed is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. plumed is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with plumed. If not, see . +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #ifndef __PLUMED_vesselbase_StoreDataVessel_h #define __PLUMED_vesselbase_StoreDataVessel_h #include #include #include #include "Vessel.h" namespace PLMD { namespace vesselbase { /** \ingroup TOOLBOX Objects that inherit from FunctionVessel can be used (in tandem with PLMD::vesselbase::ActionWithVessel) to store values and derivatives for a set of scalars or vectors that are calculated by a PLMD::vesselbase::ActionWithVessel. Functions of these stored quantities can then be calculated in a second step. */ class StoreDataVessel : public Vessel { friend class Moments; private: /// Do the quantities being stored in here need derivatives bool hasderiv; /// What is the maximum number of vectors we are going to /// have to store when using lowmem option unsigned max_lowmem_stash; /// The size of the vector we are computing unsigned vecsize; /// The amount of data per vector element unsigned nspace; /// The currently active values // std::vector active_val; /// The active derivative elements std::vector active_der; /// The buffer std::vector local_buffer; /// The actions that are going to use the stored data std::vector userActions; /// We create a vector of tempory MultiValues here so as to avoid /// lots of vector resizing unsigned tmp_index; std::vector my_tmp_vals; protected: /// Is the weight differentiable bool weightHasDerivatives(); /// Are we using low mem option bool usingLowMem(); /// Finish the setup of the storage object by setting how much /// data has to be stored void completeSetup( const unsigned&, const unsigned& ); /// Return value of nspace unsigned getNumberOfDerivativeSpacesPerComponent() const ; /// Retrieve the values from the underlying ActionWithVessel void storeValues( const unsigned&, MultiValue&, std::vector& ) const ; /// This stores the data we get from the calculation void storeDerivatives( const unsigned&, MultiValue& myvals, std::vector&, std::vector& ) const ; /// Get the ibuf'th local derivative value double getLocalDerivative( const unsigned& ibuf ); /// Set the ibuf'th local derivative value void setLocalDerivative( const unsigned& ibuf, const double& val ); public: static void registerKeywords( Keywords& keys ); explicit StoreDataVessel( const VesselOptions& ); /// Get the number of values that have been stored virtual unsigned getNumberOfStoredValues() const ; /// Get the index to store a particular index inside unsigned getStoreIndex( const unsigned& ) const ; /// Get the true index of a quantity from the index it is stored in unsigned getTrueIndex( const unsigned& ) const ; /// Recalculate one of the base quantities void recalculateStoredQuantity( const unsigned& myelm, MultiValue& myvals ); /// Set a hard cutoff on the weight of an element void setHardCutoffOnWeight( const double& mytol ); /// Add an action that uses this data void addActionThatUses( ActionWithVessel* actionThatUses ); /// Return the number of components in the vector unsigned getNumberOfComponents() const { return vecsize; } /// Get the values of all the components in the vector void retrieveSequentialValue( const unsigned& myelem, const bool& normed, std::vector& values ) const ; void retrieveValueWithIndex( const unsigned& myelem, const bool& normed, std::vector& values ) const ; double retrieveWeightWithIndex( const unsigned& myelem ) const ; /// Get the derivatives for one of the components in the vector void retrieveDerivatives( const unsigned& myelem, const bool& normed, MultiValue& myvals ); /// Do all resizing of data void resize() override; /// std::string description() override { return ""; } /// Get the number of derivatives for the ith value unsigned getNumberOfDerivatives( const unsigned& ); /// Get the size of the derivative list unsigned getSizeOfDerivativeList() const ; /// This stores the data when not using lowmem void calculate( const unsigned& current, MultiValue& myvals, std::vector& buffer, std::vector& der_index ) const override; /// Final step in gathering data void finish( const std::vector& buffer ) override; /// Is a particular stored value active at the present time bool storedValueIsActive( const unsigned& iatom ) const ; /// Set the active values void setActiveValsAndDerivatives( const std::vector& der_index ); /// Activate indexes (this is used at end of chain rule) virtual void activateIndices( ActionWithVessel* ) {} /// Forces on vectors should always be applied elsewhere bool applyForce(std::vector&) override { return false; } /// Get the number of data users unsigned getNumberOfDataUsers() const ; /// Get one of the ith data user ActionWithVessel* getDataUser( const unsigned& ); /// Set the number of tempory multivalues we need void resizeTemporyMultiValues( const unsigned& nvals ); /// Return a tempory multi value - we do this so as to avoid vector resizing MultiValue& getTemporyMultiValue( const unsigned& ind ); }; inline bool StoreDataVessel::weightHasDerivatives() { return getAction()->weightHasDerivatives; } inline bool StoreDataVessel::usingLowMem() { return getAction()->lowmem; } inline unsigned StoreDataVessel::getNumberOfDerivativeSpacesPerComponent() const { return nspace; } inline bool StoreDataVessel::storedValueIsActive( const unsigned& iatom ) const { if( !getAction()->taskIsCurrentlyActive( iatom ) ) return false; unsigned jatom = getStoreIndex( iatom ); plumed_dbg_assert( jatomepsilon; } inline unsigned StoreDataVessel::getSizeOfDerivativeList() const { return active_der.size(); } inline unsigned StoreDataVessel::getNumberOfStoredValues() const { return getAction()->nactive_tasks; } inline unsigned StoreDataVessel::getStoreIndex( const unsigned& ind ) const { if( getAction()->nactive_tasks==getAction()->getFullNumberOfTasks() ) return ind; // Binary search for required element - faster scaling than sequential search unsigned l=0, r=getAction()->nactive_tasks-1; for(unsigned i=0; inactive_tasks; ++i) { plumed_assert( l<=r ); unsigned m = std::floor( (l + r)/2 ); if( ind==getAction()->indexOfTaskInFullList[m] ) return m; else if( getAction()->indexOfTaskInFullList[m]indexOfTaskInFullList[m]>ind ) r=m-1; } plumed_merror("requested task is not active"); } inline unsigned StoreDataVessel::getTrueIndex( const unsigned& ind ) const { return getAction()->indexOfTaskInFullList[ind]; } inline void StoreDataVessel::recalculateStoredQuantity( const unsigned& myelem, MultiValue& myvals ) { getAction()->performTask( myelem, getAction()->getTaskCode(myelem), myvals ); } inline unsigned StoreDataVessel::getNumberOfDataUsers() const { return userActions.size(); } inline ActionWithVessel* StoreDataVessel::getDataUser( const unsigned& idata ) { plumed_dbg_assert( idata