LCOV - code coverage report
Current view: top level - symfunc - CoordinationNumbers.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 69 70 98.6 %
Date: 2024-10-18 13:59:31 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-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 "CoordinationNumbers.h"
      23             : #include "multicolvar/MultiColvarShortcuts.h"
      24             : #include "core/ActionWithValue.h"
      25             : #include "core/ActionRegister.h"
      26             : #include "core/PlumedMain.h"
      27             : #include "core/ActionSet.h"
      28             : 
      29             : #include <string>
      30             : #include <cmath>
      31             : 
      32             : namespace PLMD {
      33             : namespace symfunc {
      34             : 
      35             : //+PLUMEDOC MCOLVAR COORDINATIONNUMBER
      36             : /*
      37             : Calculate the coordination numbers of atoms so that you can then calculate functions of the distribution of
      38             :  coordination numbers such as the minimum, the number less than a certain quantity and so on.
      39             : 
      40             : So that the calculated coordination numbers have continuous derivatives the following function is used:
      41             : 
      42             : \f[
      43             : s = \frac{ 1 - \left(\frac{r-d_0}{r_0}\right)^n } { 1 - \left(\frac{r-d_0}{r_0}\right)^m }
      44             : \f]
      45             : 
      46             : If R_POWER is set, this will use the product of pairwise distance
      47             : raised to the R_POWER with the coordination number function defined
      48             : above. This was used in White and Voth \cite white2014efficient as a
      49             : way of indirectly biasing radial distribution functions. Note that in
      50             : that reference this function is referred to as moments of coordination
      51             : number, but here we call them powers to distinguish from the existing
      52             : MOMENTS keyword of Multicolvars.
      53             : 
      54             : \par Examples
      55             : 
      56             : The following input tells plumed to calculate the coordination numbers of atoms 1-100 with themselves.
      57             : The minimum coordination number is then calculated.
      58             : \plumedfile
      59             : COORDINATIONNUMBER SPECIES=1-100 R_0=1.0 MIN={BETA=0.1}
      60             : \endplumedfile
      61             : 
      62             : The following input tells plumed to calculate how many atoms from 1-100 are within 3.0 of each of the atoms
      63             : from 101-110.  In the first 101 is the central atom, in the second 102 is the central atom and so on.  The
      64             : number of coordination numbers more than 6 is then computed.
      65             : \plumedfile
      66             : COORDINATIONNUMBER SPECIESA=101-110 SPECIESB=1-100 R_0=3.0 MORE_THAN={RATIONAL R_0=6.0 NN=6 MM=12 D_0=0}
      67             : \endplumedfile
      68             : 
      69             : The following input tells plumed to calculate the mean coordination number of all atoms with themselves
      70             : and its powers. An explicit cutoff is set for each of 8.
      71             : \plumedfile
      72             : cn0: COORDINATIONNUMBER SPECIES=1-10 SWITCH={RATIONAL R_0=1.0 D_MAX=8} MEAN
      73             : cn1: COORDINATIONNUMBER SPECIES=1-10 SWITCH={RATIONAL R_0=1.0 D_MAX=8} R_POWER=1 MEAN
      74             : cn2: COORDINATIONNUMBER SPECIES=1-10 SWITCH={RATIONAL R_0=1.0 D_MAX=8} R_POWER=2 MEAN
      75             : PRINT ARG=cn0.mean,cn1.mean,cn2.mean STRIDE=1 FILE=cn_out
      76             : \endplumedfile
      77             : 
      78             : */
      79             : //+ENDPLUMEDOC
      80             : 
      81             : //+PLUMEDOC MCOLVAR COORDINATION_MOMENTS
      82             : /*
      83             : Calculate moments of the distribution of distances in the first coordination sphere
      84             : 
      85             : \par Examples
      86             : 
      87             : */
      88             : //+ENDPLUMEDOC
      89             : 
      90             : 
      91             : PLUMED_REGISTER_ACTION(CoordinationNumbers,"COORDINATIONNUMBER")
      92             : PLUMED_REGISTER_ACTION(CoordinationNumbers,"COORDINATION_MOMENTS")
      93             : 
      94         176 : void CoordinationNumbers::shortcutKeywords( Keywords& keys ) {
      95         176 :   ActionShortcut::registerKeywords( keys );
      96         352 :   keys.add("atoms-3","SPECIES","this keyword is used for colvars such as coordination number. In that context it specifies that plumed should calculate "
      97             :            "one coordination number for each of the atoms specified.  Each of these coordination numbers specifies how many of the "
      98             :            "other specified atoms are within a certain cutoff of the central atom.  You can specify the atoms here as another multicolvar "
      99             :            "action or using a MultiColvarFilter or ActionVolume action.  When you do so the quantity is calculated for those atoms specified "
     100             :            "in the previous multicolvar.  This is useful if you would like to calculate the Steinhardt parameter for those atoms that have a "
     101             :            "coordination number more than four for example");
     102         352 :   keys.add("atoms-4","SPECIESA","this keyword is used for colvars such as the coordination number.  In that context it species that plumed should calculate "
     103             :            "one coordination number for each of the atoms specified in SPECIESA.  Each of these cooordination numbers specifies how many "
     104             :            "of the atoms specifies using SPECIESB is within the specified cutoff.  As with the species keyword the input can also be specified "
     105             :            "using the label of another multicolvar");
     106         352 :   keys.add("atoms-4","SPECIESB","this keyword is used for colvars such as the coordination number.  It must appear with SPECIESA.  For a full explanation see "
     107             :            "the documentation for that keyword");
     108         352 :   keys.add("compulsory","NN","6","The n parameter of the switching function ");
     109         352 :   keys.add("compulsory","MM","0","The m parameter of the switching function; 0 implies 2*NN");
     110         352 :   keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function");
     111         352 :   keys.add("compulsory","R_0","The r_0 parameter of the switching function");
     112         352 :   keys.add("optional","SWITCH","the switching function that it used in the construction of the contact matrix");
     113         176 :   multicolvar::MultiColvarShortcuts::shortcutKeywords( keys );
     114         352 :   keys.needsAction("CONTACT_MATRIX"); keys.needsAction("GROUP");
     115         176 : }
     116             : 
     117         108 : void CoordinationNumbers::expandMatrix( const bool& components, const std::string& lab, const std::string& sp_str,
     118             :                                         const std::string& spa_str, const std::string& spb_str, ActionShortcut* action ) {
     119         108 :   if( sp_str.length()==0 && spa_str.length()==0 ) return;
     120             : 
     121         108 :   std::string matinp = lab  + "_mat: CONTACT_MATRIX";
     122         108 :   if( sp_str.length()>0 ) {
     123          69 :     matinp += " GROUP=" + sp_str;
     124         138 :     action->readInputLine( lab + "_grp: GROUP ATOMS=" + sp_str );
     125          39 :   } else if( spa_str.length()>0 ) {
     126          78 :     matinp += " GROUPA=" + spa_str + " GROUPB=" + spb_str;
     127          78 :     action->readInputLine( lab + "_grp: GROUP ATOMS=" + spa_str );
     128             :   }
     129             : 
     130         216 :   std::string sw_str; action->parse("SWITCH",sw_str);
     131         108 :   if( sw_str.length()>0 ) {
     132         162 :     matinp += " SWITCH={" + sw_str + "}";
     133             :   } else {
     134          81 :     std::string r0; action->parse("R_0",r0); std::string d0; action->parse("D_0",d0);
     135          27 :     if( r0.length()==0 ) action->error("missing switching function parameters use SWITCH/R_0");
     136          54 :     std::string nn; action->parse("NN",nn); std::string mm; action->parse("MM",mm);
     137          54 :     matinp += " R_0=" + r0 + " D_0=" + d0 + " NN=" + nn + " MM=" + mm;
     138             :   }
     139         108 :   if( components ) matinp += " COMPONENTS";
     140         108 :   action->readInputLine( matinp );
     141             : }
     142             : 
     143          67 : void CoordinationNumbers::registerKeywords( Keywords& keys ) {
     144          67 :   shortcutKeywords( keys );
     145         134 :   keys.add("compulsory","R_POWER","the power to which you want to raise the distance");
     146         134 :   keys.addFlag("LOWMEM",false,"this flag does nothing and is present only to ensure back-compatibility");
     147         134 :   keys.add("optional","MOMENTS","the list of moments that you would like to calculate");
     148         134 :   keys.addOutputComponent("moment","MOMENTS","scalar","the moments of the distribution");
     149         201 :   keys.needsAction("MATRIX_VECTOR_PRODUCT"); keys.needsAction("ONES"); keys.needsAction("MOMENTS");
     150         134 :   keys.setValueDescription("vector","the coordination numbers of the specified atoms");
     151          67 : }
     152             : 
     153          45 : CoordinationNumbers::CoordinationNumbers(const ActionOptions& ao):
     154             :   Action(ao),
     155          45 :   ActionShortcut(ao)
     156             : {
     157          45 :   bool lowmem; parseFlag("LOWMEM",lowmem);
     158          45 :   if( lowmem ) warning("LOWMEM flag is deprecated and is no longer required for this action");
     159             :   // Setup the contract matrix if that is what is needed
     160             :   std::string matlab, sp_str, specA, specB;
     161         180 :   parse("SPECIES",sp_str); parse("SPECIESA",specA); parse("SPECIESB",specB);
     162          45 :   if( sp_str.length()>0 || specA.length()>0 ) {
     163          90 :     matlab = getShortcutLabel() + "_mat"; bool comp=false;
     164          48 :     if( getName()=="COORDINATION_MOMENTS" ) { comp=true; matlab = getShortcutLabel() + "_mat"; }
     165          45 :     expandMatrix( comp, getShortcutLabel(), sp_str, specA, specB, this );
     166           0 :   } else error("missing atoms input use SPECIES or SPECIESA/SPECIESB");
     167          45 :   ActionWithValue* mb=plumed.getActionSet().selectWithLabel<ActionWithValue*>( matlab );
     168          45 :   if( !mb ) error("could not find action with name " + matlab );
     169          45 :   Value*  arg=mb->copyOutput(0);
     170          45 :   if( arg->getRank()!=2 || arg->hasDerivatives() ) error("the input to this action should be a matrix or scalar");
     171             :   // Create vector of ones to multiply input matrix by
     172          45 :   std::string nones; Tools::convert( arg->getShape()[1], nones );
     173          90 :   readInputLine( getShortcutLabel() + "_ones: ONES SIZE=" + nones );
     174          45 :   if( getName()=="COORDINATION_MOMENTS" ) {
     175             :     // Calculate the lengths of the vectors
     176           3 :     std::string r_power; parse("R_POWER",r_power);
     177           9 :     readInputLine( getShortcutLabel() + "_pow: CUSTOM ARG=" + matlab + ".x," + matlab + ".y," + matlab + ".z," + matlab + ".w VAR=x,y,z,w "
     178           6 :                    + "PERIODIC=NO FUNC=w*(sqrt(x*x+y*y+z*z)^" + r_power +")");
     179           6 :     matlab = getShortcutLabel() + "_pow";
     180             :   }
     181             :   // Calcualte coordination numbers as matrix vector times vector of ones
     182          90 :   readInputLine( getShortcutLabel() + ": MATRIX_VECTOR_PRODUCT  ARG=" + matlab + "," + getShortcutLabel() + "_ones");
     183          90 :   std::vector<std::string> moments; parseVector("MOMENTS",moments); Tools::interpretRanges( moments );
     184          90 :   readInputLine( getShortcutLabel() + "_caverage: MEAN ARG=" + getShortcutLabel() + " PERIODIC=NO");
     185          47 :   for(unsigned i=0; i<moments.size(); ++i) {
     186           4 :     readInputLine( getShortcutLabel() + "_diffpow-" + moments[i] + ": CUSTOM ARG=" + getShortcutLabel() + "," + getShortcutLabel() + "_caverage PERIODIC=NO FUNC=(x-y)^" + moments[i] );
     187           4 :     readInputLine( getShortcutLabel() + "_moment-" + moments[i] + ": MEAN ARG=" + getShortcutLabel() + "_diffpow-" + moments[i] + " PERIODIC=NO");
     188             :   }
     189             :   // Read in all the shortcut stuff
     190          45 :   std::map<std::string,std::string> keymap; multicolvar::MultiColvarShortcuts::readShortcutKeywords( keymap, this );
     191          90 :   multicolvar::MultiColvarShortcuts::expandFunctions( getShortcutLabel(), getShortcutLabel(), "", keymap, this );
     192          90 : }
     193             : 
     194             : 
     195             : }
     196             : }

Generated by: LCOV version 1.16