LCOV - code coverage report
Current view: top level - multicolvar - MultiColvarShortcuts.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 170 195 87.2 %
Date: 2025-04-08 21:11:17 Functions: 5 5 100.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 "MultiColvarShortcuts.h"
      23             : #include "core/PlumedMain.h"
      24             : #include "core/ActionSet.h"
      25             : #include "core/Group.h"
      26             : 
      27             : namespace PLMD {
      28             : namespace multicolvar {
      29             : 
      30         735 : void MultiColvarShortcuts::shortcutKeywords( Keywords& keys ) {
      31         735 :   keys.add("numbered","LESS_THAN","calculate the number of variables that are less than a certain target value. "
      32             :            "This quantity is calculated using \\f$\\sum_i \\sigma(s_i)\\f$, where \\f$\\sigma(s)\\f$ "
      33             :            "is a \\ref switchingfunction.");
      34        1470 :   keys.linkActionInDocs("LESS_THAN","LESS_THAN");
      35        1470 :   keys.addOutputComponent("lessthan","LESS_THAN","scalar","the number of colvars that have a value less than a threshold");
      36         735 :   keys.add("numbered","MORE_THAN","calculate the number of variables that are more than a certain target value. "
      37             :            "This quantity is calculated using \\f$\\sum_i 1 - \\sigma(s_i)\\f$, where \\f$\\sigma(s)\\f$ "
      38             :            "is a \\ref switchingfunction.");
      39        1470 :   keys.linkActionInDocs("MORE_THAN","MORE_THAN");
      40        1470 :   keys.addOutputComponent("morethan","MORE_THAN","scalar","the number of colvars that have a value more than a threshold");
      41         735 :   keys.add("optional","ALT_MIN","calculate the minimum value. "
      42             :            "To make this quantity continuous the minimum is calculated using "
      43             :            "\\f$ \\textrm{min} = -\\frac{1}{\\beta} \\log \\sum_i \\exp\\left( -\\beta s_i \\right)  \\f$ "
      44             :            "The value of \\f$\\beta\\f$ in this function is specified using (BETA=\\f$\\beta\\f$).");
      45        1470 :   keys.addOutputComponent("altmin","ALT_MIN","scalar","the minimum value of the cv");
      46         735 :   keys.add("optional","MIN","calculate the minimum value. "
      47             :            "To make this quantity continuous the minimum is calculated using "
      48             :            "\\f$ \\textrm{min} = \\frac{\\beta}{ \\log \\sum_i \\exp\\left( \\frac{\\beta}{s_i} \\right) } \\f$ "
      49             :            "The value of \\f$\\beta\\f$ in this function is specified using (BETA=\\f$\\beta\\f$)");
      50        1470 :   keys.addOutputComponent("min","MIN","scalar","the minimum colvar");
      51         735 :   keys.add("optional","MAX","calculate the maximum value. "
      52             :            "To make this quantity continuous the maximum is calculated using "
      53             :            "\\f$ \\textrm{max} = \\beta \\log \\sum_i \\exp\\left( \\frac{s_i}{\\beta}\\right) \\f$ "
      54             :            "The value of \\f$\\beta\\f$ in this function is specified using (BETA=\\f$\\beta\\f$)");
      55        1470 :   keys.addOutputComponent("max","MAX","scalar","the maximum colvar");
      56         735 :   keys.add("numbered","BETWEEN","calculate the number of values that are within a certain range. "
      57             :            "These quantities are calculated using kernel density estimation as described on "
      58             :            "\\ref histogrambead.");
      59        1470 :   keys.linkActionInDocs("BETWEEN","BETWEEN");
      60        1470 :   keys.addOutputComponent("between","BETWEEN","scalar","the number of colvars that have a value that lies in a particular interval");
      61         735 :   keys.addFlag("HIGHEST",false,"this flag allows you to recover the highest of these variables.");
      62        1470 :   keys.addOutputComponent("highest","HIGHEST","scalar","the largest of the colvars");
      63         735 :   keys.add("optional","HISTOGRAM","calculate a discretized histogram of the distribution of values. "
      64             :            "This shortcut allows you to calculates NBIN quantites like BETWEEN.");
      65         735 :   keys.addFlag("LOWEST",false,"this flag allows you to recover the lowest of these variables.");
      66        1470 :   keys.addOutputComponent("lowest","LOWEST","scalar","the smallest of the colvars");
      67         735 :   keys.addFlag("SUM",false,"calculate the sum of all the quantities.");
      68        1470 :   keys.addOutputComponent("sum","SUM","scalar","the sum of the colvars");
      69         735 :   keys.addFlag("MEAN",false,"calculate the mean of all the quantities.");
      70        1470 :   keys.addOutputComponent("mean","MEAN","scalar","the mean of the colvars");
      71         735 :   keys.needsAction("SUM");
      72         735 :   keys.needsAction("MEAN");
      73         735 :   keys.needsAction("CUSTOM");
      74         735 :   keys.needsAction("HIGHEST");
      75         735 :   keys.needsAction("LOWEST");
      76         735 :   keys.needsAction("LESS_THAN");
      77         735 :   keys.needsAction("MORE_THAN");
      78         735 :   keys.needsAction("BETWEEN");
      79         735 : }
      80             : 
      81         119 : void MultiColvarShortcuts::expandFunctions( const std::string& labout, const std::string& argin, const std::string& weights, ActionShortcut* action ) {
      82             :   std::map<std::string,std::string> keymap;
      83         119 :   readShortcutKeywords( keymap, action );
      84         119 :   expandFunctions( labout, argin, weights, keymap, action );
      85         119 : }
      86             : 
      87         231 : void MultiColvarShortcuts::readShortcutKeywords( std::map<std::string,std::string>& keymap, ActionShortcut* action ) {
      88         231 :   Keywords keys;
      89         231 :   shortcutKeywords( keys );
      90         231 :   action->readShortcutKeywords( keys, keymap );
      91         231 : }
      92             : 
      93          94 : void MultiColvarShortcuts::parseAtomList( const std::string& key, std::vector<std::string>& atoms, ActionShortcut* action ) {
      94             :   std::vector<std::string> astr;
      95          94 :   action->parseVector(key,astr);
      96          94 :   if( astr.size()==0 ) {
      97             :     return ;
      98             :   }
      99          28 :   Tools::interpretRanges( astr );
     100        1265 :   for(unsigned i=0; i<astr.size(); ++i) {
     101        1237 :     Group* mygr=action->plumed.getActionSet().selectWithLabel<Group*>(astr[i]);
     102        1237 :     if( mygr ) {
     103           1 :       std::vector<std::string> grstr( mygr->getGroupAtoms() );
     104         101 :       for(unsigned j=0; j<grstr.size(); ++j) {
     105         100 :         atoms.push_back(grstr[j]);
     106             :       }
     107           1 :     } else {
     108        1236 :       Group* mygr2=action->plumed.getActionSet().selectWithLabel<Group*>(astr[i] + "_grp");
     109        1236 :       if( mygr2 ) {
     110          10 :         std::vector<std::string> grstr( mygr2->getGroupAtoms() );
     111       16082 :         for(unsigned j=0; j<grstr.size(); ++j) {
     112       16072 :           atoms.push_back(grstr[j]);
     113             :         }
     114          10 :       } else {
     115        1226 :         atoms.push_back(astr[i]);
     116             :       }
     117             :     }
     118             :   }
     119          94 : }
     120             : 
     121         240 : void MultiColvarShortcuts::expandFunctions( const std::string& labout, const std::string& argin, const std::string& weights,
     122             :     const std::map<std::string,std::string>& keymap, ActionShortcut* action ) {
     123         240 :   if( keymap.empty() ) {
     124          93 :     return;
     125             :   }
     126             :   // Parse LESS_THAN
     127         294 :   if( keymap.count("LESS_THAN") ) {
     128          16 :     std::string sum_arg = labout + "_lt", lt_string = keymap.find("LESS_THAN")->second;
     129          16 :     action->readInputLine( labout + "_lt: LESS_THAN ARG=" + argin + " SWITCH={" + lt_string + "}");
     130           8 :     if( weights.length()>0 ) {
     131           1 :       sum_arg = labout + "_wlt";
     132           2 :       action->readInputLine( labout + "_wlt: CUSTOM ARG=" + weights + "," + labout + "_lt FUNC=x*y PERIODIC=NO");
     133             :     }
     134          16 :     action->readInputLine( labout + "_lessthan: SUM ARG=" + sum_arg + " PERIODIC=NO");
     135             :   }
     136         294 :   if( keymap.count("LESS_THAN1") ) {
     137           2 :     for(unsigned i=1;; ++i) {
     138             :       std::string istr;
     139           6 :       Tools::convert( i, istr );
     140          12 :       if( !keymap.count("LESS_THAN" + istr ) ) {
     141             :         break;
     142             :       }
     143          12 :       std::string sum_arg = labout + "_lt" + istr, lt_string1 = keymap.find("LESS_THAN" + istr)->second;
     144           8 :       action->readInputLine( labout + "_lt" + istr + ": LESS_THAN ARG=" + argin + " SWITCH={" + lt_string1 + "}");
     145           4 :       if( weights.length()>0 ) {
     146           0 :         sum_arg = labout + "_wlt" + istr;
     147           0 :         action->readInputLine( labout + "_wlt" + istr + ": CUSTOM ARG=" + weights + "," + labout + "_lt" + istr + " FUNC=x*y PERIODIC=NO");
     148             :       }
     149           8 :       action->readInputLine( labout + "_lessthan-" + istr + ": SUM ARG=" + sum_arg + " PERIODIC=NO");
     150           4 :     }
     151             :   }
     152             :   // Parse MORE_THAN
     153         294 :   if( keymap.count("MORE_THAN") ) {
     154          48 :     std::string sum_arg=labout + "_mt", mt_string = keymap.find("MORE_THAN")->second;
     155          48 :     action->readInputLine( labout + "_mt: MORE_THAN ARG=" + argin + " SWITCH={" + mt_string + "}");
     156          24 :     if( weights.length()>0 ) {
     157           1 :       sum_arg = labout + "_wmt";
     158           2 :       action->readInputLine( labout + "_wmt: CUSTOM ARG=" + weights + "," + labout + "_mt FUNC=x*y PERIODIC=NO" );
     159             :     }
     160          48 :     action->readInputLine( labout + "_morethan: SUM ARG=" + sum_arg + " PERIODIC=NO");
     161             :   }
     162         294 :   if(  keymap.count("MORE_THAN1") ) {
     163           0 :     for(unsigned i=1;; ++i) {
     164             :       std::string istr;
     165           0 :       Tools::convert( i, istr );
     166           0 :       if( !keymap.count("MORE_THAN" + istr ) ) {
     167             :         break;
     168             :       }
     169           0 :       std::string sum_arg = labout + "_mt" + istr, mt_string1 = keymap.find("MORE_THAN" + istr)->second;
     170           0 :       action->readInputLine( labout + "_mt" + istr + ": MORE_THAN ARG=" + argin + " SWITCH={" + mt_string1 + "}");
     171           0 :       if( weights.length()>0 ) {
     172           0 :         sum_arg = labout + "_wmt" + istr;
     173           0 :         action->readInputLine( labout + "_wmt" + istr + ": CUSTOM ARG=" + weights + "," + labout + "_lt" + istr + " FUNC=x*y PERIODIC=NO");
     174             :       }
     175           0 :       action->readInputLine( labout + "_morethan-" + istr + ": SUM ARG=" + sum_arg + " PERIODIC=NO");
     176           0 :     }
     177             :   }
     178             :   // Parse ALT_MIN
     179         294 :   if( keymap.count("ALT_MIN") ) {
     180           1 :     if( weights.length()>0 ) {
     181           0 :       plumed_merror("cannot use ALT_MIN with this shortcut");
     182             :     }
     183           2 :     std::string amin_string = keymap.find("ALT_MIN")->second;
     184           1 :     std::size_t dd = amin_string.find("BETA");
     185           1 :     std::string beta_str = amin_string.substr(dd+5);
     186           1 :     beta_str.erase(std::remove_if(beta_str.begin(), beta_str.end(), ::isspace), beta_str.end());
     187           2 :     action->readInputLine( labout + "_me_altmin: CUSTOM ARG=" + argin + " FUNC=exp(-x*" + beta_str + ") PERIODIC=NO");
     188           2 :     action->readInputLine( labout + "_mec_altmin: SUM ARG=" + labout + "_me_altmin PERIODIC=NO");
     189           2 :     action->readInputLine( labout + "_altmin: CUSTOM ARG=" + labout + "_mec_altmin FUNC=-log(x)/" + beta_str + " PERIODIC=NO");
     190             :   }
     191             :   // Parse MIN
     192         294 :   if( keymap.count("MIN") ) {
     193           1 :     if( weights.length()>0 ) {
     194           0 :       plumed_merror("cannot use MIN with this shortcut");
     195             :     }
     196           2 :     std::string min_string = keymap.find("MIN")->second;
     197           1 :     std::size_t dd = min_string.find("BETA");
     198           1 :     std::string beta_str = min_string.substr(dd+5);
     199           1 :     beta_str.erase(std::remove_if(beta_str.begin(), beta_str.end(), ::isspace), beta_str.end());
     200           2 :     action->readInputLine( labout + "_me_min: CUSTOM ARG=" + argin + " FUNC=exp(" + beta_str + "/x) PERIODIC=NO");
     201           2 :     action->readInputLine( labout + "_mec_min: SUM ARG=" + labout + "_me_min PERIODIC=NO");
     202           2 :     action->readInputLine( labout + "_min: CUSTOM ARG=" + labout + "_mec_min FUNC=" + beta_str + "/log(x) PERIODIC=NO");
     203             :   }
     204             :   // Parse MAX
     205         294 :   if( keymap.count("MAX") ) {
     206           3 :     if( weights.length()>0 ) {
     207           0 :       plumed_merror("cannot use MAX with this shortcut");
     208             :     }
     209           6 :     std::string max_string = keymap.find("MAX")->second;
     210           3 :     std::size_t dd = max_string.find("BETA");
     211           3 :     std::string beta_str = max_string.substr(dd+5);
     212           3 :     beta_str.erase(std::remove_if(beta_str.begin(), beta_str.end(), ::isspace), beta_str.end());
     213           6 :     action->readInputLine( labout + "_me_max: CUSTOM ARG=" + argin + " FUNC=exp(x/" + beta_str + ") PERIODIC=NO");
     214           6 :     action->readInputLine( labout + "_mec_max: SUM ARG=" + labout + "_me_max PERIODIC=NO");
     215           6 :     action->readInputLine( labout + "_max: CUSTOM ARG=" + labout + "_mec_max FUNC=" + beta_str  + "*log(x) PERIODIC=NO");
     216             :   }
     217             :   // Parse HIGHEST
     218         294 :   if( keymap.count("HIGHEST") ) {
     219           8 :     if( weights.length()>0 ) {
     220           0 :       plumed_merror("cannot use HIGHEST with this shortcut");
     221             :     }
     222          16 :     action->readInputLine( labout + "_highest: HIGHEST ARG=" + argin );
     223             :   }
     224             :   // Parse LOWEST
     225         294 :   if( keymap.count("LOWEST") ) {
     226           3 :     if( weights.length()>0 ) {
     227           0 :       plumed_merror("cannot use LOWEST with this shortcut");
     228             :     }
     229           6 :     action->readInputLine( labout + "_lowest: LOWEST ARG=" + argin );
     230             :   }
     231             :   // Parse SUM
     232         294 :   if( keymap.count("SUM") ) {
     233          44 :     std::string sum_arg=argin;
     234          44 :     if( weights.length()>0 ) {
     235          22 :       sum_arg = labout + "_wsum";
     236          44 :       action->readInputLine( labout + "_wsum: CUSTOM ARG=" + weights + "," + argin + " FUNC=x*y PERIODIC=NO");
     237             :     }
     238          88 :     action->readInputLine( labout + "_sum: SUM ARG=" + sum_arg + " PERIODIC=NO");
     239             :   }
     240             :   // Parse MEAN
     241         294 :   if( keymap.count("MEAN") ) {
     242          64 :     if( weights.length()>0 ) {
     243           0 :       plumed_merror("cannot use MEAN with this shortcut");
     244             :     }
     245         128 :     action->readInputLine( labout + "_mean: MEAN ARG=" + argin + " PERIODIC=NO");
     246             :   }
     247             :   // Parse BETWEEN
     248         294 :   if( keymap.count("BETWEEN") ) {
     249          16 :     std::string sum_arg=labout + "_bt", bt_string = keymap.find("BETWEEN")->second;
     250          16 :     action->readInputLine( labout + "_bt: BETWEEN ARG=" + argin + " SWITCH={" + bt_string + "}" );
     251           8 :     if( weights.length()>0 ) {
     252           0 :       sum_arg = labout + "_wbt";
     253           0 :       action->readInputLine( labout + "_wbt: CUSTOM ARG=" + weights + "," + labout + "_bt FUNC=x*y PERIODIC=NO");
     254             :     }
     255          16 :     action->readInputLine( labout + "_between: SUM ARG=" + sum_arg + " PERIODIC=NO");
     256             :   }
     257             :   std::string bt_string1;
     258         294 :   if( keymap.count("BETWEEN1") ) {
     259           6 :     for(unsigned i=1;; ++i) {
     260             :       std::string istr;
     261          17 :       Tools::convert( i, istr );
     262          34 :       if( !keymap.count("BETWEEN" + istr) ) {
     263             :         break;
     264             :       }
     265          33 :       std::string sum_arg=labout + "_bt" + istr, bt_string1 = keymap.find("BETWEEN" + istr)->second;
     266          22 :       action->readInputLine( labout + "_bt" + istr + ": BETWEEN ARG=" + argin + " SWITCH={" + bt_string1 + "}" );
     267          11 :       if( weights.length()>0 ) {
     268           2 :         sum_arg = labout + "_wbt" + istr;
     269           2 :         action->readInputLine( labout + "_wbt" + istr + ": CUSTOM ARG=" + weights + "," + labout + "_bt" + istr + " FUNC=x*y PERIODIC=NO");
     270             :       }
     271          22 :       action->readInputLine( labout + "_between-" + istr + ": SUM ARG=" + sum_arg + " PERIODIC=NO");
     272          11 :     }
     273             :   }
     274             :   // Parse HISTOGRAM
     275         294 :   if( keymap.count("HISTOGRAM") ) {
     276          24 :     std::vector<std::string> words=Tools::getWords( keymap.find("HISTOGRAM")->second );
     277             :     unsigned nbins;
     278          12 :     bool found=Tools::parse(words,"NBINS",nbins,0); // Need replica index
     279          12 :     if( !found ) {
     280           0 :       plumed_merror("did not find NBINS in specification for HISTOGRAM");
     281             :     }
     282             :     double lower;
     283          12 :     found=Tools::parse(words,"LOWER",lower,0);
     284          12 :     if( !found ) {
     285           0 :       plumed_merror("did not find LOWER in specification for HISTOGRAM");
     286             :     }
     287             :     double upper;
     288          12 :     found=Tools::parse(words,"UPPER",upper,0);
     289          12 :     if( !found ) {
     290           0 :       plumed_merror("did not find UPPER in specification for HISTOGRAM");
     291             :     }
     292          12 :     double delr = ( upper - lower ) / static_cast<double>( nbins );
     293          12 :     double smear=0.5;
     294          12 :     found=Tools::parse(words,"SMEAR",smear,0);
     295          12 :     if( !found ) {
     296           5 :       smear = 0.5;
     297             :     }
     298          41 :     for(unsigned i=0; i<nbins; ++i) {
     299             :       std::string smstr, istr;
     300          29 :       Tools::convert( i+1, istr );
     301          29 :       Tools::convert( smear, smstr );
     302          58 :       std::string sum_arg=labout + "_bt" + istr;
     303             :       std::string low_str, high_str;
     304          29 :       Tools::convert( lower + i*delr, low_str );
     305          29 :       Tools::convert( lower + (i+1)*delr, high_str );
     306          58 :       action->readInputLine( labout + "_bt" + istr + ": BETWEEN ARG=" + argin + " SWITCH={" + words[0] + " LOWER=" + low_str + " UPPER=" + high_str + " SMEAR=" + smstr + "}");
     307          29 :       if( weights.length()>0 ) {
     308           0 :         sum_arg = labout + "_wbt" + istr;
     309           0 :         action->readInputLine( labout + "_wbt" + istr + ": CUSTOM ARG=" + weights + "," + labout + "_bt" + istr + " FUNC=x*y PERIODIC=NO");
     310             :       }
     311          58 :       action->readInputLine( labout + "_between-" + istr + ": SUM ARG=" + sum_arg + " PERIODIC=NO");
     312             :     }
     313          12 :   }
     314             : }
     315             : 
     316             : }
     317             : }

Generated by: LCOV version 1.16