source: src/Potentials/Specifics/ManyBodyPotential_Tersoff.cpp@ ca8d82

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since ca8d82 was ca8d82, checked in by Frederik Heber <heber@…>, 12 years ago

FIX: Corrected parameter derivatives of ManyBodyPotential_Tersoff.

  • setParameters also allows setting of less parameters than required.
  • Property mode set to 100644
File size: 17.2 KB
RevLine 
[610c11]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2012 University of Bonn. All rights reserved.
5 * Please see the COPYING file or "Copyright notice" in builder.cpp for details.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * ManyBodyPotential_Tersoff.cpp
26 *
27 * Created on: Sep 26, 2012
28 * Author: heber
29 */
30
31
32// include config.h
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36
37#include "CodePatterns/MemDebug.hpp"
38
39#include "ManyBodyPotential_Tersoff.hpp"
40
41#include <boost/bind.hpp>
42#include <cmath>
43
44#include "CodePatterns/Assert.hpp"
[ffc368]45//#include "CodePatterns/Info.hpp"
[f904d5]46#include "CodePatterns/Log.hpp"
[610c11]47
48#include "Potentials/helpers.hpp"
49
[e7579e]50ManyBodyPotential_Tersoff::ManyBodyPotential_Tersoff(
51 boost::function< std::vector<arguments_t>(const argument_t &, const double)> &_triplefunction
52 ) :
53 params(parameters_t(MAXPARAMS, 0.)),
[752dc7]54 R(3.2),
55 S(3.5),
[990a62]56 lambda3(0.),
57 alpha(0.),
58 chi(1.),
59 omega(1.),
[e7579e]60 triplefunction(_triplefunction)
61{}
62
63ManyBodyPotential_Tersoff::ManyBodyPotential_Tersoff(
[ffc368]64 const double &_R,
65 const double &_S,
[e7579e]66 const double &_A,
67 const double &_B,
[ffc368]68 const double &_lambda,
69 const double &_mu,
[e7579e]70 const double &_lambda3,
71 const double &_alpha,
72 const double &_beta,
[ffc368]73 const double &_chi,
74 const double &_omega,
[e7579e]75 const double &_n,
76 const double &_c,
77 const double &_d,
78 const double &_h,
79 boost::function< std::vector<arguments_t>(const argument_t &, const double)> &_triplefunction) :
80 params(parameters_t(MAXPARAMS, 0.)),
[752dc7]81 R(_R),
82 S(_S),
[990a62]83 lambda3(_lambda3),
84 alpha(_alpha),
85 chi(_chi),
86 omega(_mu),
[e7579e]87 triplefunction(_triplefunction)
88{
[ffc368]89// Info info(__func__);
[752dc7]90// R = _R;
91// S = _S;
[e7579e]92 params[A] = _A;
93 params[B] = _B;
[ffc368]94 params[lambda] = _lambda;
95 params[mu] = _mu;
[990a62]96// lambda3 = _lambda3;
97// alpha = _alpha;
[e7579e]98 params[beta] = _beta;
[990a62]99// chi = _chi;
100// omega = _omega;
[e7579e]101 params[n] = _n;
102 params[c] = _c;
103 params[d] = _d;
104 params[h] = _h;
105}
106
[4f82f8]107ManyBodyPotential_Tersoff::results_t
[610c11]108ManyBodyPotential_Tersoff::operator()(
109 const arguments_t &arguments
110 ) const
111{
[ffc368]112// Info info(__func__);
113 const argument_t &r_ij = arguments[0];
114 const double cutoff = function_cutoff(r_ij.distance);
115 const double result = (cutoff == 0.) ?
116 0. :
117 cutoff * (
118 function_prefactor(
[990a62]119 alpha,
[ffc368]120 function_eta(r_ij))
121 * function_smoother(
122 params[A],
123 params[lambda],
124 r_ij.distance)
125 +
126 function_prefactor(
127 params[beta],
128 function_zeta(r_ij))
129 * function_smoother(
130 -params[B],
131 params[mu],
132 r_ij.distance)
133 );
134// LOG(2, "DEBUG: operator()(" << r_ij.distance << ") = " << result);
[4f82f8]135 return std::vector<result_t>(1, result);
[610c11]136}
137
[ffc368]138ManyBodyPotential_Tersoff::derivative_components_t
139ManyBodyPotential_Tersoff::derivative(
140 const arguments_t &arguments
141 ) const
142{
143// Info info(__func__);
144 return ManyBodyPotential_Tersoff::derivative_components_t();
145}
146
147ManyBodyPotential_Tersoff::results_t
148ManyBodyPotential_Tersoff::parameter_derivative(
149 const arguments_t &arguments,
150 const size_t index
151 ) const
152{
153// Info info(__func__);
154// ASSERT( arguments.size() == 1,
155// "PairPotential_Harmonic::parameter_derivative() - requires exactly one argument.");
156 const argument_t &r_ij = arguments[0];
157 switch (index) {
[752dc7]158// case R:
159// {
160// const double result = 0.;
161// return results_t(1, result);
162// break;
163// }
164// case S:
165// {
166// const double result = 0.;
167// return results_t(1, result);
168// break;
169// }
[ffc368]170 case A:
171 {
[ca8d82]172 const double cutoff = function_cutoff(r_ij.distance);
173 const double result = (cutoff == 0.) ?
174 0. :
175 cutoff *
176 function_prefactor(
177 alpha,
178 function_eta(r_ij))
179 * function_smoother(
180 1.,
181 params[lambda],
182 r_ij.distance);
183// cutoff * function_prefactor(
184// alpha,
185// function_eta(r_ij))
186// * function_smoother(
187// 1.,
188// params[mu],
189// r_ij.distance);
[ffc368]190 return results_t(1, result);
191 break;
192 }
193 case B:
194 {
[ca8d82]195 const double cutoff = function_cutoff(r_ij.distance);
196 const double result = (cutoff == 0.) ?
197 0. :
198 cutoff * function_prefactor(
199 params[beta],
200 function_zeta(r_ij))
201 * function_smoother(
202 -1.,
203 params[mu],
204 r_ij.distance);
205// cutoff * function_prefactor(
206// beta,
207// function_zeta(r_ij))
208// * function_smoother(
209// -params[B],
210// params[mu],
211// r_ij.distance)/params[B];
[ffc368]212 return results_t(1, result);
213 break;
214 }
215 case lambda:
216 {
217 const double cutoff = function_cutoff(r_ij.distance);
218 const double result = (cutoff == 0.) ?
219 0. :
[ca8d82]220 -r_ij.distance * cutoff *
221 function_prefactor(
222 alpha,
223 function_eta(r_ij))
224 * function_smoother(
225 params[A],
226 params[lambda],
227 r_ij.distance);
[ffc368]228 return results_t(1, result);
229 break;
230 }
231 case mu:
232 {
233 const double cutoff = function_cutoff(r_ij.distance);
234 const double result = (cutoff == 0.) ?
235 0. :
[f904d5]236 -r_ij.distance * cutoff *(
[ffc368]237 function_prefactor(
238 params[beta],
239 function_zeta(r_ij))
240 * function_smoother(
241 -params[B],
242 params[mu],
243 r_ij.distance)
244 );
245 return results_t(1, result);
246 break;
247 }
[990a62]248// case lambda3:
249// {
250// const double result = 0.;
251// return results_t(1, result);
252// break;
253// }
254// case alpha:
255// {
256// const double temp =
257// pow(alpha*function_eta(r_ij), params[n]);
258// const double cutoff = function_cutoff(r_ij.distance);
259// const double result = (cutoff == 0.) || (alpha == 0. )?
260// 0. :
261// function_smoother(
[ca8d82]262// params[A],
[990a62]263// params[lambda],
264// r_ij.distance)
265// * (-.5) * alpha * (temp/alpha)
266// / (1. + temp)
267// ;
268// return results_t(1, result);
269// break;
270// }
271// case chi:
272// {
273// const double result = 0.;
274// return results_t(1, result);
275// break;
276// }
277// case omega:
278// {
279// const double result = 0.;
280// return results_t(1, result);
281// break;
282// }
[ffc368]283 case beta:
284 {
285 const double temp =
286 pow(params[beta]*function_zeta(r_ij), params[n]);
287 const double cutoff = function_cutoff(r_ij.distance);
288 const double result = (cutoff == 0.) || (params[beta] == 0. )?
289 0. : cutoff *
290 function_smoother(
291 -params[B],
292 params[mu],
293 r_ij.distance)
[f904d5]294 * (-.5)
295 * function_prefactor(
296 params[beta],
297 function_zeta(r_ij))
298 * (temp/params[beta])
[ffc368]299 / (1. + temp)
300 ;
301 return results_t(1, result);
302 break;
303 }
304 case n:
305 {
306 const double temp =
307 pow(params[beta]*function_zeta(r_ij), params[n]);
308 const double cutoff = function_cutoff(r_ij.distance);
309 const double result = (cutoff == 0.) ?
[f904d5]310 0. : .5 * cutoff *
[ffc368]311 function_smoother(
312 -params[B],
313 params[mu],
314 r_ij.distance)
[f904d5]315 * function_prefactor(
316 params[beta],
317 function_zeta(r_ij))
[ffc368]318 * ( log(1.+temp)/(params[n]*params[n]) - temp
319 * (log(function_zeta(r_ij)) + log(params[beta]))
320 /(params[n]*(1.+temp)))
321 ;
322 return results_t(1, result);
323 break;
324 }
325 case c:
326 {
[f904d5]327 const double zeta = function_zeta(r_ij);
[ca8d82]328 if (zeta == 0.)
329 break;
[f904d5]330 const double temp =
[ca8d82]331 pow(zeta, params[n]-1.) * pow(params[beta],params[n]);
[f904d5]332 const double cutoff = function_cutoff(r_ij.distance);
333 const double result = (cutoff == 0.) ?
[ca8d82]334 0. : cutoff *
[f904d5]335 function_smoother(
336 -params[B],
337 params[mu],
338 r_ij.distance)
339 * function_prefactor(
340 params[beta],
341 zeta)
[ca8d82]342 * (-1.) * temp / (1.+temp*zeta);
343 double factor = function_derivative_c(r_ij);
[f904d5]344 return results_t(1, result*factor);
[ffc368]345 break;
346 }
347 case d:
348 {
[f904d5]349 const double zeta = function_zeta(r_ij);
350 const double temp =
[ca8d82]351 pow(zeta, params[n]-1.) * pow(params[beta],params[n]);
[f904d5]352 const double cutoff = function_cutoff(r_ij.distance);
353 const double result = (cutoff == 0.) ?
[ca8d82]354 0. : cutoff *
[f904d5]355 function_smoother(
356 -params[B],
357 params[mu],
358 r_ij.distance)
359 * function_prefactor(
360 params[beta],
361 zeta)
[ca8d82]362 * (-1.) * temp / (1.+temp*zeta);
363 double factor = function_derivative_d(r_ij);
[f904d5]364 return results_t(1, result*factor);
[ffc368]365 break;
366 }
367 case h:
368 {
[f904d5]369 const double zeta = function_zeta(r_ij);
370 const double temp =
[ca8d82]371 pow(zeta, params[n]-1.) * pow(params[beta],params[n]);
[f904d5]372 const double cutoff = function_cutoff(r_ij.distance);
373 const double result = (cutoff == 0.) ?
[ca8d82]374 0. : cutoff *
[f904d5]375 function_smoother(
376 -params[B],
377 params[mu],
378 r_ij.distance)
379 * function_prefactor(
380 params[beta],
381 zeta)
[ca8d82]382 * (-1.) * temp / (1.+temp*zeta);
383 double factor = function_derivative_h(r_ij);
[f904d5]384 return results_t(1, result*factor);
[ffc368]385 break;
386 }
387 default:
388 break;
389 }
390 return results_t(1, 0.);
391}
392
[ca8d82]393ManyBodyPotential_Tersoff::result_t
394ManyBodyPotential_Tersoff::function_derivative_c(
395 const argument_t &r_ij
396 ) const
397{
398 double result = 0.;
399 std::vector<arguments_t> triples = triplefunction(r_ij, S);
400 for (std::vector<arguments_t>::const_iterator iter = triples.begin();
401 iter != triples.end(); ++iter) {
402 ASSERT( iter->size() == 2,
403 "ManyBodyPotential_Tersoff::function_derivative_c() - the triples result must contain exactly two distances.");
404 const argument_t &r_ik = (*iter)[0];
405 const argument_t &r_jk = (*iter)[1];
406 const double tempangle = params[h] - function_theta(r_ij.distance, r_ik.distance, r_jk.distance);
407 const double cutoff = function_cutoff(r_ik.distance);
408 result += (cutoff == 0.) ?
409 0. : cutoff * omega * exp( Helpers::pow(lambda3 * (r_ij.distance - r_ik.distance) ,3)) * (
410 params[c]/Helpers::pow(params[d],2)
411 - params[c] / ( Helpers::pow(params[d],2) + Helpers::pow(tempangle,2) )
412 );
413 }
414 return result;
415}
416
417ManyBodyPotential_Tersoff::result_t
418ManyBodyPotential_Tersoff::function_derivative_d(
419 const argument_t &r_ij
420 ) const
421{
422 double result = 0.;
423 std::vector<arguments_t> triples = triplefunction(r_ij, S);
424 for (std::vector<arguments_t>::const_iterator iter = triples.begin();
425 iter != triples.end(); ++iter) {
426 ASSERT( iter->size() == 2,
427 "ManyBodyPotential_Tersoff::function_derivative_d() - the triples result must contain exactly two distances.");
428 const argument_t &r_ik = (*iter)[0];
429 const argument_t &r_jk = (*iter)[1];
430 const double tempangle = params[h] - function_theta(r_ij.distance, r_ik.distance, r_jk.distance);
431 const double cutoff = function_cutoff(r_ik.distance);
432 result += (cutoff == 0.) ?
433 0. : cutoff * omega * exp( Helpers::pow(lambda3 * (r_ij.distance - r_ik.distance) ,3)) * (
434 - Helpers::pow(params[c],2)/Helpers::pow(params[d],3)
435 + Helpers::pow(params[c],2) * params[d]
436 / Helpers::pow(Helpers::pow(params[d],2) + Helpers::pow(tempangle,2),2)
437 );
438 }
439 return result;
440}
441
442ManyBodyPotential_Tersoff::result_t
443ManyBodyPotential_Tersoff::function_derivative_h(
444 const argument_t &r_ij
445 ) const
446{
447 double result = 0.;
448 std::vector<arguments_t> triples = triplefunction(r_ij, S);
449 for (std::vector<arguments_t>::const_iterator iter = triples.begin();
450 iter != triples.end(); ++iter) {
451 ASSERT( iter->size() == 2,
452 "ManyBodyPotential_Tersoff::function_derivative_h() - the triples result must contain exactly two distances.");
453 const argument_t &r_ik = (*iter)[0];
454 const argument_t &r_jk = (*iter)[1];
455 const double tempangle = params[h] - function_theta(r_ij.distance, r_ik.distance, r_jk.distance);
456 const double cutoff = function_cutoff(r_ik.distance);
457 result += (cutoff == 0.) ?
458 0. : cutoff * omega * exp( Helpers::pow(lambda3 * (r_ij.distance - r_ik.distance) ,3)) * (
459 ( Helpers::pow(params[c],2)*tempangle )
460 / Helpers::pow(Helpers::pow(params[d],2) + Helpers::pow(tempangle,2),2)
461 );
462 }
463 return result;
464}
465
[4f82f8]466ManyBodyPotential_Tersoff::result_t
[610c11]467ManyBodyPotential_Tersoff::function_cutoff(
468 const double &distance
469 ) const
470{
[ffc368]471// Info info(__func__);
472 double result = 0.;
[752dc7]473 if (distance < R)
[ffc368]474 result = 1.;
[752dc7]475 else if (distance > S)
[ffc368]476 result = 0.;
[610c11]477 else {
[752dc7]478 result = (0.5 + 0.5 * cos( M_PI * (distance - R)/(S-R)));
[610c11]479 }
[ffc368]480// LOG(2, "DEBUG: function_cutoff(" << distance << ") = " << result);
481 return result;
[610c11]482}
483
[4f82f8]484ManyBodyPotential_Tersoff::result_t
[610c11]485ManyBodyPotential_Tersoff::function_prefactor(
486 const double &alpha,
[ffc368]487 const double &eta
[610c11]488 ) const
489{
[ffc368]490// Info info(__func__);
[990a62]491 const double result = chi * pow(
[ffc368]492 (1. + pow(alpha * eta, params[n])),
493 -1./(2.*params[n]));
494// LOG(2, "DEBUG: function_prefactor(" << alpha << "," << eta << ") = " << result);
495 return result;
496}
497
498ManyBodyPotential_Tersoff::result_t
499ManyBodyPotential_Tersoff::function_smoother(
500 const double &prefactor,
501 const double &lambda,
502 const double &distance
503 ) const
504{
505// Info info(__func__);
506 const double result = prefactor * exp(-lambda * distance);
507// LOG(2, "DEBUG: function_smoother(" << prefactor << "," << lambda << "," << distance << ") = " << result);
508 return result;
[610c11]509}
510
[4f82f8]511ManyBodyPotential_Tersoff::result_t
[610c11]512ManyBodyPotential_Tersoff::function_eta(
513 const argument_t &r_ij
514 ) const
515{
[ffc368]516// Info info(__func__);
[610c11]517 result_t result = 0.;
518
519 // get all triples within the cutoff
[752dc7]520 std::vector<arguments_t> triples = triplefunction(r_ij, S);
[610c11]521 for (std::vector<arguments_t>::const_iterator iter = triples.begin();
522 iter != triples.end(); ++iter) {
523 ASSERT( iter->size() == 2,
524 "ManyBodyPotential_Tersoff::function_zeta() - the triples result must contain of exactly two distances.");
525 const argument_t &r_ik = (*iter)[0];
526 result += function_cutoff(r_ik.distance)
[990a62]527 * exp( Helpers::pow(lambda3 * (r_ij.distance - r_ik.distance) ,3));
[610c11]528 }
529
[ffc368]530// LOG(2, "DEBUG: function_eta(" << r_ij.distance << ") = " << result);
[610c11]531 return result;
532}
533
[4f82f8]534ManyBodyPotential_Tersoff::result_t
[610c11]535ManyBodyPotential_Tersoff::function_zeta(
536 const argument_t &r_ij
537 ) const
538{
[ffc368]539// Info info(__func__);
[610c11]540 result_t result = 0.;
541
542 // get all triples within the cutoff
[752dc7]543 std::vector<arguments_t> triples = triplefunction(r_ij, S);
[610c11]544 for (std::vector<arguments_t>::const_iterator iter = triples.begin();
545 iter != triples.end(); ++iter) {
546 ASSERT( iter->size() == 2,
547 "ManyBodyPotential_Tersoff::function_zeta() - the triples result must contain exactly two distances.");
548 const argument_t &r_ik = (*iter)[0];
549 const argument_t &r_jk = (*iter)[1];
550 result +=
551 function_cutoff(r_ik.distance)
[990a62]552 * omega
[610c11]553 * function_angle(r_ij.distance, r_ik.distance, r_jk.distance)
[990a62]554 * exp( Helpers::pow(lambda3 * (r_ij.distance - r_ik.distance) ,3));
[610c11]555 }
556
[ffc368]557// LOG(2, "DEBUG: function_zeta(" << r_ij.distance << ") = " << result);
[610c11]558 return result;
559}
560
[4f82f8]561ManyBodyPotential_Tersoff::result_t
[f904d5]562ManyBodyPotential_Tersoff::function_theta(
[610c11]563 const double &r_ij,
564 const double &r_ik,
565 const double &r_jk
566 ) const
567{
568 const double angle = Helpers::pow(r_ij,2) + Helpers::pow(r_ik,2) - Helpers::pow(r_jk,2);
[ffc368]569 const double divisor = 2.* r_ij * r_ik;
570 if (divisor != 0.) {
[f904d5]571 LOG(2, "DEBUG: cos(theta)= " << angle/divisor);
572 return angle/divisor;
[ffc368]573 } else
574 return 0.;
[610c11]575}
[ffc368]576
[f904d5]577ManyBodyPotential_Tersoff::result_t
578ManyBodyPotential_Tersoff::function_angle(
579 const double &r_ij,
580 const double &r_ik,
581 const double &r_jk
582 ) const
583{
584// Info info(__func__);
585 const double result =
586 1.
587 + (Helpers::pow(params[c]/params[d], 2))
588 - Helpers::pow(params[c], 2)/(Helpers::pow(params[d], 2) +
[ca8d82]589 Helpers::pow(params[h] - function_theta(r_ij, r_ik, r_jk),2));
[f904d5]590
[ca8d82]591// LOG(2, "DEBUG: function_angle(" << r_ij << "," << r_ik << "," << r_jk << ") = " << result);
[f904d5]592 return result;
593}
594
Note: See TracBrowser for help on using the repository browser.