LCOV - code coverage report
Current view: top level - symfunc - Fccubic.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 32 32 100.0 %
Date: 2025-12-04 11:19:34 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2014-2020 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 "function/FunctionSetup.h"
      23             : #include "function/FunctionShortcut.h"
      24             : #include "function/FunctionOfMatrix.h"
      25             : #include "core/ActionRegister.h"
      26             : 
      27             : #include <string>
      28             : #include <cmath>
      29             : 
      30             : namespace PLMD {
      31             : namespace symfunc {
      32             : 
      33             : //+PLUMEDOC MCOLVAR FCCUBIC
      34             : /*
      35             : Measure how similar the environment around atoms is to that found in a FCC structure.
      36             : 
      37             : This shortcut is an example of a [COORDINATION_SHELL_AVERAGE](COORDINATION_SHELL_AVERAGE.md),
      38             : which we can use to measure how similar the environment around atom $i$ is to an fcc structure.
      39             : The function that is used to make this determination is as follows:
      40             : 
      41             : $$
      42             : s_i = \frac{ \sum_{i \ne j} \sigma(r_{ij}) \left\{ a\left[ \frac{(x_{ij}y_{ij})^4 + (x_{ij}z_{ij})^4 + (y_{ij}z_{ij})^4}{r_{ij}^8} - \frac{\alpha (x_{ij}y_{ij}z_{ij})^4}{r_{ij}^{12}} \right] + b \right\} }{ \sum_{i \ne j} \sigma(r_{ij}) }
      43             : $$
      44             : 
      45             : 
      46             : In this expression $x_{ij}$, $y_{ij}$ and $z_{ij}$ are the $x$, $y$ and $z$ components of the vector connecting atom $i$ to
      47             : atom $j$ and $r_{ij}$ is the magnitude of this vector.  $\sigma(r_{ij})$ is a switching function that acts on the distance between
      48             : atom $i$ and atom $j$ and its inclusion in the numerator and the denominator of the above expression as well as the fact that we are summing
      49             : over all of the other atoms in the system ensures that we are calculating an average
      50             : of the function of $x_{ij}$, $y_{ij}$ and $z_{ij}$ for the atoms in the first coordination sphere around atom $i$.  Lastly, $\alpha$
      51             : is a parameter that can be set by the user, which by default is equal to three.  The values of $a$ and $b$ are calculated from $\alpha$ using:
      52             : 
      53             : $$
      54             : a = \frac{ 80080}{ 2717 + 16 \alpha} \qquad \textrm{and} \qquad b = \frac{ 16(\alpha - 143) }{2717 + 16\alpha}
      55             : $$
      56             : 
      57             : This action was been used in all the articles in the bibliography. We thus wrote an explict
      58             : action to calculate it in PLUMED instead of using a shortcut as we did for [SIMPLECUBIC](SIMPLECUBIC.md) so that we could get
      59             : good computational performance.  Notice also that you can you can rotate the bond vectors before computing the
      60             : function in the above expression by using the PHI, THETA and PSI keywords as is discussed in the documentation for [COORDINATION_SHELL_FUNCTION](COORDINATION_SHELL_FUNCTION.md).
      61             : 
      62             : The following input calculates the FCCUBIC parameter for the 64 atoms in the system
      63             : and then calculates and prints the average value for this quantity.
      64             : 
      65             : ```plumed
      66             : d: FCCUBIC SPECIES=1-64 D_0=3.0 R_0=1.5 NN=6 MM=12
      67             : dm: MEAN ARG=d PERIODIC=NO
      68             : PRINT ARG=dm FILE=colv
      69             : ```
      70             : 
      71             : In the input above we use a rational [switching function](LESS_THAN.md) with the parameters above. We would recommend using SWITCH syntax
      72             : rather than the syntax above when giving the parameters for the switching function as you can then use any of the switching functions described
      73             : in the documentation for [LESS_THAN](LESS_THAN.md).  More importantly, however, using this syntax allows you to set the D_MAX parameter for the
      74             : switching function as demonstrated below:
      75             : 
      76             : ```plumed
      77             : d: FCCUBIC SPECIES=1-64 SWITCH={RATIONAL D_0=3.0 R_0=1.5 D_MAX=6.0}
      78             : dm: MEAN ARG=d PERIODIC=NO
      79             : PRINT ARG=dm FILE=colv
      80             : ```
      81             : 
      82             : Setting the `D_MAX` can substantially improve PLUMED performance as it turns on the linked list algorithm that is discussed in the optimisation details part
      83             : of the documentation for [CONTACT_MATRIX](CONTACT_MATRIX.md).
      84             : 
      85             : ## Working with two types of atom
      86             : 
      87             : If you would like to calculate whether the atoms in GROUPB are arranged around the atoms in GROUPA as they in in an FCC structure you use an input like the one
      88             : shown below:
      89             : 
      90             : ```plumed
      91             : d: FCCUBIC SPECIESA=1-64 SPECIESB=65-200 SWITCH={RATIONAL D_0=3.0 R_0=1.5 D_MAX=6.0}
      92             : lt: MORE_THAN ARG=d SWITCH={RATIONAL R_0=0.5}
      93             : s: SUM ARG=lt PERIODIC=NO
      94             : PRINT ARG=s FILE=colv
      95             : ```
      96             : 
      97             : This input calculates how many of the 64 atoms that were input to the SPECIESA keyword have an fcc value that is greater than 0.5.
      98             : 
      99             : ## The MASK keyword
     100             : 
     101             : 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
     102             : input, which tells FCCUBIC that it is safe not to calculate the FCCUBIC parameter for some of the atoms.  As illustrated below, this is useful if you are using functionality
     103             : from the [volumes module](module_volumes.md) to calculate the average value of the FCCUBIC parameter for only those atoms that lie in a certain part of the simulation box.
     104             : 
     105             : ```plumed
     106             : # Fixed virtual atom which serves as the probe volume's center (pos. in nm)
     107             : center: FIXEDATOM AT=2.5,2.5,2.5
     108             : # Vector in which element i is one if atom i is in sphere of interest and zero otherwise
     109             : sphere: INSPHERE ATOMS=1-400 CENTER=center RADIUS={GAUSSIAN D_0=0.5 R_0=0.01 D_MAX=0.52}
     110             : # Calculate the fccubic parameter of the atoms
     111             : cc: FCCUBIC ...
     112             :   SPECIES=1-400 MASK=sphere
     113             :   SWITCH={RATIONAL D_0=3.0 R_0=1.5 D_MAX=6.0}
     114             : ...
     115             : # Multiply fccubic parameters numbers by sphere vector
     116             : prod: CUSTOM ARG=cc,sphere FUNC=x*y PERIODIC=NO
     117             : # Sum of coordination numbers for atoms that are in the sphere of interest
     118             : numer: SUM ARG=prod PERIODIC=NO
     119             : # Number of atoms that are in sphere of interest
     120             : denom: SUM ARG=sphere PERIODIC=NO
     121             : # Average coordination number for atoms in sphere of interest
     122             : av: CUSTOM ARG=numer,denom FUNC=x/y PERIODIC=NO
     123             : # And print out final CV to a file
     124             : PRINT ARG=av FILE=colvar STRIDE=1
     125             : ```
     126             : 
     127             : This input calculate the average value of the FCCUBIC parameter for only those atoms that are within a spherical region that is centered on the point
     128             : $(2.5,2.5,2.5)$.
     129             : 
     130             : ## Deprecated syntax
     131             : 
     132             : More information on the deprecated keywords that are given below is available in the documentation for the [DISTANCES](DISTANCES.md) command.
     133             : 
     134             : */
     135             : //+ENDPLUMEDOC
     136             : 
     137             : //+PLUMEDOC MCOLVAR FCCUBIC_FUNC
     138             : /*
     139             : Measure how similar the environment around atoms is to that found in a FCC structure.
     140             : 
     141             : This is the function that is used in the [FCCUBIC](FCCUBIC.md) shortcut. You can see an example that shows how it is used
     142             : if you expand the FCCUBIC shortcut in the following example input:
     143             : 
     144             : ```plumed
     145             : d: FCCUBIC SPECIES=1-64 SWITCH={RATIONAL D_0=3.0 R_0=1.5} MEAN
     146             : PRINT ARG=d.* FILE=colv
     147             : ```
     148             : 
     149             : Notice that the decomposition of the function that is illustrated above allows you to do things like the calculation in the following input:
     150             : 
     151             : ```plumed
     152             : # Calculate the distances between atoms
     153             : d_mat: DISTANCE_MATRIX GROUP=1-64 CUTOFF=4.5 COMPONENTS
     154             : # Find the six nearest atom to each of the coordinates
     155             : nn: NEIGHBORS ARG=d_mat.w NLOWEST=6
     156             : # Evalulate the FCC function
     157             : d_vfunc: FCCUBIC_FUNC ARG=d_mat.x,d_mat.y,d_mat.z MASK=nn ALPHA=3.0
     158             : # Take the product of the weights with the fcc function evaluations
     159             : d_wvfunc: CUSTOM ARG=d_vfunc,nn FUNC=x*y PERIODIC=NO
     160             : # Calculate the sum of fcc cubic function values for each atom
     161             : d_ones: ONES SIZE=64
     162             : d: MATRIX_VECTOR_PRODUCT ARG=d_wvfunc,d_ones
     163             : # Calculate the number of neighbours
     164             : d_denom: MATRIX_VECTOR_PRODUCT ARG=nn,d_ones
     165             : # Calculate the average value of the fcc cubic function per bonds
     166             : d_n: CUSTOM ARG=d,d_denom FUNC=x/y PERIODIC=NO
     167             : d_mean: MEAN ARG=d_n PERIODIC=NO
     168             : PRINT ARG=d_mean FILE=colv
     169             : ```
     170             : 
     171             : In this input we evaluate the [FCCUBIC](FCCUBIC.md) function for the six nearest neighbours to each atom rather than the atoms that are within a certain cutoff.
     172             : By using the MASK keyword in the input to FCCUBIC_FUNC we ensure that the [FCCUBIC](FCCUBIC.md) function is only evaluated for the six nearest neighbors.
     173             : 
     174             : */
     175             : //+ENDPLUMEDOC
     176             : 
     177             : class Fccubic {
     178             : public:
     179             :   double alpha, a1, b1;
     180             :   static void registerKeywords( Keywords& keys );
     181             :   static void read( Fccubic& func, ActionWithArguments* action, function::FunctionOptions& funcout );
     182             :   static void calc( const Fccubic& func, bool noderiv, View<const double> args, function::FunctionOutput& funcout );
     183             :   Fccubic& operator=(const Fccubic& m) {
     184             :     alpha = m.alpha;
     185             :     a1 = m.a1;
     186             :     b1 = m.b1;
     187             :     return *this;
     188             :   }
     189             : };
     190             : 
     191             : typedef function::FunctionShortcut<Fccubic> FccubicShortcut;
     192             : PLUMED_REGISTER_ACTION(FccubicShortcut,"FCCUBIC_FUNC")
     193             : typedef function::FunctionOfMatrix<Fccubic> MatrixFccubic;
     194             : PLUMED_REGISTER_ACTION(MatrixFccubic,"FCCUBIC_FUNC_MATRIX")
     195             : 
     196          28 : void Fccubic::registerKeywords( Keywords& keys ) {
     197          28 :   keys.add("compulsory","ALPHA","3.0","The alpha parameter of the angular function");
     198          56 :   keys.setValueDescription("matrix","a function that measures the similarity with an fcc environment");
     199          28 : }
     200             : 
     201           6 : void Fccubic::read( Fccubic& func, ActionWithArguments* action, function::FunctionOptions& funcout ) {
     202             :   // Scaling factors such that '1' corresponds to fcc lattice
     203             :   // and '0' corresponds to isotropic (liquid)
     204           6 :   action->parse("ALPHA",func.alpha);
     205           6 :   func.a1 = 80080. / (2717. + 16*func.alpha);
     206           6 :   func.b1 = 16.*(func.alpha-143)/(2717+16*func.alpha);
     207           6 :   action->log.printf("  setting alpha paramter equal to %f \n",func.alpha);
     208           6 : }
     209             : 
     210     2490346 : void Fccubic::calc( const Fccubic& func, bool noderiv, const View<const double> args, function::FunctionOutput& funcout ) {
     211     2490346 :   double x2 = args[0]*args[0];
     212     2490346 :   double x4 = x2*x2;
     213             : 
     214     2490346 :   double y2 = args[1]*args[1];
     215     2490346 :   double y4 = y2*y2;
     216             : 
     217     2490346 :   double z2 = args[2]*args[2];
     218     2490346 :   double z4 = z2*z2;
     219             : 
     220     2490346 :   double d2 = x2 + y2 + z2;
     221     2490346 :   if( d2 < epsilon ) {
     222             :     d2 = 1;
     223             :   }
     224     2490346 :   double r8 = pow( d2, 4 );
     225     2490346 :   double r12 = pow( d2, 6 );
     226             : 
     227     2490346 :   double tmp = ((x4*y4)+(x4*z4)+(y4*z4))/r8-func.alpha*x4*y4*z4/r12;
     228             : 
     229     2490346 :   double t0 = (x2*y4+x2*z4)/r8-func.alpha*x2*y4*z4/r12;
     230     2490346 :   double t1 = (y2*x4+y2*z4)/r8-func.alpha*y2*x4*z4/r12;
     231     2490346 :   double t2 = (z2*x4+z2*y4)/r8-func.alpha*z2*x4*y4/r12;
     232     2490346 :   double t3 = (2*tmp-func.alpha*x4*y4*z4/r12)/d2;
     233             : 
     234     2490346 :   if( !noderiv ) {
     235        5057 :     funcout.derivs[0][0]=4*func.a1*args[0]*(t0-t3);
     236        5057 :     funcout.derivs[0][1]=4*func.a1*args[1]*(t1-t3);
     237        5057 :     funcout.derivs[0][2]=4*func.a1*args[2]*(t2-t3);
     238             :   }
     239             : 
     240             :   // Set the value and the derivatives
     241     2490346 :   funcout.values[0] = (func.a1*tmp+func.b1);
     242     2490346 : }
     243             : 
     244             : }
     245             : }
     246             : 

Generated by: LCOV version 1.16