LCOV - code coverage report
Current view: top level - volumes - VolumeInCylinder.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 59 71 83.1 %
Date: 2026-11-05 10:19:04 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2015-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_VolumeInCylinder_h
      23             : #define __PLUMED_volumes_VolumeInCylinder_h
      24             : #include "tools/Pbc.h"
      25             : #include "tools/SwitchingFunction.h"
      26             : #include "ActionVolume.h"
      27             : #include "tools/HistogramBead.h"
      28             : 
      29             : 
      30             : namespace PLMD {
      31             : namespace volumes {
      32             : 
      33           3 : class VolumeInCylinder {
      34             : public:
      35             :   using precision=double;
      36             :   typedef VolumeIn<precision> VolumeInput;
      37             :   typedef VolumeOut<precision> VolumeOutput;
      38             :   bool docylinder;
      39             :   double min, max, sigma;
      40             :   HistogramBead::KernelType kerneltype;
      41             :   std::array<unsigned,3> dir;
      42             : #ifdef __PLUMED_HAS_OPENACC
      43             :   SwitchingFunctionAccelerable switchingFunction;
      44             : #else
      45             :   SwitchingFunction switchingFunction;
      46             : #endif //__PLUMED_HAS_OPENACC
      47             :   static void registerKeywords( Keywords& keys );
      48             :   template<typename TPM>
      49             :   void parseInput( ActionVolume<VolumeInCylinder, TPM>* action );
      50             :   template<typename TPM>
      51             :   void setupRegions( ActionVolume<VolumeInCylinder, TPM>* action,
      52             :                      const Pbc& pbc,
      53             :                      const std::vector<Vector>& positions ) {}
      54             :   template<typename TPM>
      55             :   static void parseAtoms( ActionVolume<VolumeInCylinder, TPM>* action,
      56             :                           std::vector<AtomNumber>& atom );
      57             :   static void calculateNumberInside( const VolumeInput& input,
      58             :                                      const VolumeInCylinder& actioninput,
      59             :                                      VolumeOutput& output );
      60             : #ifdef __PLUMED_HAS_OPENACC
      61             :   void toACCDevice() const {
      62             : #pragma acc enter data copyin(this[0:1], \
      63             : docylinder, min, max, sigma, kerneltype, dir[0:3])
      64             :     switchingFunction.toACCDevice();
      65             :   }
      66             :   void removeFromACCDevice() const {
      67             :     switchingFunction.removeFromACCDevice();
      68             : #pragma acc exit data delete(dir[0:3], kerneltype, sigma, max, min, \
      69             :       docylinder, this[0:1])
      70             :   }
      71             : #endif //__PLUMED_HAS_OPENACC
      72             : };
      73             : 
      74          11 : void VolumeInCylinder::registerKeywords( Keywords& keys ) {
      75          22 :   keys.setDisplayName("INCYLINDER");
      76          11 :   keys.add("atoms","CENTER","the atom whose vicinity we are interested in examining");
      77          11 :   keys.add("optional","SIGMA","the width of the function to be used for kernel density estimation");
      78          11 :   keys.add("compulsory","KERNEL","gaussian","the type of kernel function to be used");
      79          11 :   keys.add("compulsory","DIRECTION","the direction of the long axis of the cylinder. Must be x, y or z");
      80          11 :   keys.add("compulsory","RADIUS","a switching function that gives the extent of the cylinder in the plane perpendicular to the direction");
      81          11 :   keys.add("compulsory","LOWER","0.0","the lower boundary on the direction parallel to the long axis of the cylinder");
      82          11 :   keys.add("compulsory","UPPER","0.0","the upper boundary on the direction parallel to the long axis of the cylinder");
      83          22 :   keys.linkActionInDocs("RADIUS","LESS_THAN");
      84          11 : }
      85             : 
      86             : template<typename TPM>
      87           1 : void VolumeInCylinder::parseInput( ActionVolume<VolumeInCylinder, TPM>* action ) {
      88           2 :   action->parse("SIGMA",sigma);
      89             :   std::string mykerneltype;
      90           1 :   action->parse("KERNEL",mykerneltype);
      91           1 :   kerneltype=HistogramBead::getKernelType(mykerneltype);
      92             :   std::string sdir;
      93           1 :   action->parse("DIRECTION",sdir);
      94           1 :   if( sdir=="X") {
      95           0 :     dir[0]=1;
      96           0 :     dir[1]=2;
      97           0 :     dir[2]=0;
      98           1 :   } else if( sdir=="Y") {
      99           0 :     dir[0]=0;
     100           0 :     dir[1]=2;
     101           0 :     dir[2]=1;
     102           1 :   } else if( sdir=="Z") {
     103           1 :     dir[0]=0;
     104           1 :     dir[1]=1;
     105           1 :     dir[2]=2;
     106             :   } else {
     107           0 :     action->error(sdir + "is not a valid direction.  Should be X, Y or Z");
     108             :   }
     109           1 :   action->log.printf("  cylinder's long axis is along %s axis\n",sdir.c_str() );
     110             : 
     111             :   std::string errors;
     112             :   std::string swinput;
     113           2 :   action->parse("RADIUS",swinput);
     114           1 :   if(swinput.length()==0) {
     115           0 :     action->error("missing RADIUS keyword");
     116             :   }
     117           1 :   switchingFunction.set(swinput,errors);
     118           1 :   if( errors.length()!=0 ) {
     119           0 :     action->error("problem reading RADIUS keyword : " + errors );
     120             :   }
     121           1 :   action->log.printf("  radius of cylinder is given by %s \n", ( switchingFunction.description() ).c_str() );
     122             : 
     123           1 :   docylinder=false;
     124           1 :   action->parse("LOWER",min);
     125           1 :   action->parse("UPPER",max);
     126           1 :   if( min!=0.0 ||  max!=0.0 ) {
     127           1 :     if( min>max ) {
     128           0 :       action->error("minimum of cylinder should be less than maximum");
     129             :     }
     130           1 :     docylinder=true;
     131           1 :     action->log.printf("  cylinder extends from %f to %f along the %s axis\n",min,max,sdir.c_str() );
     132             :   }
     133           1 : }
     134             : 
     135             : template<typename TPM>
     136           1 : void VolumeInCylinder::parseAtoms( ActionVolume<VolumeInCylinder, TPM>* action,
     137             :                                    std::vector<AtomNumber>& atom ) {
     138           2 :   action->parseAtomList("CENTER",atom);
     139           1 :   if( atom.size()!=1 ) {
     140           0 :     action->error("should only be one atom specified");
     141             :   }
     142           1 :   action->log.printf("  center of cylinder is at position of atom : %d\n",atom[0].serial() );
     143           1 : }
     144             : 
     145        8000 : void VolumeInCylinder::calculateNumberInside( const VolumeInput& input,
     146             :     const VolumeInCylinder& actioninput,
     147             :     VolumeOutput& output ) {
     148             :   // Calculate position of atom wrt to origin
     149        8000 :   Vector fpos=input.pbc.distance( Vector(input.refpos[0][0],input.refpos[0][1],input.refpos[0][2]), Vector(input.cpos[0],input.cpos[1],input.cpos[2]) );
     150             : 
     151             :   double vcylinder, dcylinder;
     152        8000 :   if( actioninput.docylinder ) {
     153        8000 :     HistogramBead bead( actioninput.kerneltype,
     154        8000 :                         actioninput.min, actioninput.max, actioninput.sigma );
     155        8000 :     vcylinder=bead.calculate( fpos[actioninput.dir[2]], dcylinder );
     156             :   } else {
     157             :     vcylinder=1.0;
     158           0 :     dcylinder=0.0;
     159             :   }
     160             : 
     161        8000 :   const double dd = fpos[actioninput.dir[0]]*fpos[actioninput.dir[0]] + fpos[actioninput.dir[1]]*fpos[actioninput.dir[1]];
     162             :   double dfunc;
     163        8000 :   double vswitch = actioninput.switchingFunction.calculateSqr( dd, dfunc );
     164        8000 :   output.values[0]=vswitch*vcylinder;
     165        8000 :   output.derivatives[actioninput.dir[0]]=vcylinder*dfunc*fpos[actioninput.dir[0]];
     166        8000 :   output.derivatives[actioninput.dir[1]]=vcylinder*dfunc*fpos[actioninput.dir[1]];
     167        8000 :   output.derivatives[actioninput.dir[2]]=vswitch*dcylinder;
     168             :   // Add derivatives wrt to position of origin atom
     169        8000 :   output.refders[0][0] = -output.derivatives[0];
     170        8000 :   output.refders[0][1] = -output.derivatives[1];
     171        8000 :   output.refders[0][2] = -output.derivatives[2];
     172             :   // Add virial contribution
     173       16000 :   output.virial.set( 0, -Tensor(fpos,Vector(output.derivatives[0], output.derivatives[1], output.derivatives[2])) );
     174        8000 : }
     175             : 
     176             : }
     177             : }
     178             : #endif //__PLUMED_volumes_VolumeInCylinder_h

Generated by: LCOV version 1.16