LCOV - code coverage report
Current view: top level - volumes - ActionVolume.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 94 98 95.9 %
Date: 2025-12-04 11:19:34 Functions: 46 54 85.2 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2020 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_volumes_ActionVolume_h
      23             : #define __PLUMED_volumes_ActionVolume_h
      24             : 
      25             : #include "core/ActionWithVector.h"
      26             : #include "core/ParallelTaskManager.h"
      27             : #include "tools/ColvarOutput.h"
      28             : 
      29             : namespace PLMD {
      30             : namespace volumes {
      31             : 
      32             : template <class T>
      33          76 : struct VolumeData {
      34             :   bool not_in;
      35             :   std::size_t numberOfNonReferenceAtoms;
      36             :   T voldata;
      37             : #ifdef __PLUMED_USE_OPENACC
      38             :   void toACCDevice() const {
      39             : #pragma acc enter data copyin(this[0:1],not_in,numberOfNonReferenceAtoms)
      40             :     voldata.toACCDevice();
      41             :   }
      42             :   void removeFromACCDevice() const {
      43             :     voldata.removeFromACCDevice();
      44             : #pragma acc exit data delete(numberOfNonReferenceAtoms,not_in,this[0:1])
      45             :   }
      46             : #endif //__PLUMED_USE_OPENACC
      47             : };
      48             : 
      49             : struct VolumeInput {
      50             :   std::size_t task_index;
      51             :   const Pbc& pbc;
      52             :   View<const double,3> cpos;
      53             :   View2D<const double,helpers::dynamic_extent,3> refpos;
      54             :   VolumeInput( std::size_t t, unsigned nref, double* p, double* rp, const Pbc& box ) :
      55        3120 :     task_index(t),pbc(box),cpos(p),refpos(rp,nref) {
      56             :   }
      57             : };
      58             : 
      59             : class VolumeOutput {
      60             : private:
      61             :   class RefderHelper {
      62             :   private:
      63             :     double* derivatives;
      64             :   public:
      65     1098882 :     RefderHelper( double* d ) : derivatives(d) {}
      66             :     View<double,3> operator[](std::size_t i) {
      67     1142362 :       return View<double,3>( derivatives + 3*(i+1) );
      68             :     }
      69             :   };
      70             :   ColvarOutput fulldata;
      71             : public:
      72             :   View<double>& values;
      73             :   ColvarOutput::VirialHelper& virial;
      74             :   View<double,3> derivatives;
      75             :   RefderHelper refders;
      76             :   VolumeOutput( View<double>& v, std::size_t nder, double* d ) :
      77             :     fulldata(v, nder, d),
      78     1098882 :     values(fulldata.values),
      79     1098882 :     virial(fulldata.virial),
      80             :     derivatives(d), refders(d) {
      81             :   }
      82             : };
      83             : 
      84             : /**
      85             : \ingroup INHERIT
      86             : This is the abstract base class to use for implementing a new way of defining a particular region of the simulation
      87             : box. You can use this to calculate the number of atoms inside that part or the average value of a quantity like the
      88             : coordination number inside that part of the cell.
      89             : */
      90             : 
      91             : template <class T>
      92             : class ActionVolume : public ActionWithVector {
      93             : public:
      94             :   using input_type = VolumeData<T>;
      95             :   using PTM = ParallelTaskManager<ActionVolume<T>>;
      96             : private:
      97             : /// The parallel task manager
      98             :   PTM taskmanager;
      99             : public:
     100             :   static void registerKeywords( Keywords& keys );
     101             :   explicit ActionVolume(const ActionOptions&);
     102             :   unsigned getNumberOfDerivatives() override;
     103             :   void getInputData( std::vector<double>& inputdata ) const override ;
     104             :   void calculate() override ;
     105             :   void applyNonZeroRankForces( std::vector<double>& outforces ) override ;
     106             :   static void performTask( std::size_t task_index, const VolumeData<T>& actiondata, ParallelActionsInput& input, ParallelActionsOutput& output );
     107             :   static void gatherForces( std::size_t task_index, const VolumeData<T>& actiondata, const ParallelActionsInput& input, const ForceInput& fdata, ForceOutput& forces );
     108             :   static int getNumberOfValuesPerTask( std::size_t task_index, const VolumeData<T>& actiondata );
     109             :   static void getForceIndices( std::size_t task_index, std::size_t colno, std::size_t ntotal_force, const VolumeData<T>& actiondata, const ParallelActionsInput& input, ForceIndexHolder force_indices );
     110             : };
     111             : 
     112             : template <class T>
     113        9548 : unsigned ActionVolume<T>::getNumberOfDerivatives() {
     114        9548 :   return 3*getNumberOfAtoms()+9;
     115             : }
     116             : 
     117             : template <class T>
     118         244 : void ActionVolume<T>::registerKeywords( Keywords& keys ) {
     119         244 :   ActionWithVector::registerKeywords( keys );
     120         244 :   PTM::registerKeywords( keys );
     121         244 :   keys.add("atoms","ATOMS","the group of atoms that you would like to investigate");
     122         244 :   keys.addFlag("OUTSIDE",false,"calculate quantities for colvars that are on atoms outside the region of interest");
     123         488 :   keys.setValueDescription("scalar/vector","vector of numbers between 0 and 1 that measure the degree to which each atom is within the volume of interest");
     124         244 :   T::registerKeywords( keys );
     125         244 : }
     126             : 
     127             : template <class T>
     128          68 : ActionVolume<T>::ActionVolume(const ActionOptions&ao):
     129             :   Action(ao),
     130             :   ActionWithVector(ao),
     131          68 :   taskmanager(this) {
     132             :   std::vector<AtomNumber> atoms;
     133         136 :   parseAtomList("ATOMS",atoms);
     134          68 :   if( atoms.size()==0 ) {
     135           0 :     error("no atoms were specified");
     136             :   }
     137          68 :   log.printf("  examining positions of atoms ");
     138       50664 :   for(unsigned i=0; i<atoms.size(); ++i) {
     139       50596 :     log.printf(" %d", atoms[i].serial() );
     140             :   }
     141          68 :   log.printf("\n");
     142          68 :   std::vector<std::size_t> shape(1);
     143          68 :   shape[0]=atoms.size();
     144             : 
     145             :   std::vector<AtomNumber> refatoms;
     146          68 :   T::parseAtoms( this, refatoms );
     147         149 :   for(unsigned i=0; i<refatoms.size(); ++i) {
     148          81 :     atoms.push_back( refatoms[i] );
     149             :   }
     150          68 :   requestAtoms( atoms );
     151             :   VolumeData<T> actioninput;
     152          68 :   actioninput.voldata.parseInput(this);
     153             : 
     154          68 :   actioninput.numberOfNonReferenceAtoms=shape[0];
     155         136 :   parseFlag("OUTSIDE",actioninput.not_in);
     156             : 
     157          68 :   if( shape[0]==1 ) {
     158           4 :     ActionWithValue::addValueWithDerivatives();
     159             :   } else {
     160          66 :     ActionWithValue::addValue( shape );
     161          66 :     taskmanager.setupParallelTaskManager( 3*(1+refatoms.size())+9, 3*refatoms.size()+9 );
     162             :   }
     163          68 :   setNotPeriodic();
     164          68 :   getPntrToComponent(0)->setDerivativeIsZeroWhenValueIsZero();
     165             : 
     166          68 :   taskmanager.setActionInput( actioninput );
     167          68 : }
     168             : 
     169             : template <class T>
     170        3775 : void ActionVolume<T>::getInputData( std::vector<double>& inputdata ) const {
     171        3775 :   if( inputdata.size()!=3*getNumberOfAtoms() ) {
     172        3184 :     inputdata.resize( 3*getNumberOfAtoms() );
     173             :   }
     174             : 
     175      702491 :   for(unsigned i=0; i<getNumberOfAtoms(); ++i) {
     176      698716 :     Vector ipos = getPosition(i);
     177     2794864 :     for(unsigned j=0; j<3; ++j) {
     178     2096148 :       inputdata[3*i+j] = ipos[j];
     179             :     }
     180             :   }
     181        3775 : }
     182             : 
     183             : template <class T>
     184        3775 : void ActionVolume<T>::calculate() {
     185             :   unsigned k=0;
     186        3775 :   std::vector<Vector> positions( getNumberOfAtoms()-getPntrToComponent(0)->getNumberOfValues() );
     187       16945 :   for(unsigned i=getPntrToComponent(0)->getNumberOfValues(); i<getNumberOfAtoms(); ++i) {
     188       13170 :     positions[k] = getPosition( i );
     189       13170 :     k++;
     190             :   }
     191        3775 :   taskmanager.getActionInput().voldata.setupRegions( this, getPbc(), positions );
     192             : 
     193        3775 :   if( getPntrToComponent(0)->getRank()==0 ) {
     194        3120 :     std::size_t nref = getNumberOfAtoms() - 1;
     195             :     std::vector<double> posvec;
     196        3120 :     getInputData( posvec );
     197        3120 :     std::vector<double> deriv( getNumberOfDerivatives() );
     198        3120 :     std::vector<double> val(1);
     199             :     View<double> valview(val.data(),1);
     200        3120 :     VolumeOutput output( valview, getNumberOfDerivatives(), deriv.data() );
     201        3120 :     T::calculateNumberInside( VolumeInput( 0, nref, posvec.data(), posvec.data()+3, getPbc() ), taskmanager.getActionInput().voldata, output );
     202        3120 :     if( taskmanager.getActionInput().not_in ) {
     203           0 :       val[0] = 1.0 - val[0];
     204           0 :       for(unsigned i=0; i<deriv.size(); ++i) {
     205           0 :         deriv[i] *= -1;
     206             :       }
     207             :     }
     208        3120 :     Value* v = getPntrToComponent(0);
     209        3120 :     v->set( val[0] );
     210       78000 :     for(unsigned i=0; i<deriv.size(); ++i) {
     211       74880 :       v->addDerivative( i, deriv[i] );
     212             :     }
     213             :   } else {
     214         655 :     taskmanager.runAllTasks();
     215             :   }
     216        3775 : }
     217             : 
     218             : template <class T>
     219         404 : void ActionVolume<T>::applyNonZeroRankForces( std::vector<double>& outforces ) {
     220         404 :   taskmanager.applyForces( outforces );
     221         404 : }
     222             : 
     223             : template <class T>
     224     1095762 : void ActionVolume<T>::performTask( std::size_t task_index, const VolumeData<T>& actiondata, ParallelActionsInput& input, ParallelActionsOutput& output ) {
     225     1095762 :   std::size_t nref = output.derivatives.size()/3 - 4; // This is the number of reference atoms
     226             :   VolumeOutput volout( output.values, output.derivatives.size(), output.derivatives.data() );
     227     1095762 :   T::calculateNumberInside( VolumeInput( task_index, nref, input.inputdata+3*task_index, input.inputdata+3*actiondata.numberOfNonReferenceAtoms, *input.pbc ), actiondata.voldata, volout );
     228             : 
     229     1095762 :   if( actiondata.not_in ) {
     230        8000 :     output.values[0] = 1.0 - output.values[0];
     231        8000 :     if( input.noderiv ) {
     232        4000 :       return;
     233             :     }
     234       64000 :     for(unsigned i=0; i<output.derivatives.size(); ++i) {
     235       60000 :       output.derivatives[i] *= -1;
     236             :     }
     237             :   }
     238             : }
     239             : 
     240             : template <class T>
     241      413336 : int ActionVolume<T>::getNumberOfValuesPerTask( std::size_t task_index,
     242             :     const VolumeData<T>& actiondata ) {
     243      413336 :   return 1;
     244             : }
     245             : 
     246             : template<class T>
     247      413336 : void ActionVolume<T>::getForceIndices( std::size_t task_index,
     248             :                                        std::size_t colno,
     249             :                                        std::size_t ntotal_force,
     250             :                                        const VolumeData<T>& actiondata,
     251             :                                        const ParallelActionsInput& input,
     252             :                                        ForceIndexHolder force_indices ) {
     253      413336 :   std::size_t base = 3*task_index;
     254      413336 :   force_indices.indices[0][0] = base;
     255      413336 :   force_indices.indices[0][1] = base + 1;
     256      413336 :   force_indices.indices[0][2] = base + 2;
     257      413336 :   force_indices.threadsafe_derivatives_end[0]=3;
     258             :   std::size_t m=3;
     259     5383868 :   for(unsigned n=3*actiondata.numberOfNonReferenceAtoms; n<ntotal_force; ++n) {
     260     4970532 :     force_indices.indices[0][m] = n;
     261     4970532 :     ++m;
     262             :   }
     263      413336 :   force_indices.tot_indices[0] = m;
     264      413336 : }
     265             : 
     266             : }
     267             : }
     268             : #endif

Generated by: LCOV version 1.16