LCOV - code coverage report
Current view: top level - colvar - GyrationShortcut.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 70 123 56.9 %
Date: 2025-11-25 13:55:50 Functions: 2 3 66.7 %

          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             :    See http://www.plumed.org for more information.
       5             :    This file is part of plumed, version 2.
       6             :    plumed is free software: you can redistribute it and/or modify
       7             :    it under the terms of the GNU Lesser General Public License as published by
       8             :    the Free Software Foundation, either version 3 of the License, or
       9             :    (at your option) any later version.
      10             :    plumed is distributed in the hope that it will be useful,
      11             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :    GNU Lesser General Public License for more details.
      14             :    You should have received a copy of the GNU Lesser General Public License
      15             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      16             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      17             : #include "core/ActionRegister.h"
      18             : #include "core/PlumedMain.h"
      19             : #include "core/ActionSet.h"
      20             : #include "core/ActionWithValue.h"
      21             : #include "core/ActionShortcut.h"
      22             : 
      23             : namespace PLMD {
      24             : namespace colvar {
      25             : 
      26             : //+PLUMEDOC COLVAR GYRATION
      27             : /*
      28             : Calculate the radius of gyration, or other properties related to it.
      29             : 
      30             : With this version of the command you can use any property you so choose to define the weights that are used when computing the average.
      31             : If you use the mass or if all the atoms are ascribed weights of one PLUMED defaults to \ref GYRATION_FAST
      32             : 
      33             : \par Examples
      34             : 
      35             : */
      36             : //+ENDPLUMEDOC
      37             : 
      38             : //+PLUMEDOC MCOLVAR GYRATION_TENSOR
      39             : /*
      40             : Calculate the gyration tensor using a user specified vector of weights
      41             : 
      42             : \par Examples
      43             : 
      44             : */
      45             : //+ENDPLUMEDOC
      46             : 
      47             : class GyrationShortcut : public ActionShortcut {
      48             : public:
      49             :   static void registerKeywords( Keywords& keys );
      50             :   explicit GyrationShortcut(const ActionOptions&);
      51             : };
      52             : 
      53             : PLUMED_REGISTER_ACTION(GyrationShortcut,"GYRATION")
      54             : PLUMED_REGISTER_ACTION(GyrationShortcut,"GYRATION_TENSOR")
      55             : 
      56         122 : void GyrationShortcut::registerKeywords( Keywords& keys ) {
      57         122 :   ActionShortcut::registerKeywords( keys );
      58         244 :   keys.add("atoms","ATOMS","the group of atoms that you are calculating the Gyration Tensor for");
      59         244 :   keys.add("compulsory","TYPE","RADIUS","The type of calculation relative to the Gyration Tensor you want to perform");
      60         244 :   keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
      61         244 :   keys.add("optional","WEIGHTS","what weights should be used when calculating the center.  If this keyword is not present the geometric center is computed. "
      62             :            "If WEIGHTS=@Masses is used the center of mass is computed.  If WEIGHTS=@charges the center of charge is computed.  If "
      63             :            "the label of an action is provided PLUMED assumes that that action calculates a list of symmetry functions that can be used "
      64             :            "as weights. Lastly, an explicit list of numbers to use as weights can be provided");
      65         244 :   keys.addFlag("PHASES",false,"use trigonometric phases when computing position of center of mass");
      66         244 :   keys.addFlag("MASS",false,"calculate the center of mass");
      67         244 :   keys.addFlag("MASS_WEIGHTED",false,"set the masses of all the atoms equal to one");
      68         244 :   keys.addFlag("UNORMALIZED",false,"do not divide by the sum of the weights");
      69         122 :   keys.setValueDescription("the radius that was computed from the weights");
      70         122 :   keys.addActionNameSuffix("_FAST");
      71         122 :   keys.needsAction("CENTER");
      72         122 :   keys.needsAction("CONSTANT");
      73         122 :   keys.needsAction("ONES");
      74         122 :   keys.needsAction("MASS");
      75         122 :   keys.needsAction("DISTANCE");
      76         122 :   keys.needsAction("COVARIANCE_MATRIX");
      77         122 :   keys.needsAction("SELECT_COMPONENTS");
      78         122 :   keys.needsAction("SUM");
      79         122 :   keys.needsAction("CUSTOM");
      80         122 :   keys.needsAction("DIAGONALIZE");
      81         122 : }
      82             : 
      83         116 : GyrationShortcut::GyrationShortcut(const ActionOptions& ao):
      84             :   Action(ao),
      85         116 :   ActionShortcut(ao) {
      86             :   bool usemass, phases;
      87         116 :   parseFlag("MASS",usemass);
      88         232 :   parseFlag("PHASES",phases);
      89             :   std::vector<std::string> str_weights;
      90         232 :   parseVector("WEIGHTS",str_weights);
      91             :   std::string wflab;
      92         116 :   if( !phases ) {
      93         115 :     if( usemass || str_weights.size()==0 || (str_weights.size()==1 && str_weights[0]=="@Masses") ) {
      94             :       std::string wt_str;
      95         112 :       if( str_weights.size()>0 ) {
      96           0 :         wt_str="WEIGHTS=" + str_weights[0];
      97           0 :         for(unsigned i=1; i<str_weights.size(); ++i) {
      98           0 :           wt_str += "," + str_weights[i];
      99             :         }
     100             :       }
     101         112 :       if( usemass || (str_weights.size()==1 && str_weights[0]=="@Masses") ) {
     102             :         wt_str = "MASS";
     103             :       }
     104         232 :       readInputLine( getShortcutLabel() + ": GYRATION_FAST " + wt_str + " " + convertInputLineToString() );
     105             :       return;
     106             :     }
     107             :   }
     108           4 :   if( usemass ) {
     109           0 :     str_weights.resize(1);
     110             :     str_weights[0]="@Masses";
     111             :   }
     112          10 :   log<<"  Bibliography "<<plumed.cite("Jirí Vymetal and Jirí Vondrasek, J. Phys. Chem. A 115, 11455 (2011)")<<"\n";
     113             :   // Read in the atoms involved
     114             :   std::vector<std::string> atoms;
     115           4 :   parseVector("ATOMS",atoms);
     116           4 :   Tools::interpretRanges(atoms);
     117           4 :   std::string gtype, atlist=atoms[0];
     118          12 :   for(unsigned i=1; i<atoms.size(); ++i) {
     119          16 :     atlist += "," + atoms[i];
     120             :   }
     121             :   bool nopbc;
     122           8 :   parseFlag("NOPBC",nopbc);
     123             :   std::string pbcstr;
     124           4 :   if(nopbc) {
     125             :     pbcstr = " NOPBC";
     126             :   }
     127             :   std::string phasestr;
     128           4 :   if(phases) {
     129             :     phasestr = " PHASES";
     130             :   }
     131             :   // Create the geometric center of the molecule
     132           4 :   std::string weights_str=" WEIGHTS=" + str_weights[0];
     133           8 :   for(unsigned i=1; i<str_weights.size(); ++i) {
     134           8 :     weights_str += "," + str_weights[i];
     135             :   }
     136           8 :   readInputLine( getShortcutLabel() + "_cent: CENTER ATOMS=" + atlist + pbcstr + phasestr + weights_str );
     137           4 :   if( str_weights.size()==0 ) {
     138           0 :     wflab = getShortcutLabel() + "_w";
     139             :     std::string str_natoms;
     140           0 :     Tools::convert( atoms.size(), str_natoms );
     141           0 :     readInputLine( getShortcutLabel() + "_w: ONES SIZE=" + str_natoms );
     142           6 :   } else if( str_weights.size()==1 && str_weights[0]=="@Masses" ) {
     143           0 :     wflab = getShortcutLabel() + "_m";
     144           0 :     readInputLine( getShortcutLabel() + "_m: MASS ATOMS=" + atlist );
     145           4 :   } else if( str_weights.size()>1 ) {
     146           2 :     std::string vals=str_weights[0];
     147           6 :     for(unsigned i=1; i<str_weights.size(); ++i) {
     148           8 :       vals += "," + str_weights[i];
     149             :     }
     150           4 :     readInputLine( getShortcutLabel() + "_w: CONSTANT VALUES=" + vals );
     151           4 :     wflab=getShortcutLabel() + "_w";
     152             :   } else {
     153           2 :     plumed_assert( str_weights.size()==1 );
     154           2 :     wflab = getShortcutLabel() + "_cent_w";
     155           2 :     ActionWithValue* av=plumed.getActionSet().selectWithLabel<ActionWithValue*>( wflab );
     156           2 :     if( !av ) {
     157             :       wflab = str_weights[0];
     158             :     }
     159             :   }
     160             :   // Check for normalisation
     161             :   bool unorm;
     162           8 :   parseFlag("UNORMALIZED",unorm);
     163             :   // Find out the type
     164           4 :   if( getName()!="GYRATION_TENSOR" ) {
     165           0 :     parse("TYPE",gtype);
     166           0 :     if( gtype!="RADIUS" && gtype!="TRACE" && gtype!="GTPC_1" && gtype!="GTPC_2" && gtype!="GTPC_3" && gtype!="ASPHERICITY" && gtype!="ACYLINDRICITY"
     167           0 :         && gtype!= "KAPPA2" && gtype!="RGYR_1" && gtype!="RGYR_2" && gtype!="RGYR_3" ) {
     168           0 :       error("type " + gtype + " is invalid");
     169             :     }
     170             :     // Check if we need to calculate the unormlised radius
     171           0 :     if( gtype=="TRACE" || gtype=="KAPPA2" ) {
     172           0 :       unorm=true;
     173             :     }
     174             :   }
     175             :   // Compute all the vectors separating all the positions from the center
     176           4 :   std::string distance_act = getShortcutLabel() + "_dists: DISTANCE COMPONENTS" + pbcstr;
     177          16 :   for(unsigned i=0; i<atoms.size(); ++i) {
     178             :     std::string num;
     179          12 :     Tools::convert( i+1, num );
     180          24 :     distance_act += " ATOMS" + num + "=" + getShortcutLabel() + "_cent," + atoms[i];
     181             :   }
     182           4 :   readInputLine( distance_act );
     183             :   // And calculate the covariance
     184             :   std::string norm_str;
     185           4 :   if( unorm ) {
     186             :     norm_str = " UNORMALIZED";
     187             :   }
     188           4 :   if( getName()=="GYRATION_TENSOR" ) {
     189           8 :     readInputLine( getShortcutLabel() + ": COVARIANCE_MATRIX ARG=" + getShortcutLabel() + "_dists.x," + getShortcutLabel() + "_dists.y," + getShortcutLabel() + "_dists.z WEIGHTS=" + wflab + norm_str );
     190             :     return;
     191             :   }
     192           0 :   readInputLine( getShortcutLabel() + "_tensor: COVARIANCE_MATRIX ARG=" + getShortcutLabel() + "_dists.x," + getShortcutLabel() + "_dists.y," + getShortcutLabel() + "_dists.z WEIGHTS=" + wflab + norm_str );
     193             :   // Pick out the diagonal elements
     194           0 :   readInputLine( getShortcutLabel() + "_diag_elements: SELECT_COMPONENTS ARG=" + getShortcutLabel() + "_tensor COMPONENTS=1.1,2.2,3.3");
     195           0 :   if( gtype=="RADIUS") {
     196             :     // And now we need the average trace for the gyration radius
     197           0 :     readInputLine( getShortcutLabel() + "_trace: SUM ARG=" + getShortcutLabel() + "_diag_elements PERIODIC=NO");
     198             :     // Square root the radius
     199           0 :     readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_trace FUNC=sqrt(x) PERIODIC=NO");
     200           0 :   } else if( gtype=="TRACE" ) {
     201             :     // Compte the trace of the gyration tensor
     202           0 :     readInputLine( getShortcutLabel() + "_trace: SUM ARG=" + getShortcutLabel() + "_diag_elements PERIODIC=NO");
     203             :     // And double it
     204           0 :     readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_trace FUNC=2*x PERIODIC=NO");
     205             :   } else {
     206             :     // Diagonalize the gyration tensor
     207           0 :     readInputLine( getShortcutLabel() + "_diag: DIAGONALIZE ARG=" + getShortcutLabel() + "_tensor VECTORS=all" );
     208           0 :     if( gtype.find("GTPC")!=std::string::npos ) {
     209           0 :       std::size_t und=gtype.find_first_of("_");
     210           0 :       if( und==std::string::npos ) {
     211           0 :         error( gtype + " is not a valid type for gyration radius");
     212             :       }
     213           0 :       std::string num = gtype.substr(und+1);
     214           0 :       if( num!="1" && num!="2" && num!="3" ) {
     215           0 :         error( gtype + " is not a valid type for gyration radius");
     216             :       }
     217             :       // Now get the appropriate eigenvalue
     218           0 :       readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-" + num + " FUNC=sqrt(x) PERIODIC=NO");
     219           0 :     } else if( gtype.find("RGYR")!=std::string::npos ) {
     220           0 :       std::size_t und=gtype.find_first_of("_");
     221           0 :       if( und==std::string::npos ) {
     222           0 :         error( gtype + " is not a valid type for gyration radius");
     223             :       }
     224             :       unsigned ind;
     225           0 :       Tools::convert( gtype.substr(und+1), ind );
     226             :       // Now get the appropriate quantity
     227           0 :       if( ind==3 ) {
     228           0 :         readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + "_diag.vals-2 FUNC=sqrt(x+y) PERIODIC=NO");
     229           0 :       } else if( ind==2 ) {
     230           0 :         readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + "_diag.vals-3 FUNC=sqrt(x+y) PERIODIC=NO");
     231           0 :       } else if( ind==1 ) {
     232           0 :         readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-2," + getShortcutLabel() + "_diag.vals-3 FUNC=sqrt(x+y) PERIODIC=NO");
     233             :       } else {
     234           0 :         error( gtype + " is not a valid type for gyration radius");
     235             :       }
     236           0 :     } else if( gtype=="ASPHERICITY" ) {
     237           0 :       readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + "_diag.vals-2," + getShortcutLabel() + "_diag.vals-3 FUNC=sqrt(x-0.5*(y+z)) PERIODIC=NO" );
     238           0 :     } else if( gtype=="ACYLINDRICITY" ) {
     239           0 :       readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-2," + getShortcutLabel() + "_diag.vals-3 FUNC=sqrt(x-y) PERIODIC=NO" );
     240           0 :     } else if( gtype=="KAPPA2" ) {
     241           0 :       readInputLine( getShortcutLabel() + "_numer: CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + "_diag.vals-2," + getShortcutLabel() + "_diag.vals-3 FUNC=x*y+x*z+y*z PERIODIC=NO" );
     242           0 :       readInputLine( getShortcutLabel() + "_denom: CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + "_diag.vals-2," + getShortcutLabel() + "_diag.vals-3 FUNC=x+y+z PERIODIC=NO" );
     243           0 :       readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_numer," + getShortcutLabel() + "_denom FUNC=1-3*(x/(y*y)) PERIODIC=NO");
     244             :     } else {
     245           0 :       error( gtype + " is not a valid type for gyration radius");
     246             :     }
     247             :   }
     248         124 : }
     249             : 
     250             : }
     251             : }

Generated by: LCOV version 1.16