1 | //
|
---|
2 | // taylor.cc
|
---|
3 | //
|
---|
4 | // Copyright (C) 1996 Limit Point Systems, Inc.
|
---|
5 | //
|
---|
6 | // Author: Curtis Janssen <cljanss@limitpt.com>
|
---|
7 | // Maintainer: LPS
|
---|
8 | //
|
---|
9 | // This file is part of the SC Toolkit.
|
---|
10 | //
|
---|
11 | // The SC Toolkit is free software; you can redistribute it and/or modify
|
---|
12 | // it under the terms of the GNU Library General Public License as published by
|
---|
13 | // the Free Software Foundation; either version 2, or (at your option)
|
---|
14 | // any later version.
|
---|
15 | //
|
---|
16 | // The SC Toolkit is distributed in the hope that it will be useful,
|
---|
17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
19 | // GNU Library General Public License for more details.
|
---|
20 | //
|
---|
21 | // You should have received a copy of the GNU Library General Public License
|
---|
22 | // along with the SC Toolkit; see the file COPYING.LIB. If not, write to
|
---|
23 | // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
24 | //
|
---|
25 | // The U.S. Government is granted a limited license as per AL 91-7.
|
---|
26 | //
|
---|
27 |
|
---|
28 | #ifdef __GNUC__
|
---|
29 | #pragma implementation
|
---|
30 | #endif
|
---|
31 |
|
---|
32 | #include <util/class/scexception.h>
|
---|
33 | #include <util/misc/formio.h>
|
---|
34 | #include <util/state/stateio.h>
|
---|
35 | #include <math/scmat/local.h>
|
---|
36 | #include <chemistry/molecule/taylor.h>
|
---|
37 |
|
---|
38 | using namespace std;
|
---|
39 | using namespace sc;
|
---|
40 |
|
---|
41 | static ClassDesc TaylorMolecularEnergy_cd(
|
---|
42 | typeid(TaylorMolecularEnergy),"TaylorMolecularEnergy",1,"public MolecularEnergy",
|
---|
43 | 0, create<TaylorMolecularEnergy>, create<TaylorMolecularEnergy>);
|
---|
44 |
|
---|
45 | // Note: this gets the values of the coordinates from the current molecule
|
---|
46 | // rather than the coordinates.
|
---|
47 | TaylorMolecularEnergy::TaylorMolecularEnergy(const Ref<KeyVal>&keyval):
|
---|
48 | MolecularEnergy(keyval)
|
---|
49 | {
|
---|
50 | coordinates_ << keyval->describedclassvalue("coordinates");
|
---|
51 | // if coordinates is nonnull use cartesian coordinates
|
---|
52 | if (coordinates_.nonnull()) {
|
---|
53 | dim_ = new SCDimension(coordinates_->n());
|
---|
54 | }
|
---|
55 | else {
|
---|
56 | dim_ = moldim();
|
---|
57 | }
|
---|
58 | if (coordinates_.nonnull()) {
|
---|
59 | expansion_point_ = matrixkit()->vector(dim_);
|
---|
60 | coordinates_->update_values(molecule());
|
---|
61 | coordinates_->values_to_vector(expansion_point_);
|
---|
62 | }
|
---|
63 | else {
|
---|
64 | expansion_point_ = get_cartesian_x();
|
---|
65 | }
|
---|
66 |
|
---|
67 | e0_ = keyval->doublevalue("e0");
|
---|
68 |
|
---|
69 | // count the number of force constants
|
---|
70 | int i;
|
---|
71 | int n_fc1 = keyval->count("force_constants_1");
|
---|
72 | int n_fc = keyval->count("force_constants");
|
---|
73 |
|
---|
74 | int use_guess_hessian = 0;
|
---|
75 | if (coordinates_.null() && n_fc == 0) {
|
---|
76 | use_guess_hessian = 1;
|
---|
77 | n_fc = (moldim().n()*(moldim().n()+1))/2;
|
---|
78 | maxorder_ = 2;
|
---|
79 | }
|
---|
80 |
|
---|
81 | force_constant_index_.resize(n_fc1+n_fc);
|
---|
82 | force_constant_value_.resize(n_fc1+n_fc);
|
---|
83 | maxorder_ = 0;
|
---|
84 | if (n_fc1 > 0) maxorder_ = 1;
|
---|
85 |
|
---|
86 | // first read in the short hand notation for first derivatives
|
---|
87 | for (i=0; i<n_fc1; i++) {
|
---|
88 | force_constant_value_[i] = keyval->doublevalue("force_constants_1", i);
|
---|
89 | force_constant_index_[i].resize(1);
|
---|
90 | force_constant_index_[i][0] = i;
|
---|
91 | }
|
---|
92 |
|
---|
93 | if (use_guess_hessian) {
|
---|
94 | RefSymmSCMatrix hess(moldim(), matrixkit());
|
---|
95 | guess_hessian(hess);
|
---|
96 | int ifc,j;
|
---|
97 | for (ifc=i=0; i<moldim().n(); i++) {
|
---|
98 | for (j=0; j<=i; j++, ifc++) {
|
---|
99 | force_constant_index_[n_fc1+ifc].resize(2);
|
---|
100 | force_constant_index_[n_fc1+ifc][0] = i;
|
---|
101 | force_constant_index_[n_fc1+ifc][1] = j;
|
---|
102 | force_constant_value_[n_fc1+ifc] = hess->get_element(i,j);
|
---|
103 | }
|
---|
104 | }
|
---|
105 | }
|
---|
106 | else {
|
---|
107 | // read in the general force constants
|
---|
108 | for (i=0; i<n_fc; i++) {
|
---|
109 | int order = keyval->count("force_constants", i) - 1;
|
---|
110 | force_constant_value_[n_fc1+i]
|
---|
111 | = keyval->doublevalue("force_constants", i,order);
|
---|
112 | force_constant_index_[n_fc1+i].resize(order);
|
---|
113 | if (maxorder_ < order) maxorder_ = order;
|
---|
114 | for (int j=0; j<order; j++) {
|
---|
115 | force_constant_index_[n_fc1+i][j]
|
---|
116 | = keyval->intvalue("force_constants",i,j) - 1;
|
---|
117 | }
|
---|
118 | }
|
---|
119 | }
|
---|
120 | }
|
---|
121 |
|
---|
122 | TaylorMolecularEnergy::~TaylorMolecularEnergy()
|
---|
123 | {
|
---|
124 | }
|
---|
125 |
|
---|
126 | TaylorMolecularEnergy::TaylorMolecularEnergy(StateIn&s):
|
---|
127 | SavableState(s),
|
---|
128 | MolecularEnergy(s)
|
---|
129 | {
|
---|
130 | throw ProgrammingError("cannot save state for this class",
|
---|
131 | __FILE__, __LINE__, class_desc());
|
---|
132 | }
|
---|
133 |
|
---|
134 | void
|
---|
135 | TaylorMolecularEnergy::save_data_state(StateOut&s)
|
---|
136 | {
|
---|
137 | MolecularEnergy::save_data_state(s);
|
---|
138 | throw ProgrammingError("cannot save state for this class",
|
---|
139 | __FILE__, __LINE__, class_desc());
|
---|
140 | }
|
---|
141 |
|
---|
142 | void
|
---|
143 | TaylorMolecularEnergy::print(ostream&o) const
|
---|
144 | {
|
---|
145 | MolecularEnergy::print(o);
|
---|
146 | if (coordinates_.nonnull()) coordinates_->print_details(molecule(), o);
|
---|
147 | int nfc = force_constant_index_.size();
|
---|
148 | o << indent << "Force Constants:" << endl;
|
---|
149 | o << incindent;
|
---|
150 | for (int i=0; i<nfc; i++) {
|
---|
151 | int order = force_constant_index_[i].size();
|
---|
152 | for (int j=0; j<order; j++) {
|
---|
153 | o << indent << scprintf("%5d",force_constant_index_[i][j]+1);
|
---|
154 | }
|
---|
155 | o << indent
|
---|
156 | << scprintf(" %*.*f",14,10,force_constant_value_[i])
|
---|
157 | << endl;
|
---|
158 | }
|
---|
159 | o << decindent;
|
---|
160 | }
|
---|
161 |
|
---|
162 | // this is used by the factor function
|
---|
163 | static int
|
---|
164 | factorial(int i)
|
---|
165 | {
|
---|
166 | if (i<2) return 1;
|
---|
167 | return i*factorial(i-1);
|
---|
168 | }
|
---|
169 |
|
---|
170 | // Compute the factors such as 1/4!, etc. assuming that only unique
|
---|
171 | // force constants we given.
|
---|
172 | static double
|
---|
173 | factor(std::vector<int>&indices)
|
---|
174 | {
|
---|
175 | std::map<int,int> n_occur;
|
---|
176 | int i;
|
---|
177 | for (i=0; i<indices.size(); i++) {
|
---|
178 | n_occur[indices[i]] = 0;
|
---|
179 | }
|
---|
180 | for (i=0; i<indices.size(); i++) {
|
---|
181 | n_occur[indices[i]]++;
|
---|
182 | }
|
---|
183 | int n_indices = indices.size();
|
---|
184 | int int_factor = 1;
|
---|
185 | std::map<int,int>::iterator I;
|
---|
186 | for (I=n_occur.begin(); I!=n_occur.end(); I++) {
|
---|
187 | int n = I->second;
|
---|
188 | int_factor *= factorial(n_indices)
|
---|
189 | /(factorial(n)*factorial(n_indices-n));
|
---|
190 | n_indices -= n;
|
---|
191 | }
|
---|
192 | double term = ((double)int_factor) / factorial(indices.size());
|
---|
193 | return term;
|
---|
194 | }
|
---|
195 |
|
---|
196 | void
|
---|
197 | TaylorMolecularEnergy::compute()
|
---|
198 | {
|
---|
199 | RefSCVector geometry;
|
---|
200 |
|
---|
201 | if (coordinates_.nonnull()) {
|
---|
202 | coordinates_->update_values(molecule());
|
---|
203 | geometry = expansion_point_.clone();
|
---|
204 | coordinates_->values_to_vector(geometry);
|
---|
205 | }
|
---|
206 | else {
|
---|
207 | geometry = get_cartesian_x();
|
---|
208 | }
|
---|
209 |
|
---|
210 | RefSCVector displacement = geometry - expansion_point_;
|
---|
211 |
|
---|
212 | if (value_needed()) {
|
---|
213 | double e = e0_;
|
---|
214 | for (int i=0; i<force_constant_index_.size(); i++) {
|
---|
215 | double term = force_constant_value_[i]
|
---|
216 | * factor(force_constant_index_[i]);
|
---|
217 | for (int j=0; j<force_constant_index_[i].size(); j++) {
|
---|
218 | term *= displacement(force_constant_index_[i][j]);
|
---|
219 | }
|
---|
220 | e += term;
|
---|
221 | }
|
---|
222 | set_energy(e);
|
---|
223 | set_actual_value_accuracy(desired_value_accuracy());
|
---|
224 | }
|
---|
225 | if (gradient_needed()) {
|
---|
226 | RefSCVector gradient = expansion_point_.clone();
|
---|
227 | gradient.assign(0.0);
|
---|
228 |
|
---|
229 | for (int i=0; i<force_constant_index_.size(); i++) {
|
---|
230 | double f = force_constant_value_[i]
|
---|
231 | * factor(force_constant_index_[i]);
|
---|
232 | for (int k=0; k<force_constant_index_[i].size(); k++) {
|
---|
233 | double t = 1.0;
|
---|
234 | for (int l=0; l<force_constant_index_[i].size(); l++) {
|
---|
235 | if (l == k) continue;
|
---|
236 | t *= displacement(force_constant_index_[i][l]);
|
---|
237 | }
|
---|
238 | gradient.accumulate_element(force_constant_index_[i][k],f*t);
|
---|
239 | }
|
---|
240 | }
|
---|
241 |
|
---|
242 | // this will only work for cartesian coordinates
|
---|
243 | set_gradient(gradient);
|
---|
244 | set_actual_gradient_accuracy(desired_gradient_accuracy());
|
---|
245 | }
|
---|
246 | }
|
---|
247 |
|
---|
248 | int
|
---|
249 | TaylorMolecularEnergy::value_implemented() const
|
---|
250 | {
|
---|
251 | return 1;
|
---|
252 | }
|
---|
253 |
|
---|
254 | int
|
---|
255 | TaylorMolecularEnergy::gradient_implemented() const
|
---|
256 | {
|
---|
257 | return coordinates_.null() && maxorder_ >= 1;
|
---|
258 | }
|
---|
259 |
|
---|
260 | int
|
---|
261 | TaylorMolecularEnergy::hessian_implemented() const
|
---|
262 | {
|
---|
263 | return 0;
|
---|
264 | }
|
---|
265 |
|
---|
266 | /////////////////////////////////////////////////////////////////////////////
|
---|
267 |
|
---|
268 | // Local Variables:
|
---|
269 | // mode: c++
|
---|
270 | // c-file-style: "CLJ"
|
---|
271 | // End:
|
---|