Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2016-2021 The VES code team 3 : (see the PEOPLE-VES file at the root of this folder for a list of names) 4 : 5 : See http://www.ves-code.org for more information. 6 : 7 : This file is part of VES code module. 8 : 9 : The VES code module 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 : The VES code module 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 the VES code module. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : 23 : #include "BasisFunctions.h" 24 : 25 : #include "core/ActionRegister.h" 26 : 27 : 28 : namespace PLMD { 29 : namespace ves { 30 : 31 : //+PLUMEDOC VES_BASISF BF_FOURIER 32 : /* 33 : Fourier basis functions. 34 : 35 : Use as basis functions Fourier series defined on a periodic interval. 36 : You need to provide the periodic interval \f$[a,b]\f$ 37 : on which the basis functions are to be used, and the order of the 38 : expansion \f$N\f$ (i.e. the highest Fourier mode used). 39 : The total number of basis functions is \f$2N+1\f$ as for each Fourier 40 : mode there is both the cosine and sine term, 41 : and the constant \f$f_{0}(x)=1\f$ is also included. 42 : These basis functions should only be used for periodic CVs. 43 : 44 : The Fourier series basis functions are given by 45 : \f{align}{ 46 : f_{0}(x) &= 1 \\ 47 : f_{1}(x) &= cos(\frac{2\pi }{P} x) \\ 48 : f_{2}(x) &= sin(\frac{2\pi }{P} x) \\ 49 : f_{3}(x) &= cos(2 \cdot \frac{2\pi}{P} x) \\ 50 : f_{4}(x) &= sin(2 \cdot \frac{2\pi}{P} x) \\ 51 : & \vdots \\ 52 : f_{2k-1}(x) &= cos(k \cdot \frac{2\pi}{P} x) \\ 53 : f_{2k}(x) &= sin(k \cdot \frac{2\pi}{P} x) \\ 54 : & \vdots \\ 55 : f_{2N-1}(x) &= cos(N \cdot \frac{2\pi}{P} x) \\ 56 : f_{2N}(x) &= sin(N \cdot \frac{2\pi}{P} x) \\ 57 : \f} 58 : where \f$P=(b-a)\f$ is the periodicity of the interval. 59 : They are orthogonal over the interval \f$[a,b]\f$ 60 : \f[ 61 : \int_{a}^{b} dx \, f_{n}(x)\, f_{m}(x) = 62 : \begin{cases} 63 : 0 & n \neq m \\ 64 : (b-a) & n = m = 0 \\ 65 : (b-a)/2 & n = m \neq 0 66 : \end{cases}. 67 : \f] 68 : 69 : 70 : \par Examples 71 : 72 : Here we employ a Fourier expansion of order 10 over the periodic interval 73 : \f$-\pi\f$ to \f$+\pi\f$. 74 : This results in a total number of 21 basis functions. 75 : The label used to identify the basis function action can then be 76 : referenced later on in the input file. 77 : \plumedfile 78 : BF_FOURIER MINIMUM=-pi MAXIMUM=+pi ORDER=10 LABEL=bf_fourier 79 : \endplumedfile 80 : 81 : 82 : */ 83 : //+ENDPLUMEDOC 84 : 85 : class BF_Fourier : public BasisFunctions { 86 : void setupLabels() override; 87 : void setupUniformIntegrals() override; 88 : public: 89 : static void registerKeywords(Keywords&); 90 : explicit BF_Fourier(const ActionOptions&); 91 : void getAllValues(const double, double&, bool&, std::vector<double>&, std::vector<double>&) const override; 92 : }; 93 : 94 : 95 10514 : PLUMED_REGISTER_ACTION(BF_Fourier,"BF_FOURIER") 96 : 97 : 98 96 : void BF_Fourier::registerKeywords(Keywords& keys) { 99 96 : BasisFunctions::registerKeywords(keys); 100 96 : } 101 : 102 : 103 95 : BF_Fourier::BF_Fourier(const ActionOptions&ao): 104 95 : PLUMED_VES_BASISFUNCTIONS_INIT(ao) 105 : { 106 95 : setNumberOfBasisFunctions(2*getOrder()+1); 107 190 : setIntrinsicInterval("-pi","+pi"); 108 : setPeriodic(); 109 : setIntervalBounded(); 110 95 : setType("trigonometric_cos-sin"); 111 95 : setDescription("Trigonometric (cos/sin)"); 112 95 : setupBF(); 113 95 : checkRead(); 114 95 : } 115 : 116 : 117 3244265 : void BF_Fourier::getAllValues(const double arg, double& argT, bool& inside_range, std::vector<double>& values, std::vector<double>& derivs) const { 118 : // plumed_assert(values.size()==numberOfBasisFunctions()); 119 : // plumed_assert(derivs.size()==numberOfBasisFunctions()); 120 3244265 : inside_range=true; 121 3244265 : argT=translateArgument(arg, inside_range); 122 3244265 : values[0]=1.0; 123 3244265 : derivs[0]=0.0; 124 17806383 : for(unsigned int i=1; i < getOrder()+1; i++) { 125 14562118 : double io = i; 126 14562118 : double cos_tmp = cos(io*argT); 127 14562118 : double sin_tmp = sin(io*argT); 128 14562118 : values[2*i-1] = cos_tmp; 129 14562118 : derivs[2*i-1] = -io*sin_tmp*intervalDerivf(); 130 14562118 : values[2*i] = sin_tmp; 131 14562118 : derivs[2*i] = io*cos_tmp*intervalDerivf(); 132 : } 133 3244265 : if(!inside_range) { 134 23980 : for(unsigned int i=0; i<derivs.size(); i++) {derivs[i]=0.0;} 135 : } 136 3244265 : } 137 : 138 : 139 95 : void BF_Fourier::setupLabels() { 140 95 : setLabel(0,"1"); 141 568 : for(unsigned int i=1; i < getOrder()+1; i++) { 142 473 : std::string is; Tools::convert(i,is); 143 946 : setLabel(2*i-1,"cos("+is+"*s)"); 144 946 : setLabel(2*i,"sin("+is+"*s)"); 145 : } 146 95 : } 147 : 148 : 149 94 : void BF_Fourier::setupUniformIntegrals() { 150 94 : setAllUniformIntegralsToZero(); 151 : setUniformIntegral(0,1.0); 152 94 : } 153 : 154 : 155 : } 156 : }