LCOV - code coverage report
Current view: top level - crystallization - MoleculeOrientation.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 67 72 93.1 %
Date: 2026-03-30 13:16:06 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-2023 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 "core/ActionRegister.h"
      23             : #include "VectorMultiColvar.h"
      24             : 
      25             : namespace PLMD {
      26             : namespace crystallization {
      27             : 
      28             : //+PLUMEDOC MCOLVAR MOLECULES
      29             : /*
      30             : Calculate the vectors connecting a pair of atoms in order to represent the orientation of a molecule.
      31             : 
      32             : At its simplest this command can be used to calculate the average length of an internal vector in a
      33             : collection of different molecules.  When used in conjunction with MutiColvarFunctions in can be used
      34             : to do a variety of more complex tasks.
      35             : 
      36             : \par Examples
      37             : 
      38             : The following input tells plumed to calculate the distances between two of the atoms in a molecule.
      39             : This is done for the same set of atoms four different molecules and the average separation is then
      40             : calculated.
      41             : 
      42             : \plumedfile
      43             : MOLECULES MOL1=1,2 MOL2=3,4 MOL3=5,6 MOL4=7,8 MEAN LABEL=mm
      44             : PRINT ARG=mm.mean FILE=colvar
      45             : \endplumedfile
      46             : 
      47             : 
      48             : */
      49             : //+ENDPLUMEDOC
      50             : 
      51             : 
      52             : class MoleculeOrientation : public VectorMultiColvar {
      53             : private:
      54             :   unsigned nvectors;
      55             : public:
      56             :   static void registerKeywords( Keywords& keys );
      57             :   explicit MoleculeOrientation( const ActionOptions& ao );
      58             :   AtomNumber getAbsoluteIndexOfCentralAtom( const unsigned& iatom ) const override;
      59             :   void calculateVector( multicolvar::AtomValuePack& myatoms ) const override;
      60             :   void normalizeVector( std::vector<double>& vals ) const override;
      61             :   void normalizeVectorDerivatives( MultiValue& myvals ) const override;
      62             : };
      63             : 
      64       13793 : PLUMED_REGISTER_ACTION(MoleculeOrientation,"MOLECULES")
      65             : 
      66           8 : void MoleculeOrientation::registerKeywords( Keywords& keys ) {
      67           8 :   VectorMultiColvar::registerKeywords( keys );
      68           8 :   keys.use("MEAN");
      69           8 :   keys.use("VMEAN");
      70          16 :   keys.add("numbered","MOL","The numerical indices of the atoms in the molecule. The orientation of the molecule is equal to "
      71             :            "the vector connecting the first two atoms specified.  If a third atom is specified its position "
      72             :            "is used to specify where the molecule is.  If a third atom is not present the molecule is assumed "
      73             :            "to be at the center of the vector connecting the first two atoms.");
      74          16 :   keys.reset_style("MOL","atoms");
      75           8 : }
      76             : 
      77           4 : MoleculeOrientation::MoleculeOrientation( const ActionOptions& ao ):
      78             :   Action(ao),
      79           4 :   VectorMultiColvar(ao) {
      80             :   std::vector<AtomNumber> all_atoms;
      81           8 :   readAtomsLikeKeyword("MOL",-1,all_atoms);
      82           4 :   nvectors = std::floor( ablocks.size() / 2 );
      83           4 :   if( ablocks.size()%2!=0 && 2*nvectors+1!=ablocks.size() ) {
      84           0 :     error("number of atoms in molecule specification is wrong.  Should be two or three.");
      85             :   }
      86             : 
      87           4 :   if( all_atoms.size()==0 ) {
      88           0 :     error("No atoms were specified");
      89             :   }
      90           4 :   setVectorDimensionality( 3*nvectors );
      91           4 :   setupMultiColvarBase( all_atoms );
      92             : 
      93           4 :   if( ablocks.size()==2*nvectors+1  ) {
      94           4 :     std::vector<bool> catom_ind(ablocks.size(), false);
      95           4 :     catom_ind[ablocks.size()-1]=true;
      96           4 :     setAtomsForCentralAtom( catom_ind );
      97             :   }
      98           4 : }
      99             : 
     100           0 : AtomNumber MoleculeOrientation::getAbsoluteIndexOfCentralAtom( const unsigned& iatom ) const {
     101             :   plumed_dbg_assert( iatom<atom_lab.size() );
     102           0 :   plumed_assert( atom_lab[iatom].first==0 );
     103           0 :   return ActionAtomistic::getAbsoluteIndex( ablocks[0][atom_lab[iatom].second] );
     104             : }
     105             : 
     106       16584 : void MoleculeOrientation::calculateVector( multicolvar::AtomValuePack& myatoms ) const {
     107       33168 :   for(unsigned i=0; i<nvectors; ++i) {
     108       16584 :     Vector distance;
     109       16584 :     distance=getSeparation( myatoms.getPosition(2*i+0), myatoms.getPosition(2*i+1) );
     110             : 
     111       16584 :     addAtomDerivatives( 2+3*i+0, 2*i+0, Vector(-1.0,0,0), myatoms );
     112       16584 :     addAtomDerivatives( 2+3*i+0, 2*i+1, Vector(+1.0,0,0), myatoms );
     113       16584 :     myatoms.addBoxDerivatives( 2+3*i+0, Tensor(distance,Vector(-1.0,0,0)) );
     114       16584 :     myatoms.addValue( 2+3*i+0, distance[0] );
     115             : 
     116       16584 :     addAtomDerivatives( 2+3*i+1, 2*i+0, Vector(0,-1.0,0), myatoms );
     117       16584 :     addAtomDerivatives( 2+3*i+1, 2*i+1, Vector(0,+1.0,0), myatoms );
     118       16584 :     myatoms.addBoxDerivatives( 2+3*i+1, Tensor(distance,Vector(0,-1.0,0)) );
     119       16584 :     myatoms.addValue( 2+3*i+1, distance[1] );
     120             : 
     121       16584 :     addAtomDerivatives( 2+3*i+2, 2*i+0, Vector(0,0,-1.0), myatoms );
     122       16584 :     addAtomDerivatives( 2+3*i+2, 2*i+1, Vector(0,0,+1.0), myatoms );
     123       16584 :     myatoms.addBoxDerivatives( 2+3*i+2, Tensor(distance,Vector(0,0,-1.0)) );
     124       16584 :     myatoms.addValue( 2+3*i+2, distance[2] );
     125             :   }
     126       16584 : }
     127             : 
     128     1041228 : void MoleculeOrientation::normalizeVector( std::vector<double>& vals ) const {
     129     2082456 :   for(unsigned i=0; i<nvectors; ++i) {
     130             :     double norm=0;
     131     4164912 :     for(unsigned j=0; j<3; ++j) {
     132     3123684 :       norm += vals[2+3*i+j]*vals[2+3*i+j];
     133             :     }
     134     1041228 :     norm = sqrt(norm);
     135             : 
     136             :     double inorm = 1.0;
     137     1041228 :     if( norm>epsilon ) {
     138     1041228 :       inorm = 1.0 / norm;
     139             :     }
     140     4164912 :     for(unsigned j=0; j<3; ++j) {
     141     3123684 :       vals[2+3*i+j] = inorm*vals[2+3*i+j];
     142             :     }
     143             :   }
     144     1041228 : }
     145             : 
     146        4992 : void MoleculeOrientation::normalizeVectorDerivatives( MultiValue& myvals ) const {
     147        4992 :   std::vector<double> weight( nvectors ), wdf( nvectors );
     148        9984 :   for(unsigned ivec=0; ivec<nvectors; ++ivec) {
     149             :     double v=0;
     150       19968 :     for(unsigned jcomp=0; jcomp<3; ++jcomp) {
     151       14976 :       v += myvals.get( 2+3*ivec+jcomp )*myvals.get( 2+3*ivec+jcomp );
     152             :     }
     153        4992 :     v=sqrt(v);
     154        4992 :     weight[ivec]=1.0;
     155        4992 :     wdf[ivec]=1.0;
     156        4992 :     if( v>epsilon ) {
     157        4992 :       weight[ivec] = 1.0 / v;
     158        4992 :       wdf[ivec] = 1.0 / ( v*v*v );
     159             :     }
     160             :   }
     161             : 
     162       54672 :   for(unsigned j=0; j<myvals.getNumberActive(); ++j) {
     163       49680 :     unsigned jder=myvals.getActiveIndex(j);
     164       99360 :     for(unsigned ivec=0; ivec<nvectors; ++ivec) {
     165             :       double comp2=0.0;
     166      198720 :       for(unsigned jcomp=0; jcomp<3; ++jcomp) {
     167      149040 :         comp2 += myvals.get(2+3*ivec+jcomp)*myvals.getDerivative( 2+3*ivec+jcomp, jder );
     168             :       }
     169      198720 :       for(unsigned jcomp=0; jcomp<3; ++jcomp) {
     170      149040 :         myvals.setDerivative( 2+3*ivec+jcomp, jder, weight[ivec]*myvals.getDerivative( 2+3*ivec+jcomp, jder ) - wdf[ivec]*comp2*myvals.get(2+3*ivec+jcomp) );
     171             :       }
     172             :     }
     173             :   }
     174        4992 : }
     175             : 
     176             : }
     177             : }

Generated by: LCOV version 1.16