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

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 086070 was 086070, checked in by Frederik Heber <heber@…>, 12 years ago

Moved all setParameters() from header files into module.

  • also each now assert that setParameters() equal getParameters().
  • Property mode set to 100644
File size: 18.7 KB
Line 
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"
45//#include "CodePatterns/Info.hpp"
46#include "CodePatterns/Log.hpp"
47
48#include "Potentials/helpers.hpp"
49
50ManyBodyPotential_Tersoff::ManyBodyPotential_Tersoff(
51 boost::function< std::vector<arguments_t>(const argument_t &, const double)> &_triplefunction
52 ) :
53 params(parameters_t(MAXPARAMS, 0.)),
54 R(3.2),
55 S(3.5),
56 lambda3(0.),
57 alpha(0.),
58 chi(1.),
59 omega(1.),
60 triplefunction(_triplefunction)
61{}
62
63ManyBodyPotential_Tersoff::ManyBodyPotential_Tersoff(
64 const double &_R,
65 const double &_S,
66 const double &_A,
67 const double &_B,
68 const double &_lambda,
69 const double &_mu,
70 const double &_lambda3,
71 const double &_alpha,
72 const double &_beta,
73 const double &_chi,
74 const double &_omega,
75 const double &_n,
76 const double &_c,
77 const double &_d,
78 const double &_h,
79 const double &_offset,
80 boost::function< std::vector<arguments_t>(const argument_t &, const double)> &_triplefunction) :
81 params(parameters_t(MAXPARAMS, 0.)),
82 R(_R),
83 S(_S),
84 lambda3(_lambda3),
85 alpha(_alpha),
86 chi(_chi),
87 omega(_mu),
88 triplefunction(_triplefunction)
89{
90// Info info(__func__);
91// R = _R;
92// S = _S;
93 params[A] = _A;
94 params[B] = _B;
95 params[lambda] = _lambda;
96 params[mu] = _mu;
97// lambda3 = _lambda3;
98// alpha = _alpha;
99 params[beta] = _beta;
100// chi = _chi;
101// omega = _omega;
102 params[n] = _n;
103 params[c] = _c;
104 params[d] = _d;
105 params[h] = _h;
106 params[offset] = _offset;
107}
108
109void ManyBodyPotential_Tersoff::setParameters(const parameters_t &_params)
110{
111 const size_t paramsDim = _params.size();
112 ASSERT( paramsDim <= getParameterDimension(),
113 "ManyBodyPotential_Tersoff::setParameters() - we need not more than "
114 +toString(getParameterDimension())+" parameters.");
115 for (size_t i=0; i< paramsDim; ++i)
116 params[i] = _params[i];
117
118#ifndef NDEBUG
119 parameters_t check_params(getParameters());
120 check_params.resize(paramsDim); // truncate to same size
121 ASSERT( check_params == _params,
122 "ManyBodyPotential_Tersoff::setParameters() - failed, mismatch in to be set "
123 +toString(_params)+" and set "+toString(check_params)+" params.");
124#endif
125}
126
127ManyBodyPotential_Tersoff::results_t
128ManyBodyPotential_Tersoff::operator()(
129 const arguments_t &arguments
130 ) const
131{
132// Info info(__func__);
133 double result = 0.;
134 for(arguments_t::const_iterator argiter = arguments.begin();
135 argiter != arguments.end();
136 ++argiter) {
137 const argument_t &r_ij = *argiter;
138 const double cutoff = function_cutoff(r_ij.distance);
139 const double temp = (cutoff == 0.) ?
140 0. :
141 cutoff * (
142 function_prefactor(
143 alpha,
144 function_eta(r_ij))
145 * function_smoother(
146 params[A],
147 params[lambda],
148 r_ij.distance)
149 +
150 function_prefactor(
151 params[beta],
152 function_zeta(r_ij))
153 * function_smoother(
154 -params[B],
155 params[mu],
156 r_ij.distance)
157 );
158 result += temp;
159 }
160// LOG(2, "DEBUG: operator()(" << r_ij.distance << ") = " << result);
161 return std::vector<result_t>(1, params[offset]+result);
162}
163
164ManyBodyPotential_Tersoff::derivative_components_t
165ManyBodyPotential_Tersoff::derivative(
166 const arguments_t &arguments
167 ) const
168{
169// Info info(__func__);
170 return ManyBodyPotential_Tersoff::derivative_components_t();
171}
172
173ManyBodyPotential_Tersoff::results_t
174ManyBodyPotential_Tersoff::parameter_derivative(
175 const arguments_t &arguments,
176 const size_t index
177 ) const
178{
179// Info info(__func__);
180// ASSERT( arguments.size() == 1,
181// "ManyBodyPotential_Tersoff::parameter_derivative() - requires exactly one argument.");
182 if (index == offset)
183 return results_t(1, 1.);
184
185 double result = 0.;
186 for(arguments_t::const_iterator argiter = arguments.begin();
187 argiter != arguments.end();
188 ++argiter) {
189 const argument_t &r_ij = *argiter;
190 switch (index) {
191// case R:
192// {
193// result += 0.;
194// break;
195// }
196// case S:
197// {
198// result += 0.;
199// break;
200// }
201 case A:
202 {
203 const double cutoff = function_cutoff(r_ij.distance);
204 result += (cutoff == 0.) ?
205 0. :
206 cutoff *
207 function_prefactor(
208 alpha,
209 function_eta(r_ij))
210 * function_smoother(
211 1.,
212 params[lambda],
213 r_ij.distance);
214// cutoff * function_prefactor(
215// alpha,
216// function_eta(r_ij))
217// * function_smoother(
218// 1.,
219// params[mu],
220// r_ij.distance);
221 break;
222 }
223 case B:
224 {
225 const double cutoff = function_cutoff(r_ij.distance);
226 result += (cutoff == 0.) ?
227 0. :
228 cutoff * function_prefactor(
229 params[beta],
230 function_zeta(r_ij))
231 * function_smoother(
232 -1.,
233 params[mu],
234 r_ij.distance);
235// cutoff * function_prefactor(
236// beta,
237// function_zeta(r_ij))
238// * function_smoother(
239// -params[B],
240// params[mu],
241// r_ij.distance)/params[B];
242 break;
243 }
244 case lambda:
245 {
246 const double cutoff = function_cutoff(r_ij.distance);
247 result += (cutoff == 0.) ?
248 0. :
249 -r_ij.distance * cutoff *
250 function_prefactor(
251 alpha,
252 function_eta(r_ij))
253 * function_smoother(
254 params[A],
255 params[lambda],
256 r_ij.distance);
257 break;
258 }
259 case mu:
260 {
261 const double cutoff = function_cutoff(r_ij.distance);
262 result += (cutoff == 0.) ?
263 0. :
264 -r_ij.distance * cutoff *(
265 function_prefactor(
266 params[beta],
267 function_zeta(r_ij))
268 * function_smoother(
269 -params[B],
270 params[mu],
271 r_ij.distance)
272 );
273 break;
274 }
275// case lambda3:
276// {
277// result += 0.;
278// break;
279// }
280// case alpha:
281// {
282// const double temp =
283// pow(alpha*function_eta(r_ij), params[n]);
284// const double cutoff = function_cutoff(r_ij.distance);
285// result += (cutoff == 0.) || (alpha == 0. )?
286// 0. :
287// function_smoother(
288// params[A],
289// params[lambda],
290// r_ij.distance)
291// * (-.5) * alpha * (temp/alpha)
292// / (1. + temp)
293// ;
294// break;
295// }
296// case chi:
297// {
298// result += 0.;
299// break;
300// }
301// case omega:
302// {
303// result += 0.;
304// break;
305// }
306 case beta:
307 {
308 const double temp =
309 pow(params[beta]*function_zeta(r_ij), params[n]);
310 const double cutoff = function_cutoff(r_ij.distance);
311 result += (cutoff == 0.) || (params[beta] == 0. )?
312 0. : cutoff *
313 function_smoother(
314 -params[B],
315 params[mu],
316 r_ij.distance)
317 * (-.5)
318 * function_prefactor(
319 params[beta],
320 function_zeta(r_ij))
321 * (temp/params[beta])
322 / (1. + temp)
323 ;
324 break;
325 }
326 case n:
327 {
328 const double zeta = function_zeta(r_ij);
329 const double temp = pow( params[beta]*zeta , params[n]);
330 const double cutoff = function_cutoff(r_ij.distance);
331 const double tempres = ((cutoff == 0.) || (zeta == 0.)) ? // zeta must be caught if zero due to log
332 0. : .5 * cutoff *
333 function_smoother(
334 -params[B],
335 params[mu],
336 r_ij.distance)
337 * function_prefactor(
338 params[beta],
339 function_zeta(r_ij))
340 * ( log(1.+temp)/(params[n]*params[n]) - temp
341 * (log(function_zeta(r_ij)) + log(params[beta]))
342 /(params[n]*(1.+temp)))
343 ;
344// if (tempres != tempres)
345// LOG(2, "DEBUG: tempres is NaN.");
346// LOG(2, "DEBUG: Adding " << tempres << " for p.d. w.r.t n, temp=" << temp << ", cutoff=" << cutoff);
347 result += tempres;
348 break;
349 }
350 case c:
351 {
352 const double zeta = function_zeta(r_ij);
353 if (zeta == 0.)
354 break;
355 const double temp =
356 pow(zeta, params[n]-1.) * pow(params[beta],params[n]);
357 const double cutoff = function_cutoff(r_ij.distance);
358 const double tempres = (cutoff == 0.) ?
359 0. : cutoff *
360 function_smoother(
361 -params[B],
362 params[mu],
363 r_ij.distance)
364 * function_prefactor(
365 params[beta],
366 zeta)
367 * (-1.) * temp / (1.+temp*zeta);
368 double factor = function_derivative_c(r_ij);
369 result += tempres*factor;
370 if (result != result)
371 ELOG(1, "result is NaN, zeta=" << zeta << ", temp=" << temp << ", cutoff=" << cutoff << ", tempres=" << tempres << ", factor=" << factor);
372 break;
373 }
374 case d:
375 {
376 const double zeta = function_zeta(r_ij);
377 const double temp =
378 pow(zeta, params[n]-1.) * pow(params[beta],params[n]);
379 const double cutoff = function_cutoff(r_ij.distance);
380 const double tempres = (cutoff == 0.) ?
381 0. : cutoff *
382 function_smoother(
383 -params[B],
384 params[mu],
385 r_ij.distance)
386 * function_prefactor(
387 params[beta],
388 zeta)
389 * (-1.) * temp / (1.+temp*zeta);
390 double factor = function_derivative_d(r_ij);
391 result += tempres*factor;
392 if (result != result)
393 ELOG(1, "result is NaN, zeta=" << zeta << ", temp=" << temp << ", cutoff=" << cutoff << ", tempres=" << tempres << ", factor=" << factor);
394 break;
395 }
396 case h:
397 {
398 const double zeta = function_zeta(r_ij);
399 const double temp =
400 pow(zeta, params[n]-1.) * pow(params[beta],params[n]);
401 const double cutoff = function_cutoff(r_ij.distance);
402 const double tempres = (cutoff == 0.) ?
403 0. : cutoff *
404 function_smoother(
405 -params[B],
406 params[mu],
407 r_ij.distance)
408 * function_prefactor(
409 params[beta],
410 zeta)
411 * (-1.) * temp / (1.+temp*zeta);
412 double factor = function_derivative_h(r_ij);
413 result += tempres*factor;
414 if (result != result)
415 ELOG(1, "result is NaN, zeta=" << zeta << ", temp=" << temp << ", cutoff=" << cutoff << ", tempres=" << tempres << ", factor=" << factor);
416 break;
417 }
418 case offset:
419 result += 1.;
420 break;
421 default:
422 break;
423 }
424 if (result != result)
425 ELOG(1, "result is NaN.");
426 }
427 return results_t(1,-result);
428}
429
430ManyBodyPotential_Tersoff::result_t
431ManyBodyPotential_Tersoff::function_derivative_c(
432 const argument_t &r_ij
433 ) const
434{
435 double result = 0.;
436 std::vector<arguments_t> triples = triplefunction(r_ij, S);
437 for (std::vector<arguments_t>::const_iterator iter = triples.begin();
438 iter != triples.end(); ++iter) {
439 ASSERT( iter->size() == 2,
440 "ManyBodyPotential_Tersoff::function_derivative_c() - the triples result must contain exactly two distances.");
441 const argument_t &r_ik = (*iter)[0];
442 const argument_t &r_jk = (*iter)[1];
443 const double tempangle = params[h] - function_theta(r_ij.distance, r_ik.distance, r_jk.distance);
444 const double cutoff = function_cutoff(r_ik.distance);
445 result += (cutoff == 0.) ?
446 0. : cutoff * omega * exp( Helpers::pow(lambda3 * (r_ij.distance - r_ik.distance) ,3)) * (
447 params[c]/Helpers::pow(params[d],2)
448 - params[c] / ( Helpers::pow(params[d],2) + Helpers::pow(tempangle,2) )
449 );
450 }
451 return result;
452}
453
454ManyBodyPotential_Tersoff::result_t
455ManyBodyPotential_Tersoff::function_derivative_d(
456 const argument_t &r_ij
457 ) const
458{
459 double result = 0.;
460 std::vector<arguments_t> triples = triplefunction(r_ij, S);
461 for (std::vector<arguments_t>::const_iterator iter = triples.begin();
462 iter != triples.end(); ++iter) {
463 ASSERT( iter->size() == 2,
464 "ManyBodyPotential_Tersoff::function_derivative_d() - the triples result must contain exactly two distances.");
465 const argument_t &r_ik = (*iter)[0];
466 const argument_t &r_jk = (*iter)[1];
467 const double tempangle = params[h] - function_theta(r_ij.distance, r_ik.distance, r_jk.distance);
468 const double cutoff = function_cutoff(r_ik.distance);
469 result += (cutoff == 0.) ?
470 0. : cutoff * omega * exp( Helpers::pow(lambda3 * (r_ij.distance - r_ik.distance) ,3)) * (
471 - Helpers::pow(params[c],2)/Helpers::pow(params[d],3)
472 + Helpers::pow(params[c],2) * params[d]
473 / Helpers::pow(Helpers::pow(params[d],2) + Helpers::pow(tempangle,2),2)
474 );
475 }
476 return result;
477}
478
479ManyBodyPotential_Tersoff::result_t
480ManyBodyPotential_Tersoff::function_derivative_h(
481 const argument_t &r_ij
482 ) const
483{
484 double result = 0.;
485 std::vector<arguments_t> triples = triplefunction(r_ij, S);
486 for (std::vector<arguments_t>::const_iterator iter = triples.begin();
487 iter != triples.end(); ++iter) {
488 ASSERT( iter->size() == 2,
489 "ManyBodyPotential_Tersoff::function_derivative_h() - the triples result must contain exactly two distances.");
490 const argument_t &r_ik = (*iter)[0];
491 const argument_t &r_jk = (*iter)[1];
492 const double tempangle = params[h] - function_theta(r_ij.distance, r_ik.distance, r_jk.distance);
493 const double cutoff = function_cutoff(r_ik.distance);
494 result += (cutoff == 0.) ?
495 0. : cutoff * omega * exp( Helpers::pow(lambda3 * (r_ij.distance - r_ik.distance) ,3)) * (
496 ( Helpers::pow(params[c],2)*tempangle )
497 / Helpers::pow(Helpers::pow(params[d],2) + Helpers::pow(tempangle,2),2)
498 );
499 }
500 return result;
501}
502
503ManyBodyPotential_Tersoff::result_t
504ManyBodyPotential_Tersoff::function_cutoff(
505 const double &distance
506 ) const
507{
508// Info info(__func__);
509 double result = 0.;
510 if (distance < R)
511 result = 1.;
512 else if (distance > S)
513 result = 0.;
514 else {
515 result = (0.5 + 0.5 * cos( M_PI * (distance - R)/(S-R)));
516 }
517// LOG(2, "DEBUG: function_cutoff(" << distance << ") = " << result);
518 return result;
519}
520
521ManyBodyPotential_Tersoff::result_t
522ManyBodyPotential_Tersoff::function_prefactor(
523 const double &alpha,
524 const double &eta
525 ) const
526{
527// Info info(__func__);
528 const double result = chi * pow(
529 (1. + pow(alpha * eta, params[n])),
530 -1./(2.*params[n]));
531// LOG(2, "DEBUG: function_prefactor(" << alpha << "," << eta << ") = " << result);
532 return result;
533}
534
535ManyBodyPotential_Tersoff::result_t
536ManyBodyPotential_Tersoff::function_smoother(
537 const double &prefactor,
538 const double &lambda,
539 const double &distance
540 ) const
541{
542// Info info(__func__);
543 const double result = prefactor * exp(-lambda * distance);
544// LOG(2, "DEBUG: function_smoother(" << prefactor << "," << lambda << "," << distance << ") = " << result);
545 return result;
546}
547
548ManyBodyPotential_Tersoff::result_t
549ManyBodyPotential_Tersoff::function_eta(
550 const argument_t &r_ij
551 ) const
552{
553// Info info(__func__);
554 result_t result = 0.;
555
556 // get all triples within the cutoff
557 std::vector<arguments_t> triples = triplefunction(r_ij, S);
558 for (std::vector<arguments_t>::const_iterator iter = triples.begin();
559 iter != triples.end(); ++iter) {
560 ASSERT( iter->size() == 2,
561 "ManyBodyPotential_Tersoff::function_zeta() - the triples result must contain of exactly two distances.");
562 const argument_t &r_ik = (*iter)[0];
563 result += function_cutoff(r_ik.distance)
564 * exp( Helpers::pow(lambda3 * (r_ij.distance - r_ik.distance) ,3));
565 }
566
567// LOG(2, "DEBUG: function_eta(" << r_ij.distance << ") = " << result);
568 return result;
569}
570
571ManyBodyPotential_Tersoff::result_t
572ManyBodyPotential_Tersoff::function_zeta(
573 const argument_t &r_ij
574 ) const
575{
576// Info info(__func__);
577 result_t result = 0.;
578
579 // get all triples within the cutoff
580 std::vector<arguments_t> triples = triplefunction(r_ij, S);
581 for (std::vector<arguments_t>::const_iterator iter = triples.begin();
582 iter != triples.end(); ++iter) {
583 ASSERT( iter->size() == 2,
584 "ManyBodyPotential_Tersoff::function_zeta() - the triples result must contain exactly two distances.");
585 const argument_t &r_ik = (*iter)[0];
586 const argument_t &r_jk = (*iter)[1];
587 result +=
588 function_cutoff(r_ik.distance)
589 * omega
590 * function_angle(r_ij.distance, r_ik.distance, r_jk.distance)
591 * exp( Helpers::pow(lambda3 * (r_ij.distance - r_ik.distance) ,3));
592 }
593
594// LOG(2, "DEBUG: function_zeta(" << r_ij.distance << ") = " << result);
595 return result;
596}
597
598ManyBodyPotential_Tersoff::result_t
599ManyBodyPotential_Tersoff::function_theta(
600 const double &r_ij,
601 const double &r_ik,
602 const double &r_jk
603 ) const
604{
605 const double angle = Helpers::pow(r_ij,2) + Helpers::pow(r_ik,2) - Helpers::pow(r_jk,2);
606 const double divisor = 2.* r_ij * r_ik;
607 if (divisor != 0.) {
608 LOG(2, "DEBUG: cos(theta)= " << angle/divisor);
609 return angle/divisor;
610 } else
611 return 0.;
612}
613
614ManyBodyPotential_Tersoff::result_t
615ManyBodyPotential_Tersoff::function_angle(
616 const double &r_ij,
617 const double &r_ik,
618 const double &r_jk
619 ) const
620{
621// Info info(__func__);
622 const double result =
623 1.
624 + (Helpers::pow(params[c]/params[d], 2))
625 - Helpers::pow(params[c], 2)/(Helpers::pow(params[d], 2) +
626 Helpers::pow(params[h] - function_theta(r_ij, r_ik, r_jk),2));
627
628// LOG(2, "DEBUG: function_angle(" << r_ij << "," << r_ik << "," << r_jk << ") = " << result);
629 return result;
630}
631
Note: See TracBrowser for help on using the repository browser.