1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2011-2021 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 "Value.h"
23 #include "ActionWithValue.h"
24 #include "ActionAtomistic.h"
25 #include "ActionWithArguments.h"
26 #include "ActionWithVirtualAtom.h"
27 #include "tools/Exception.h"
28 #include "Atoms.h"
29 #include "PlumedMain.h"
30 
31 namespace PLMD {
32 
Value()33 Value::Value():
34   action(NULL),
35   value_set(false),
36   value(0.0),
37   inputForce(0.0),
38   hasForce(false),
39   hasDeriv(true),
40   periodicity(unset),
41   min(0.0),
42   max(0.0),
43   max_minus_min(0.0),
44   inv_max_minus_min(0.0)
45 {
46 }
47 
Value(ActionWithValue * av,const std::string & name,const bool withderiv)48 Value::Value(ActionWithValue* av, const std::string& name, const bool withderiv):
49   action(av),
50   value_set(false),
51   value(0.0),
52   inputForce(0.0),
53   hasForce(false),
54   name(name),
55   hasDeriv(withderiv),
56   periodicity(unset),
57   min(0.0),
58   max(0.0),
59   max_minus_min(0.0),
60   inv_max_minus_min(0.0)
61 {
62 }
63 
setupPeriodicity()64 void Value::setupPeriodicity() {
65   if( min==0 && max==0 ) {
66     periodicity=notperiodic;
67   } else {
68     periodicity=periodic;
69     max_minus_min=max-min;
70     plumed_massert(max_minus_min>0, "your function has a very strange domain?");
71     inv_max_minus_min=1.0/max_minus_min;
72   }
73 }
74 
isPeriodic() const75 bool Value::isPeriodic()const {
76   plumed_massert(periodicity!=unset,"periodicity should be set");
77   return periodicity==periodic;
78 }
79 
applyForce(std::vector<double> & forces) const80 bool Value::applyForce(std::vector<double>& forces ) const {
81   if( !hasForce ) return false;
82   plumed_dbg_massert( derivatives.size()==forces.size()," forces array has wrong size" );
83   const unsigned N=derivatives.size();
84   for(unsigned i=0; i<N; ++i) forces[i]=inputForce*derivatives[i];
85   return true;
86 }
87 
setNotPeriodic()88 void Value::setNotPeriodic() {
89   min=0; max=0; periodicity=notperiodic;
90 }
91 
setDomain(const std::string & pmin,const std::string & pmax)92 void Value::setDomain(const std::string& pmin,const std::string& pmax) {
93   str_min=pmin;
94   if( !Tools::convert(str_min,min) ) action->error("could not convert period string " + str_min + " to real");
95   str_max=pmax;
96   if( !Tools::convert(str_max,max) ) action->error("could not convert period string " + str_max + " to read");
97   setupPeriodicity();
98 }
99 
getDomain(std::string & minout,std::string & maxout) const100 void Value::getDomain(std::string&minout,std::string&maxout) const {
101   plumed_massert(periodicity==periodic,"function should be periodic");
102   minout=str_min;
103   maxout=str_max;
104 }
105 
getDomain(double & minout,double & maxout) const106 void Value::getDomain(double&minout,double&maxout) const {
107   plumed_massert(periodicity==periodic,"function should be periodic");
108   minout=min;
109   maxout=max;
110 }
111 
setGradients()112 void Value::setGradients() {
113   // Can't do gradients if we don't have derivatives
114   if( !hasDeriv ) return;
115   gradients.clear();
116   ActionAtomistic*aa=dynamic_cast<ActionAtomistic*>(action);
117   ActionWithArguments*aw=dynamic_cast<ActionWithArguments*>(action);
118   if(aa) {
119     Atoms&atoms((aa->plumed).getAtoms());
120     for(unsigned j=0; j<aa->getNumberOfAtoms(); ++j) {
121       AtomNumber an=aa->getAbsoluteIndex(j);
122       if(atoms.isVirtualAtom(an)) {
123         const ActionWithVirtualAtom* a=atoms.getVirtualAtomsAction(an);
124         for(const auto & p : a->getGradients()) {
125 // controllare l'ordine del matmul:
126           gradients[p.first]+=matmul(Vector(derivatives[3*j],derivatives[3*j+1],derivatives[3*j+2]),p.second);
127         }
128       } else {
129         for(unsigned i=0; i<3; i++) gradients[an][i]+=derivatives[3*j+i];
130       }
131     }
132   } else if(aw) {
133     std::vector<Value*> values=aw->getArguments();
134     for(unsigned j=0; j<derivatives.size(); j++) {
135       for(const auto & p : values[j]->gradients) {
136         AtomNumber iatom=p.first;
137         gradients[iatom]+=p.second*derivatives[j];
138       }
139     }
140   } else plumed_error();
141 }
142 
projection(const Value & v1,const Value & v2)143 double Value::projection(const Value& v1,const Value&v2) {
144   double proj=0.0;
145   const std::map<AtomNumber,Vector> & grad1(v1.gradients);
146   const std::map<AtomNumber,Vector> & grad2(v2.gradients);
147   for(const auto & p1 : grad1) {
148     AtomNumber a=p1.first;
149     const auto p2=grad2.find(a);
150     if(p2!=grad2.end()) {
151       proj+=dotProduct(p1.second,(*p2).second);
152     }
153   }
154   return proj;
155 }
156 
getPntrToAction()157 ActionWithValue* Value::getPntrToAction() {
158   plumed_assert( action!=NULL );
159   return action;
160 }
161 
copy(const Value & val1,Value & val2)162 void copy( const Value& val1, Value& val2 ) {
163   unsigned nder=val1.getNumberOfDerivatives();
164   if( nder!=val2.getNumberOfDerivatives() ) { val2.resizeDerivatives( nder ); }
165   val2.clearDerivatives();
166   for(unsigned i=0; i<val1.getNumberOfDerivatives(); ++i) val2.addDerivative( i, val1.getDerivative(i) );
167   val2.set( val1.get() );
168 }
169 
copy(const Value & val1,Value * val2)170 void copy( const Value& val1, Value* val2 ) {
171   unsigned nder=val1.getNumberOfDerivatives();
172   if( nder!=val2->getNumberOfDerivatives() ) { val2->resizeDerivatives( nder ); }
173   val2->clearDerivatives();
174   for(unsigned i=0; i<val1.getNumberOfDerivatives(); ++i) val2->addDerivative( i, val1.getDerivative(i) );
175   val2->set( val1.get() );
176 }
177 
add(const Value & val1,Value * val2)178 void add( const Value& val1, Value* val2 ) {
179   plumed_assert( val1.getNumberOfDerivatives()==val2->getNumberOfDerivatives() );
180   for(unsigned i=0; i<val1.getNumberOfDerivatives(); ++i) val2->addDerivative( i, val1.getDerivative(i) );
181   val2->set( val1.get() + val2->get() );
182 }
183 
184 }
185