LCOV - code coverage report
Current view: top level - symfunc - LocalSteinhardt.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 135 167 80.8 %
Date: 2025-12-04 11:19:34 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2015-2017 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/ActionShortcut.h"
      23             : #include "core/ActionRegister.h"
      24             : #include "multicolvar/MultiColvarShortcuts.h"
      25             : #include "core/PlumedMain.h"
      26             : #include "core/ActionSet.h"
      27             : #include "core/ActionWithValue.h"
      28             : 
      29             : namespace PLMD {
      30             : namespace symfunc {
      31             : 
      32             : //+PLUMEDOC MCOLVARF LOCAL_Q1
      33             : /*
      34             : Calculate the local degree of order around an atoms by taking the average dot product between the q_1 vector on the central atom and the q_3 vector on the atoms in the first coordination sphere.
      35             : 
      36             : The [Q1](Q1.md) command allows one to calculate one complex vector for each of the atoms in your system that describe the degree of order in the coordination sphere
      37             : around a particular atom. The difficulty with these vectors comes when combining the order parameters from all of the individual atoms/molecules so as to get a
      38             : measure of the global degree of order for the system. The simplest way of doing this - calculating the average Steinhardt parameter - can be problematic. If one is
      39             : examining nucleation say only the order parameters for those atoms in the nucleus will change significantly when the nucleus forms. The order parameters for the
      40             : atoms in the surrounding liquid will remain pretty much the same. As such if one models a small nucleus embedded in a very large amount of solution/melt any
      41             : change in the average order parameter will be negligible. Substantial changes in the value of this average can be observed in simulations of nucleation but only
      42             : because the number of atoms is relatively small.
      43             : 
      44             : When the average [Q1](Q1.md) parameter is used to bias the dynamics a problems
      45             : can occur. These averaged coordinates cannot distinguish between the correct,
      46             : single-nucleus pathway and a concerted pathway in which all the atoms rearrange
      47             : themselves into their solid-like configuration simultaneously. This second type
      48             : of pathway would be impossible in reality because there is a large entropic
      49             : barrier that prevents concerted processes like this from happening.  However,
      50             : in the finite sized systems that are commonly simulated this barrier is reduced
      51             : substantially. As a result in simulations where average Steinhardt parameters
      52             : are biased there are often quite dramatic system size effects
      53             : 
      54             : If one wants to simulate nucleation using some form on
      55             : biased dynamics what is really required is an order parameter that measures:
      56             : 
      57             : - Whether or not the coordination spheres around atoms are ordered
      58             : - Whether or not the atoms that are ordered are clustered together in a crystalline nucleus
      59             : 
      60             : As discussed on [this page](https://www.plumed-tutorials.org/lessons/23/001/data/Steinhardt.html) a variety of variations on the Steinhardt parameters have been
      61             : introduced to better describe nucleation. That page also shows how PLUMED provides you with flexibility that you can use to implement new combinations of the
      62             : Steinhardt parameters. However, the inputs that you would need to write to implement common symmetry functions are rather complex so we also provide shortcuts
      63             : like this one to help you compute CVs that have been widely used in the literature easily.
      64             : 
      65             : This particular shortcut allows you to compute the LOCAL_Q1 parameter for a particular atom, which is a number that measures the extent to
      66             : which the orientation of the atoms in the first coordination sphere of an atom match the orientation of the central atom.  It does this by calculating the following
      67             : quantity for each of the atoms in the system:
      68             : 
      69             : $$
      70             :  s_i = \frac{ \sum_j \sigma( r_{ij} ) \sum_{m=-1}^1 q_{1m}^{*}(i)q_{1m}(j) }{ \sum_j \sigma( r_{ij} ) }
      71             : $$
      72             : 
      73             : where $q_{1m}(i)$ and $q_{1m}(j)$ are the 1st order Steinhardt vectors calculated for atom $i$ and atom $j$ respectively and the asterisk denotes complex
      74             : conjugation.  The function
      75             : $\sigma( r_{ij} )$ is a switching function that acts on the distance between atoms $i$ and $j$.  The parameters of this function should be set
      76             : so that it the function is equal to one when atom $j$ is in the first coordination sphere of atom $i$ and is zero otherwise.  The sum in the numerator
      77             : of this expression is the dot product of the Steinhardt parameters for atoms $i$ and $j$ and thus measures the degree to which the orientations of these
      78             : adjacent atoms are correlated.
      79             : 
      80             : The following input shows how this works in practice.  This input calculates the average value of the LOCAL_Q1 parameter for the 64 Lennard Jones atoms in the system under study and prints this
      81             : quantity to a file called colvar.
      82             : 
      83             : ```plumed
      84             : q1: Q1 SPECIES=1-64 D_0=1.3 R_0=0.2
      85             : lq1: LOCAL_Q1 SPECIES=q1 SWITCH={RATIONAL D_0=1.3 R_0=0.2}
      86             : lq1_mean: MEAN ARG=lq1 PERIODIC=NO
      87             : PRINT ARG=lq1_mean FILE=colvar
      88             : ```
      89             : 
      90             : The following input calculates the distribution of LOCAL_Q1 parameters at any given time and outputs this information to a file.
      91             : 
      92             : ```plumed
      93             : q1: Q1 SPECIES=1-64 D_0=1.3 R_0=0.2
      94             : lq1: LOCAL_Q1 SPECIES=q1 SWITCH={RATIONAL D_0=1.3 R_0=0.2} HISTOGRAM={GAUSSIAN LOWER=0.0 UPPER=1.0 NBINS=20 SMEAR=0.1}
      95             : PRINT ARG=lq1.* FILE=colvar
      96             : ```
      97             : 
      98             : The following calculates the LOCAL_Q1 parameters for atoms 1-5 only. For each of these atoms comparisons of the geometry of the coordination sphere
      99             : are done with those of all the other atoms in the system.  The final quantity is the average and is outputted to a file
     100             : 
     101             : ```plumed
     102             : q1a: Q1 SPECIESA=1-5 SPECIESB=1-64 D_0=1.3 R_0=0.2
     103             : q1b: Q1 SPECIESA=6-64 SPECIESB=1-64 D_0=1.3 R_0=0.2
     104             : w1: LOCAL_Q1 SPECIESA=q1a SPECIESB=q1b SWITCH={RATIONAL D_0=1.3 R_0=0.2} MEAN
     105             : PRINT ARG=w1.* FILE=colvar
     106             : ```
     107             : 
     108             : ## The MASK keyword
     109             : 
     110             : You can use the MASK keyword with this action in the same way that it is used with [COORDINATIONNUMBER](COORDINATIONNUMBER.md).  This keyword thus expects a vector in
     111             : input, which tells PLUMED the atoms for which you do not need to calculate the function.  As illustrated below, this is useful if you are using functionality
     112             : from the [volumes module](module_volumes.md) to calculate the average value of the $s_i$ parameter that is defined by the equation above for only those atoms that
     113             : lie in a certain part of the simulation box.
     114             : 
     115             : ```plumed
     116             : # Calculate the Q1 parameters for all the atoms
     117             : q1: Q1 SPECIES=1-400 SWITCH={RATIONAL D_0=1.3 R_0=0.2 D_MAX=3.0}
     118             : # Fixed virtual atom which serves as the probe volume's center (pos. in nm)
     119             : center: FIXEDATOM AT=2.5,2.5,2.5
     120             : # Vector in which element i is one if atom i is in sphere of interest and zero otherwise
     121             : sphere: INSPHERE ATOMS=1-400 CENTER=center RADIUS={GAUSSIAN D_0=0.5 R_0=0.01 D_MAX=0.52}
     122             : # Calculate the local_q1 parameters
     123             : lq1: LOCAL_Q1 SPECIES=q1 SWITCH={RATIONAL D_0=1.3 R_0=0.2 D_MAX=3.0} MASK=sphere
     124             : # Multiply fccubic parameters numbers by sphere vector
     125             : prod: CUSTOM ARG=lq1,sphere FUNC=x*y PERIODIC=NO
     126             : # Sum of coordination numbers for atoms that are in the sphere of interest
     127             : numer: SUM ARG=prod PERIODIC=NO
     128             : # Number of atoms that are in sphere of interest
     129             : denom: SUM ARG=sphere PERIODIC=NO
     130             : # Average coordination number for atoms in sphere of interest
     131             : av: CUSTOM ARG=numer,denom FUNC=x/y PERIODIC=NO
     132             : # And print out final CV to a file
     133             : PRINT ARG=av FILE=colvar STRIDE=1
     134             : ```
     135             : 
     136             : This input calculates the average $s_i$ parameter for those atoms that are within a spherical region that is centered on the point $(2.5,2.5,2.5)$. By including the MASK
     137             : keyword in the LOCAL_Q1 line we reduce the number of $s_i$ values we have to compute using the expression above. However, we are still asking PLUMED to calculate the $q_{lm}$ vectors for many atoms that
     138             : will not contribute to the final averaged quantity. The documentation for [LOCAL_AVERAGE](LOCAL_AVERAGE.md) discusses how you can create a mask vector that can act upon
     139             : the [Q1](Q1.md) action here that will ensure that you are not calculating $q_{lm}$  parameters that are not required.
     140             : 
     141             : */
     142             : //+ENDPLUMEDOC
     143             : 
     144             : //+PLUMEDOC MCOLVARF LOCAL_Q3
     145             : /*
     146             : Calculate the local degree of order around an atoms by taking the average dot product between the q_3 vector on the central atom and the q_3 vector on the atoms in the first coordination sphere.
     147             : 
     148             : The [Q3](Q3.md) command allows one to calculate one complex vectors for each of the atoms in your system that describe the degree of order in the coordination sphere
     149             : around a particular atom. The difficulty with these vectors comes when combining the order parameters from all of the individual atoms/molecules so as to get a
     150             : measure of the global degree of order for the system. The simplest way of doing this - calculating the average Steinhardt parameter - can be problematic. If one is
     151             : examining nucleation say only the order parameters for those atoms in the nucleus will change significantly when the nucleus forms. The order parameters for the
     152             : atoms in the surrounding liquid will remain pretty much the same. As such if one models a small nucleus embedded in a very large amount of solution/melt any
     153             : change in the average order parameter will be negligible. Substantial changes in the value of this average can be observed in simulations of nucleation but only
     154             : because the number of atoms is relatively small.
     155             : 
     156             : When the average [Q3](Q3.md) parameter is used to bias the dynamics a problems
     157             : can occur. These averaged coordinates cannot distinguish between the correct,
     158             : single-nucleus pathway and a concerted pathway in which all the atoms rearrange
     159             : themselves into their solid-like configuration simultaneously. This second type
     160             : of pathway would be impossible in reality because there is a large entropic
     161             : barrier that prevents concerted processes like this from happening.  However,
     162             : in the finite sized systems that are commonly simulated this barrier is reduced
     163             : substantially. As a result in simulations where average Steinhardt parameters
     164             : are biased there are often quite dramatic system size effects
     165             : 
     166             : If one wants to simulate nucleation using some form on
     167             : biased dynamics what is really required is an order parameter that measures:
     168             : 
     169             : - Whether or not the coordination spheres around atoms are ordered
     170             : - Whether or not the atoms that are ordered are clustered together in a crystalline nucleus
     171             : 
     172             : As discussed on [this page](https://www.plumed-tutorials.org/lessons/23/001/data/Steinhardt.html) a variety of variations on the Steinhardt parameters have been
     173             : introduced to better describe nucleation. That page also shows how PLUMED provides you with flexibility that you can use to implement new combinations of the
     174             : Steinhardt parameters. However, the inputs that you would need to write to implement common symmetry functions are rather complex so we also provide shortcuts
     175             : like this one to help you compute CVs that have been widely used in the literature easily.
     176             : 
     177             : This particular shortcut allows you to compute the LOCAL_Q3 parameter for a particular atom, which is a number that measures the extent to
     178             : which the orientation of the atoms in the first coordination sphere of an atom match the orientation of the central atom.  It does this by calculating the following
     179             : quantity for each of the atoms in the system:
     180             : 
     181             : $$
     182             :  s_i = \frac{ \sum_j \sigma( r_{ij} ) \sum_{m=-3}^3 q_{3m}^{*}(i)q_{3m}(j) }{ \sum_j \sigma( r_{ij} ) }
     183             : $$
     184             : 
     185             : where $q_{3m}(i)$ and $q_{3m}(j)$ are the 3rd order Steinhardt vectors calculated for atom $i$ and atom $j$ respectively and the asterisk denotes complex
     186             : conjugation.  The function
     187             : $\sigma( r_{ij} )$ is a switching function that acts on the distance between atoms $i$ and $j$.  The parameters of this function should be set
     188             : so that it the function is equal to one when atom $j$ is in the first coordination sphere of atom $i$ and is zero otherwise.  The sum in the numerator
     189             : of this expression is the dot product of the Steinhardt parameters for atoms $i$ and $j$ and thus measures the degree to which the orientations of these
     190             : adjacent atoms are correlated.
     191             : 
     192             : The following input shows how this works in practice.  This input calculates the average value of the LOCAL_Q3 parameter for the 64 Lennard Jones atoms in the system under study and prints this
     193             : quantity to a file called colvar.
     194             : 
     195             : ```plumed
     196             : q3: Q3 SPECIES=1-64 D_0=1.3 R_0=0.2
     197             : lq3: LOCAL_Q3 SPECIES=q3 SWITCH={RATIONAL D_0=1.3 R_0=0.2}
     198             : lq3_mean: MEAN ARG=lq3 PERIODIC=NO
     199             : PRINT ARG=lq3.mean FILE=colvar
     200             : ```
     201             : 
     202             : The following input calculates the distribution of LOCAL_Q3 parameters at any given time and outputs this information to a file.
     203             : 
     204             : ```plumed
     205             : q3: Q3 SPECIES=1-64 D_0=1.3 R_0=0.2
     206             : lq3: LOCAL_Q3 SPECIES=q3 SWITCH={RATIONAL D_0=1.3 R_0=0.2} HISTOGRAM={GAUSSIAN LOWER=0.0 UPPER=1.0 NBINS=20 SMEAR=0.1}
     207             : PRINT ARG=lq3.* FILE=colvar
     208             : ```
     209             : 
     210             : The following calculates the LOCAL_Q3 parameters for atoms 1-5 only. For each of these atoms comparisons of the geometry of the coordination sphere
     211             : are done with those of all the other atoms in the system.  The final quantity is the average and is outputted to a file
     212             : 
     213             : ```plumed
     214             : q3a: Q3 SPECIESA=1-5 SPECIESB=1-64 D_0=1.3 R_0=0.2
     215             : q3b: Q3 SPECIESA=6-64 SPECIESB=1-64 D_0=1.3 R_0=0.2
     216             : w3: LOCAL_Q3 SPECIESA=q3a SPECIESB=q3b SWITCH={RATIONAL D_0=1.3 R_0=0.2} MEAN
     217             : PRINT ARG=w3.* FILE=colvar
     218             : ```
     219             : 
     220             : ## The MASK keyword
     221             : 
     222             : You can use the MASK keyword with this action in the same way that it is used with [COORDINATIONNUMBER](COORDINATIONNUMBER.md).  This keyword thus expects a vector in
     223             : input, which tells PLUMED the atoms for which you do not need to calculate the function.  As illustrated below, this is useful if you are using functionality
     224             : from the [volumes module](module_volumes.md) to calculate the average value of the $s_i$ parameter that is defined by the equation above for only those atoms that
     225             : lie in a certain part of the simulation box.
     226             : 
     227             : ```plumed
     228             : # Calculate the Q3 parameters for all the atoms
     229             : q3: Q3 SPECIES=1-400 SWITCH={RATIONAL D_0=1.3 R_0=0.2 D_MAX=3.0}
     230             : # Fixed virtual atom which serves as the probe volume's center (pos. in nm)
     231             : center: FIXEDATOM AT=2.5,2.5,2.5
     232             : # Vector in which element i is one if atom i is in sphere of interest and zero otherwise
     233             : sphere: INSPHERE ATOMS=1-400 CENTER=center RADIUS={GAUSSIAN D_0=0.5 R_0=0.01 D_MAX=0.52}
     234             : # Calculate the local_q3 parameters
     235             : lq3: LOCAL_Q3 SPECIES=q3 SWITCH={RATIONAL D_0=1.3 R_0=0.2 D_MAX=3.0} MASK=sphere
     236             : # Multiply fccubic parameters numbers by sphere vector
     237             : prod: CUSTOM ARG=lq3,sphere FUNC=x*y PERIODIC=NO
     238             : # Sum of coordination numbers for atoms that are in the sphere of interest
     239             : numer: SUM ARG=prod PERIODIC=NO
     240             : # Number of atoms that are in sphere of interest
     241             : denom: SUM ARG=sphere PERIODIC=NO
     242             : # Average coordination number for atoms in sphere of interest
     243             : av: CUSTOM ARG=numer,denom FUNC=x/y PERIODIC=NO
     244             : # And print out final CV to a file
     245             : PRINT ARG=av FILE=colvar STRIDE=1
     246             : ```
     247             : 
     248             : This input calculates the average $s_i$ parameter for those atoms that are within a spherical region that is centered on the point $(2.5,2.5,2.5)$. By including the MASK
     249             : keyword in the LOCAL_Q3 line we reduce the number of $s_i$ values we have to compute using the expression above. However, we are still asking PLUMED to calculate the $q_{lm}$ vectors for many atoms that
     250             : will not contribute to the final averaged quantity. The documentation for [LOCAL_AVERAGE](LOCAL_AVERAGE.md) discusses how you can create a mask vector that can act upon
     251             : the [Q3](Q3.md) action here that will ensure that you are not calculating $q_{lm}$ vectors that are not required.
     252             : 
     253             : */
     254             : //+ENDPLUMEDOC
     255             : 
     256             : //+PLUMEDOC MCOLVARF LOCAL_Q4
     257             : /*
     258             : Calculate the local degree of order around an atoms by taking the average dot product between the q_4 vector on the central atom and the q_4 vector on the atoms in the first coordination sphere.
     259             : 
     260             : The [Q4](Q4.md) command allows one to calculate one complex vectors for each of the atoms in your system that describe the degree of order in the coordination sphere
     261             : around a particular atom. The difficulty with these vectors comes when combining the order parameters from all of the individual atoms/molecules so as to get a
     262             : measure of the global degree of order for the system. The simplest way of doing this - calculating the average Steinhardt parameter - can be problematic. If one is
     263             : examining nucleation say only the order parameters for those atoms in the nucleus will change significantly when the nucleus forms. The order parameters for the
     264             : atoms in the surrounding liquid will remain pretty much the same. As such if one models a small nucleus embedded in a very large amount of solution/melt any
     265             : change in the average order parameter will be negligible. Substantial changes in the value of this average can be observed in simulations of nucleation but only
     266             : because the number of atoms is relatively small.
     267             : 
     268             : When the average [Q4](Q4.md) parameter is used to bias the dynamics a problems
     269             : can occur. These averaged coordinates cannot distinguish between the correct,
     270             : single-nucleus pathway and a concerted pathway in which all the atoms rearrange
     271             : themselves into their solid-like configuration simultaneously. This second type
     272             : of pathway would be impossible in reality because there is a large entropic
     273             : barrier that prevents concerted processes like this from happening.  However,
     274             : in the finite sized systems that are commonly simulated this barrier is reduced
     275             : substantially. As a result in simulations where average Steinhardt parameters
     276             : are biased there are often quite dramatic system size effects
     277             : 
     278             : If one wants to simulate nucleation using some form on
     279             : biased dynamics what is really required is an order parameter that measures:
     280             : 
     281             : - Whether or not the coordination spheres around atoms are ordered
     282             : - Whether or not the atoms that are ordered are clustered together in a crystalline nucleus
     283             : 
     284             : As discussed on [this page](https://www.plumed-tutorials.org/lessons/23/001/data/Steinhardt.html) a variety of variations on the Steinhardt parameters have been
     285             : introduced to better describe nucleation. That page also shows how PLUMED provides you with flexibility that you can use to implement new combinations of the
     286             : Steinhardt parameters. However, the inputs that you would need to write to implement common symmetry functions are rather complex so we also provide shortcuts
     287             : like this one to help you compute CVs that have been widely used in the literature easily.
     288             : 
     289             : This particular shortcut allows you to compute the LOCAL_Q4 parameter for a particular atom, which is a number that measures the extent to
     290             : which the orientation of the atoms in the first coordination sphere of an atom match the orientation of the central atom.  It does this by calculating the following
     291             : quantity for each of the atoms in the system:
     292             : 
     293             : $$
     294             :  s_i = \frac{ \sum_j \sigma( r_{ij} ) \sum_{m=-4}^4 q_{4m}^{*}(i)q_{4m}(j) }{ \sum_j \sigma( r_{ij} ) }
     295             : $$
     296             : 
     297             : where $q_{4m}(i)$ and $q_{4m}(j)$ are the 4th order Steinhardt vectors calculated for atom $i$ and atom $j$ respectively and the asterisk denotes complex
     298             : conjugation.  The function
     299             : $\sigma( r_{ij} )$ is a switching function that acts on the distance between atoms $i$ and $j$.  The parameters of this function should be set
     300             : so that it the function is equal to one when atom $j$ is in the first coordination sphere of atom $i$ and is zero otherwise.  The sum in the numerator
     301             : of this expression is the dot product of the Steinhardt parameters for atoms $i$ and $j$ and thus measures the degree to which the orientations of these
     302             : adjacent atoms are correlated.
     303             : 
     304             : The following input shows how this works in practice.  This input calculates the average value of the LOCAL_Q4 parameter for the 64 Lennard Jones atoms in the system under study and prints this
     305             : quantity to a file called colvar.
     306             : 
     307             : ```plumed
     308             : q4: Q4 SPECIES=1-64 D_0=1.3 R_0=0.2
     309             : lq4: LOCAL_Q4 SPECIES=q4 SWITCH={RATIONAL D_0=1.3 R_0=0.2}
     310             : lq4_mean: MEAN ARG=lq4 PERIODIC=NO
     311             : PRINT ARG=lq4_mean FILE=colvar
     312             : ```
     313             : 
     314             : The following input calculates the distribution of LOCAL_Q4 parameters at any given time and outputs this information to a file.
     315             : 
     316             : ```plumed
     317             : q4: Q4 SPECIES=1-64 D_0=1.3 R_0=0.2
     318             : lq4: LOCAL_Q4 SPECIES=q4 SWITCH={RATIONAL D_0=1.3 R_0=0.2} HISTOGRAM={GAUSSIAN LOWER=0.0 UPPER=1.0 NBINS=20 SMEAR=0.1}
     319             : PRINT ARG=lq4.* FILE=colvar
     320             : ```
     321             : 
     322             : The following calculates the LOCAL_Q4 parameters for atoms 1-5 only. For each of these atoms comparisons of the geometry of the coordination sphere
     323             : are done with those of all the other atoms in the system.  The final quantity is the average and is outputted to a file
     324             : 
     325             : ```plumed
     326             : q4a: Q4 SPECIESA=1-5 SPECIESB=1-64 D_0=1.3 R_0=0.2
     327             : q4b: Q4 SPECIESA=6-64 SPECIESB=1-64 D_0=1.3 R_0=0.2
     328             : w4: LOCAL_Q4 SPECIESA=q4a SPECIESB=q4b SWITCH={RATIONAL D_0=1.3 R_0=0.2} MEAN
     329             : PRINT ARG=w4.* FILE=colvar
     330             : ```
     331             : 
     332             : ## The MASK keyword
     333             : 
     334             : You can use the MASK keyword with this action in the same way that it is used with [COORDINATIONNUMBER](COORDINATIONNUMBER.md).  This keyword thus expects a vector in
     335             : input, which tells PLUMED the atoms for which you do not need to calculate the function.  As illustrated below, this is useful if you are using functionality
     336             : from the [volumes module](module_volumes.md) to calculate the average value of the $s_i$ parameter that is defined by the equation above for only those atoms that
     337             : lie in a certain part of the simulation box.
     338             : 
     339             : ```plumed
     340             : # Calculate the Q4 parameters for all the atoms
     341             : q4: Q4 SPECIES=1-400 SWITCH={RATIONAL D_0=1.3 R_0=0.2 D_MAX=3.0}
     342             : # Fixed virtual atom which serves as the probe volume's center (pos. in nm)
     343             : center: FIXEDATOM AT=2.5,2.5,2.5
     344             : # Vector in which element i is one if atom i is in sphere of interest and zero otherwise
     345             : sphere: INSPHERE ATOMS=1-400 CENTER=center RADIUS={GAUSSIAN D_0=0.5 R_0=0.01 D_MAX=0.52}
     346             : # Calculate the local_q4 parameters
     347             : lq4: LOCAL_Q4 SPECIES=q4 SWITCH={RATIONAL D_0=1.3 R_0=0.2 D_MAX=3.0} MASK=sphere
     348             : # Multiply fccubic parameters numbers by sphere vector
     349             : prod: CUSTOM ARG=lq4,sphere FUNC=x*y PERIODIC=NO
     350             : # Sum of coordination numbers for atoms that are in the sphere of interest
     351             : numer: SUM ARG=prod PERIODIC=NO
     352             : # Number of atoms that are in sphere of interest
     353             : denom: SUM ARG=sphere PERIODIC=NO
     354             : # Average coordination number for atoms in sphere of interest
     355             : av: CUSTOM ARG=numer,denom FUNC=x/y PERIODIC=NO
     356             : # And print out final CV to a file
     357             : PRINT ARG=av FILE=colvar STRIDE=1
     358             : ```
     359             : 
     360             : This input calculates the average $s_i$ parameter for those atoms that are within a spherical region that is centered on the point $(2.5,2.5,2.5)$. By including the MASK
     361             : keyword in the LOCAL_Q4 line we reduce the number of $s_i$ values we have to compute using the expression above. However, we are still asking PLUMED to calculate the $q_{lm}$ vectors for many atoms that
     362             : will not contribute to the final averaged quantity. The documentation for [LOCAL_AVERAGE](LOCAL_AVERAGE.md) discusses how you can create a mask vector that can act upon
     363             : the [Q4](Q4.md) action here that will ensure that you are not calculating $q_{lm}$ vectors that are not required.
     364             : 
     365             : */
     366             : //+ENDPLUMEDOC
     367             : 
     368             : //+PLUMEDOC MCOLVARF LOCAL_Q6
     369             : /*
     370             : Calculate the local degree of order around an atoms by taking the average dot product between the q_6 vector on the central atom and the q_6 vector on the atoms in the first coordination sphere.
     371             : 
     372             : The [Q6](Q6.md) command allows one to calculate one complex vectors for each of the atoms in your system that describe the degree of order in the coordination sphere
     373             : around a particular atom. The difficulty with these vectors comes when combining the order parameters from all of the individual atoms/molecules so as to get a
     374             : measure of the global degree of order for the system. The simplest way of doing this - calculating the average Steinhardt parameter - can be problematic. If one is
     375             : examining nucleation say only the order parameters for those atoms in the nucleus will change significantly when the nucleus forms. The order parameters for the
     376             : atoms in the surrounding liquid will remain pretty much the same. As such if one models a small nucleus embedded in a very large amount of solution/melt any
     377             : change in the average order parameter will be negligible. Substantial changes in the value of this average can be observed in simulations of nucleation but only
     378             : because the number of atoms is relatively small.
     379             : 
     380             : When the average [Q6](Q6.md) parameter is used to bias the dynamics a problems
     381             : can occur. These averaged coordinates cannot distinguish between the correct,
     382             : single-nucleus pathway and a concerted pathway in which all the atoms rearrange
     383             : themselves into their solid-like configuration simultaneously. This second type
     384             : of pathway would be impossible in reality because there is a large entropic
     385             : barrier that prevents concerted processes like this from happening.  However,
     386             : in the finite sized systems that are commonly simulated this barrier is reduced
     387             : substantially. As a result in simulations where average Steinhardt parameters
     388             : are biased there are often quite dramatic system size effects
     389             : 
     390             : If one wants to simulate nucleation using some form on
     391             : biased dynamics what is really required is an order parameter that measures:
     392             : 
     393             : - Whether or not the coordination spheres around atoms are ordered
     394             : - Whether or not the atoms that are ordered are clustered together in a crystalline nucleus
     395             : 
     396             : As discussed on [this page](https://www.plumed-tutorials.org/lessons/23/001/data/Steinhardt.html) a variety of variations on the Steinhardt parameters have been
     397             : introduced to better describe nucleation. That page also shows how PLUMED provides you with flexibility that you can use to implement new combinations of the
     398             : Steinhardt parameters. However, the inputs that you would need to write to implement common symmetry functions are rather complex so we also provide shortcuts
     399             : like this one to help you compute CVs that have been widely used in the literature easily.
     400             : 
     401             : This particular shortcut allows you to compute the LOCAL_Q6 parameter for a particular atom, which is a number that measures the extent to
     402             : which the orientation of the atoms in the first coordination sphere of an atom match the orientation of the central atom.  It does this by calculating the following
     403             : quantity for each of the atoms in the system:
     404             : 
     405             : $$
     406             :  s_i = \frac{ \sum_j \sigma( r_{ij} ) \sum_{m=-6}^6 q_{6m}^{*}(i)q_{6m}(j) }{ \sum_j \sigma( r_{ij} ) }
     407             : $$
     408             : 
     409             : where $q_{6m}(i)$ and $q_{6m}(j)$ are the 6th order Steinhardt vectors calculated for atom $i$ and atom $j$ respectively and the asterisk denotes complex
     410             : conjugation.  The function
     411             : $\sigma( r_{ij} )$ is a switching function that acts on the distance between atoms $i$ and $j$.  The parameters of this function should be set
     412             : so that it the function is equal to one when atom $j$ is in the first coordination sphere of atom $i$ and is zero otherwise.  The sum in the numerator
     413             : of this expression is the dot product of the Steinhardt parameters for atoms $i$ and $j$ and thus measures the degree to which the orientations of these
     414             : adjacent atoms are correlated.
     415             : 
     416             : The following input shows how this works in practice.  This input calculates the average value of the LOCAL_Q6 parameter for the 64 Lennard Jones atoms in the system under study and prints this
     417             : quantity to a file called colvar.
     418             : 
     419             : ```plumed
     420             : q6: Q6 SPECIES=1-64 D_0=1.3 R_0=0.2
     421             : lq6: LOCAL_Q6 SPECIES=q6 SWITCH={RATIONAL D_0=1.3 R_0=0.2}
     422             : lq6_mean: MEAN ARG=lq6 PERIODIC=NO
     423             : PRINT ARG=lq6_mean FILE=colvar
     424             : ```
     425             : 
     426             : The following input calculates the distribution of LOCAL_Q6 parameters at any given time and outputs this information to a file.
     427             : 
     428             : ```plumed
     429             : q6: Q6 SPECIES=1-64 D_0=1.3 R_0=0.2
     430             : lq6: LOCAL_Q6 SPECIES=q6 SWITCH={RATIONAL D_0=1.3 R_0=0.2} HISTOGRAM={GAUSSIAN LOWER=0.0 UPPER=1.0 NBINS=20 SMEAR=0.1}
     431             : PRINT ARG=lq6.* FILE=colvar
     432             : ```
     433             : 
     434             : The following calculates the LOCAL_Q6 parameters for atoms 1-5 only. For each of these atoms comparisons of the geometry of the coordination sphere
     435             : are done with those of all the other atoms in the system.  The final quantity is the average and is outputted to a file
     436             : 
     437             : ```plumed
     438             : q6a: Q6 SPECIESA=1-5 SPECIESB=1-64 D_0=1.3 R_0=0.2
     439             : q6b: Q6 SPECIESA=6-64 SPECIESB=1-64 D_0=1.3 R_0=0.2
     440             : w6: LOCAL_Q6 SPECIESA=q6a SPECIESB=q6b SWITCH={RATIONAL D_0=1.3 R_0=0.2} MEAN
     441             : PRINT ARG=w6.* FILE=colvar
     442             : ```
     443             : 
     444             : ## The MASK keyword
     445             : 
     446             : You can use the MASK keyword with this action in the same way that it is used with [COORDINATIONNUMBER](COORDINATIONNUMBER.md).  This keyword thus expects a vector in
     447             : input, which tells PLUMED the atoms for which you do not need to calculate the function.  As illustrated below, this is useful if you are using functionality
     448             : from the [volumes module](module_volumes.md) to calculate the average value of the $s_i$ parameter that is defined by the equation above for only those atoms that
     449             : lie in a certain part of the simulation box.
     450             : 
     451             : ```plumed
     452             : # Calculate the Q6 parameters for all the atoms
     453             : q6: Q6 SPECIES=1-400 SWITCH={RATIONAL D_0=1.3 R_0=0.2 D_MAX=3.0}
     454             : # Fixed virtual atom which serves as the probe volume's center (pos. in nm)
     455             : center: FIXEDATOM AT=2.5,2.5,2.5
     456             : # Vector in which element i is one if atom i is in sphere of interest and zero otherwise
     457             : sphere: INSPHERE ATOMS=1-400 CENTER=center RADIUS={GAUSSIAN D_0=0.5 R_0=0.01 D_MAX=0.52}
     458             : # Calculate the local_q6 parameters
     459             : lq6: LOCAL_Q6 SPECIES=q6 SWITCH={RATIONAL D_0=1.3 R_0=0.2 D_MAX=3.0} MASK=sphere
     460             : # Multiply fccubic parameters numbers by sphere vector
     461             : prod: CUSTOM ARG=lq6,sphere FUNC=x*y PERIODIC=NO
     462             : # Sum of coordination numbers for atoms that are in the sphere of interest
     463             : numer: SUM ARG=prod PERIODIC=NO
     464             : # Number of atoms that are in sphere of interest
     465             : denom: SUM ARG=sphere PERIODIC=NO
     466             : # Average coordination number for atoms in sphere of interest
     467             : av: CUSTOM ARG=numer,denom FUNC=x/y PERIODIC=NO
     468             : # And print out final CV to a file
     469             : PRINT ARG=av FILE=colvar STRIDE=1
     470             : ```
     471             : 
     472             : This input calculates the average $s_i$ parameter for those atoms that are within a spherical region that is centered on the point $(2.5,2.5,2.5)$. By including the MASK
     473             : keyword in the LOCAL_Q6 line we reduce the number of $s_i$ values we have to compute using the expression above. However, we are still asking PLUMED to calculate the $q_{lm}$ vectors for many atoms that
     474             : will not contribute to the final averaged quantity. The documentation for [LOCAL_AVERAGE](LOCAL_AVERAGE.md) discusses how you can create a mask vector that can act upon
     475             : the [Q6](Q6.md) action here that will ensure that you are not calculating $q_{lm}$ vectors that are not required.
     476             : 
     477             : */
     478             : //+ENDPLUMEDOC
     479             : 
     480             : class LocalSteinhardt : public ActionShortcut {
     481             : private:
     482             :   std::string getSymbol( const int& m ) const ;
     483             :   std::string getArgsForStack( const int& l, const std::string& lab ) const;
     484             : public:
     485             :   static void registerKeywords( Keywords& keys );
     486             :   explicit LocalSteinhardt(const ActionOptions&);
     487             : };
     488             : 
     489             : PLUMED_REGISTER_ACTION(LocalSteinhardt,"LOCAL_Q1")
     490             : PLUMED_REGISTER_ACTION(LocalSteinhardt,"LOCAL_Q3")
     491             : PLUMED_REGISTER_ACTION(LocalSteinhardt,"LOCAL_Q4")
     492             : PLUMED_REGISTER_ACTION(LocalSteinhardt,"LOCAL_Q6")
     493             : 
     494          20 : void LocalSteinhardt::registerKeywords( Keywords& keys ) {
     495          20 :   ActionShortcut::registerKeywords( keys );
     496          20 :   keys.add("optional","SPECIES","the label of the action that computes the Steinhardt parameters for which you would like to calculate local steinhardt parameters");
     497          20 :   keys.add("optional","SPECIESA","the label of the action that computes the Steinhardt parameters for which you would like to calculate local steinhardt parameters");
     498          20 :   keys.add("optional","SPECIESB","the label of the action that computes the Steinhardt parameters that you would like to use when calculating the loal steinhardt parameters");
     499          20 :   keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. "
     500             :            "The following provides information on the \\ref switchingfunction that are available. "
     501             :            "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords.");
     502          20 :   keys.add("optional","MASK","the label/s for vectors that are used to determine which local steinhardt parameters to compute");
     503          40 :   keys.addDeprecatedFlag("LOWMEM","");
     504          40 :   keys.setValueDescription("vector","the values of the local steinhardt parameters for the input atoms");
     505          20 :   multicolvar::MultiColvarShortcuts::shortcutKeywords( keys );
     506          20 :   keys.needsAction("CONTACT_MATRIX");
     507          20 :   keys.needsAction("MATRIX_PRODUCT");
     508          20 :   keys.needsAction("GROUP");
     509          20 :   keys.needsAction("ONES");
     510          20 :   keys.needsAction("OUTER_PRODUCT");
     511          20 :   keys.needsAction("VSTACK");
     512          20 :   keys.needsAction("CONCATENATE");
     513          20 :   keys.needsAction("CUSTOM");
     514          20 :   keys.needsAction("TRANSPOSE");
     515          40 :   keys.needsAction("MATRIX_VECTOR_PRODUCT");
     516          20 :   keys.addFlag("USEGPU",false,"run part of this calculation on the GPU");
     517          20 : }
     518             : 
     519          98 : std::string LocalSteinhardt::getSymbol( const int& m ) const {
     520          98 :   if( m<0 ) {
     521             :     std::string num;
     522          40 :     Tools::convert( -1*m, num );
     523          40 :     return "n" + num;
     524          58 :   } else if( m>0 ) {
     525             :     std::string num;
     526          49 :     Tools::convert( m, num );
     527          49 :     return "p" + num;
     528             :   }
     529           9 :   return "0";
     530             : }
     531             : 
     532           9 : std::string LocalSteinhardt::getArgsForStack( const int& l, const std::string& sp_lab ) const {
     533             :   std::string numstr;
     534           9 :   Tools::convert( l, numstr );
     535          18 :   std::string data_mat = " ARG=" + sp_lab + "_sp.rm-n" + numstr + ","
     536          18 :                          + sp_lab + "_sp.im-n" + numstr;
     537         107 :   for(int i=-l+1; i<=l; ++i) {
     538          98 :     numstr = getSymbol( i );
     539         196 :     data_mat += "," + sp_lab + "_sp.rm-" + numstr + ","
     540         196 :                 + sp_lab + "_sp.im-" + numstr;
     541             :   }
     542           9 :   return data_mat;
     543             : }
     544             : 
     545           7 : LocalSteinhardt::LocalSteinhardt(const ActionOptions& ao):
     546             :   Action(ao),
     547           7 :   ActionShortcut(ao) {
     548             : 
     549             :   bool usegpu;
     550           7 :   parseFlag("USEGPU",usegpu);
     551          14 :   const std::string doUSEGPU = usegpu?" USEGPU":"";
     552             : 
     553             : #define createLabel(name) const std::string name##Lab = getShortcutLabel()+"_"#name;
     554             :   bool lowmem;
     555           7 :   parseFlag("LOWMEM",lowmem);
     556           7 :   if( lowmem ) {
     557           0 :     warning("LOWMEM flag is deprecated and is no longer required for this action");
     558             :   }
     559             :   // Get the Q value
     560             :   int l;
     561          14 :   Tools::convert( getName().substr(7), l);
     562             :   // Create a vector filled with ones
     563             :   std::string twolplusone;
     564           7 :   Tools::convert( 2*(2*l+1), twolplusone );
     565           7 :   createLabel( uvec );
     566          14 :   readInputLine( uvecLab + ": ONES SIZE=" + twolplusone );
     567             :   // Read in species keyword
     568             :   std::string sp_str;
     569          14 :   parse("SPECIES",sp_str);
     570             :   std::string spa_str;
     571           7 :   parse("SPECIESA",spa_str);
     572           7 :   createLabel( dpmat );
     573           7 :   createLabel( cmap );
     574           7 :   createLabel( grp );
     575           7 :   if( sp_str.length()>0 ) {
     576             :     // Create a group with these atoms
     577          12 :     readInputLine( grpLab + ": GROUP ATOMS=" + sp_str );
     578           6 :     std::vector<std::string> sp_lab = Tools::getWords(sp_str, "\t\n ,");
     579             :     // This creates the stash to hold all the vectors
     580           6 :     createLabel( uvecs );
     581           6 :     createLabel( nmat );
     582           6 :     if( sp_lab.size()==1 ) {
     583             :       // The lengths of all the vectors in a vector
     584          18 :       readInputLine( nmatLab + ": OUTER_PRODUCT "
     585          12 :                      "ARG=" + sp_lab[0] + "_norm," + uvecLab);
     586             :       // The unormalised vectors
     587          12 :       readInputLine( uvecsLab + ": VSTACK" + getArgsForStack( l, sp_lab[0] ) );
     588             :     } else {
     589           0 :       createLabel( mags );
     590           0 :       std::string len_vec = magsLab + ": CONCATENATE ARG=" + sp_lab[0] + "_norm";
     591           0 :       for(unsigned i=1; i<sp_lab.size(); ++i) {
     592           0 :         len_vec += "," + sp_lab[i] + "_norm";
     593             :       }
     594             :       // This is the vector that contains all the magnitudes
     595           0 :       readInputLine( len_vec );
     596           0 :       std::string concat_str = uvecsLab + ": CONCATENATE";
     597           0 :       for(unsigned i=0; i<sp_lab.size(); ++i) {
     598             :         std::string snum;
     599           0 :         Tools::convert( i+1, snum );
     600           0 :         concat_str += " MATRIX" + snum + "1=" + uvecsLab + snum;
     601           0 :         readInputLine( uvecsLab + snum + ": VSTACK" + getArgsForStack( l, sp_lab[i] ) );
     602             :       }
     603             :       // And the normalising matrix by taking the column vector of magnitudes and multiplying by the row vector of ones
     604           0 :       readInputLine( nmatLab + ": OUTER_PRODUCT ARG=" + magsLab + "," + uvecLab);
     605             :       // The unormalised vectors
     606           0 :       readInputLine( concat_str );
     607             :     }
     608             :     // Now normalise all the vectors by doing Hadammard "product" with normalising matrix
     609           6 :     createLabel( vecs );
     610          18 :     readInputLine( vecsLab + ": CUSTOM ARG=" + uvecsLab + ","
     611          12 :                    + nmatLab + " FUNC=x/y PERIODIC=NO");
     612             :     // And transpose the matrix
     613           6 :     createLabel( vecsT );
     614          12 :     readInputLine( vecsTLab + ": TRANSPOSE ARG=" + vecsLab );
     615             :     std::string sw_str;
     616          12 :     parse("SWITCH",sw_str);
     617             :     std::string maskstr;
     618          12 :     parse("MASK",maskstr);
     619           6 :     if( maskstr.length()>0 ) {
     620           4 :       maskstr=" MASK=" + maskstr;
     621             :     }
     622          18 :     readInputLine( cmapLab + ": CONTACT_MATRIX GROUP=" + sp_str + " "
     623          12 :                    "SWITCH={" + sw_str + "}" + maskstr + doUSEGPU);
     624             :     // And the matrix of dot products
     625          18 :     readInputLine( dpmatLab + ": MATRIX_PRODUCT ARG=" + vecsLab + ","
     626          12 :                    + vecsTLab + " MASK=" + cmapLab + doUSEGPU);
     627           7 :   } else if( spa_str.length()>0 ) {
     628             :     // Create a group with these atoms
     629           2 :     readInputLine( grpLab + ": GROUP ATOMS=" + spa_str );
     630             :     std::string spb_str;
     631           2 :     parse("SPECIESB",spb_str);
     632           1 :     if( spb_str.length()==0 ) {
     633           0 :       plumed_merror("need both SPECIESA and SPECIESB in input");
     634             :     }
     635           1 :     const std::vector<std::string> sp_laba = Tools::getWords(spa_str, "\t\n ,");
     636           1 :     const std::vector<std::string> sp_labb = Tools::getWords(spb_str, "\t\n ,");
     637           1 :     createLabel(nmatA);
     638           1 :     createLabel(uvecsA);
     639           1 :     if( sp_laba.size()==1 ) {
     640             :       // The matrix that is used for normalising
     641           3 :       readInputLine( nmatALab + ": OUTER_PRODUCT "
     642           2 :                      "ARG=" +  sp_laba[0] + "_norm," + uvecLab);
     643             :       // The unormalised vectors
     644           2 :       readInputLine( uvecsALab + ": VSTACK" + getArgsForStack( l, sp_laba[0] ) );
     645             :     } else {
     646           0 :       createLabel(magsA);
     647           0 :       std::string len_vec = magsALab + ": CONCATENATE "
     648           0 :                             "ARG=" + sp_laba[0] + "_norm";
     649           0 :       for(unsigned i=1; i<sp_laba.size(); ++i) {
     650           0 :         len_vec += "," + sp_laba[i] + "_norm";
     651             :       }
     652             :       //  This is the vector that contains all the magnitudes
     653           0 :       readInputLine( len_vec );
     654           0 :       std::string concat_str = uvecsALab + ": CONCATENATE";
     655           0 :       for(unsigned i=0; i<sp_laba.size(); ++i) {
     656             :         std::string snum;
     657           0 :         Tools::convert( i+1, snum );
     658           0 :         concat_str += " MATRIX" + snum + "1=" + uvecsALab + snum;
     659           0 :         readInputLine( uvecsALab + snum + ": VSTACK" + getArgsForStack( l, sp_laba[i] ) );
     660             :       }
     661             :       // And the normalising matrix by taking the column vector of magnitudes and multiplying by the row vector of ones
     662           0 :       readInputLine( nmatALab + ": OUTER_PRODUCT ARG=" + magsALab + "," + uvecLab);
     663             :       // The unormalised vector
     664           0 :       readInputLine( concat_str );
     665             :     }
     666             :     // Now normalise all the vectors by doing Hadammard "product" with normalising matrix
     667           1 :     createLabel( vecsA );
     668           3 :     readInputLine( vecsALab + ": CUSTOM ARG=" + uvecsALab + ","
     669           2 :                    + nmatALab + " FUNC=x/y PERIODIC=NO");
     670             :     // Now do second matrix
     671           1 :     createLabel(nmatB);
     672           1 :     createLabel(uvecsBT);
     673           1 :     createLabel(uvecsB);
     674           1 :     if( sp_labb.size()==1 ) {
     675           0 :       readInputLine( nmatBLab + ": OUTER_PRODUCT ARG=" +  uvecLab + ","
     676           0 :                      + sp_labb[0] + "_norm");
     677           0 :       readInputLine( uvecsBTLab + ": VSTACK" + getArgsForStack( l, sp_labb[0] ) );
     678           0 :       readInputLine( uvecsBLab + ": TRANSPOSE ARG=" + uvecsBTLab);
     679             :     } else {
     680           1 :       createLabel(magsB);
     681           2 :       std::string len_vec = magsBLab + ": CONCATENATE ARG=" +  sp_labb[0] + "_norm";
     682           2 :       for(unsigned i=1; i<sp_labb.size(); ++i) {
     683           2 :         len_vec += "," + sp_labb[i] + "_norm";
     684             :       }
     685             :       //  This is the vector that contains all the magnitudes
     686           1 :       readInputLine( len_vec );
     687           1 :       std::string concat_str = uvecsBLab + ": CONCATENATE";
     688           3 :       for(unsigned i=0; i<sp_labb.size(); ++i) {
     689             :         std::string snum;
     690           2 :         Tools::convert( i+1, snum );
     691           4 :         concat_str += " MATRIX1" + snum + "=" + uvecsBLab + snum;
     692           4 :         readInputLine( uvecsBTLab + snum + ": VSTACK" + getArgsForStack( l, sp_labb[i] ) );
     693           4 :         readInputLine( uvecsBLab + snum + ": TRANSPOSE ARG=" + uvecsBTLab + snum );
     694             :       }
     695             :       // And the normalising matrix
     696           2 :       readInputLine( nmatBLab + ": OUTER_PRODUCT ARG=" + uvecLab + "," + magsBLab);
     697             :       // The unormalised vectors
     698           1 :       readInputLine( concat_str );
     699             :     }
     700             :     // Now normalise all the vectors by doing Hadammard "product" with normalising matrix
     701           1 :     createLabel(vecsB);
     702           3 :     readInputLine( vecsBLab + ": CUSTOM ARG=" + uvecsBLab + ","
     703           2 :                    + nmatBLab + " FUNC=x/y PERIODIC=NO");
     704             :     std::string sw_str;
     705           2 :     parse("SWITCH",sw_str);
     706             :     std::string maskstr;
     707           2 :     parse("MASK",maskstr);
     708           1 :     if( maskstr.length()>0 ) {
     709           0 :       maskstr=" MASK=" + maskstr;
     710             :     }
     711           3 :     readInputLine( cmapLab + ": CONTACT_MATRIX GROUPA=" + spa_str
     712           2 :                    + " GROUPB=" + spb_str + " SWITCH={" + sw_str + "}" + maskstr + doUSEGPU);
     713           3 :     readInputLine( dpmatLab + ": MATRIX_PRODUCT ARG=" + vecsALab + "," + vecsBLab
     714           2 :                    + " MASK=" + cmapLab + doUSEGPU);
     715           1 :   }
     716             : 
     717             :   // Now create the product matrix
     718           7 :   createLabel( prod );
     719          14 :   readInputLine( prodLab + ": CUSTOM ARG=" + cmapLab + "," + dpmatLab + " FUNC=x*y PERIODIC=NO");
     720             :   // Now the sum of coordination numbers times the switching functions
     721           7 :   ActionWithValue* av = plumed.getActionSet().selectWithLabel<ActionWithValue*>( cmapLab);
     722           7 :   plumed_assert( av && av->getNumberOfComponents()>0 && (av->copyOutput(0))->getRank()==2 );
     723             :   std::string size;
     724           7 :   Tools::convert( (av->copyOutput(0))->getShape()[1], size );
     725           7 :   createLabel( ones );
     726          14 :   readInputLine( onesLab + ": ONES SIZE=" + size );
     727          14 :   readInputLine( getShortcutLabel() + ": MATRIX_VECTOR_PRODUCT "
     728          21 :                  "ARG=" + prodLab +"," + getShortcutLabel() +"_ones" + doUSEGPU);
     729             :   // And just the sum of the coordination numbers
     730          14 :   readInputLine( getShortcutLabel() + "_denom: MATRIX_VECTOR_PRODUCT "
     731          21 :                  "ARG=" + cmapLab + "," + getShortcutLabel() +"_ones" + doUSEGPU);
     732             :   // And matheval to get the final quantity
     733           7 :   createLabel( av );
     734          21 :   readInputLine( avLab + ": CUSTOM ARG=" + getShortcutLabel() + ","
     735          21 :                  + getShortcutLabel() + "_denom FUNC=x/y PERIODIC=NO");
     736             :   // And this expands everything
     737          14 :   multicolvar::MultiColvarShortcuts::expandFunctions( getShortcutLabel(), avLab, "", this );
     738             : #undef createLabel
     739           7 : }
     740             : 
     741             : }
     742             : }

Generated by: LCOV version 1.16