Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2011-2023 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : #ifndef __PLUMED_tools_Angle_h 23 : #define __PLUMED_tools_Angle_h 24 : 25 : #include "Vector.h" 26 : #include "Tools.h" 27 : #include <cmath> 28 : #include <limits> 29 : 30 : namespace PLMD { 31 : 32 : /// \ingroup TOOLBOX 33 : /// Class to compute angles. 34 : /// I define it as a class even if it does not contain anything. The reason 35 : /// is that in the future I would like to extend it to contain options about 36 : /// how the calculation should be done. So, for now use it as 37 : /// Angle a; 38 : /// double angle=a.compute(v1,v2); 39 : /// I know it is a bit misleading. If we really do not need to store "options" 40 : /// inside the Angle class, we can remove it later and write compute as 41 : /// a static function. 42 : class Angle { 43 : // still empty, but may accommodate some options in the future 44 : public: 45 : /// Compute the angle between vectors v1 and v2 46 : template <typename T> 47 : static T compute(const VectorTyped<T,3> v1,const VectorTyped<T,3> v2) { 48 : return std::acos(dotProduct(v1,v2)/(v1.modulo()*v2.modulo())); 49 : } 50 : /// Compute the angle between vectors v1 and v2 and its derivatives wrt v1 and v2 51 : template <typename T> 52 784680 : static T compute(const VectorTyped<T,3> v1, 53 : const VectorTyped<T,3> v2, 54 : VectorTyped<T,3>& d1, 55 : VectorTyped<T,3>& d2) { 56 : using V3=VectorTyped<T,3>; 57 : const T dp(dotProduct(v1,v2)); 58 : const V3& dp_dv1(v2); 59 : const V3& dp_dv2(v1); 60 : const T sv1(v1.modulo2()); 61 : const T sv2(v2.modulo2()); 62 : const V3 dsv1_dv1(2*v1); 63 : const V3 dsv2_dv2(2*v2); 64 784680 : const T nn(1.0/std::sqrt(sv1*sv2)); 65 784680 : const V3 dnn_dv1(-0.5*nn/sv1*dsv1_dv1); 66 784680 : const V3 dnn_dv2(-0.5*nn/sv2*dsv2_dv2); 67 : 68 784680 : const T dpnn(dp*nn); 69 : // the tolerance must be T's: PLMD::epsilon is double's, which for float means "exactly 1" 70 : const T eps(std::numeric_limits<T>::epsilon()); 71 784680 : if(dpnn>=1.0-eps) { 72 0 : d1=V3(0.0,0.0,0.0); 73 0 : d2=V3(0.0,0.0,0.0); 74 0 : return 0.0; 75 : } 76 784680 : if(dpnn<=-1.0+eps) { 77 0 : d1=V3(0.0,0.0,0.0); 78 0 : d2=V3(0.0,0.0,0.0); 79 0 : return pi; 80 : } 81 : const V3 ddpnn_dv1(dp*dnn_dv1+dp_dv1*nn); 82 : const V3 ddpnn_dv2(dp*dnn_dv2+dp_dv2*nn); 83 : 84 784680 : const T x(-1.0/std::sqrt(1-dpnn*dpnn)); 85 : 86 784680 : d1=x*ddpnn_dv1; 87 784680 : d2=x*ddpnn_dv2; 88 : 89 : 90 784680 : return std::acos(dpnn); 91 : } 92 : 93 : }; 94 : 95 : } 96 : 97 : #endif