/*
* Project: MoleCuilder
* Description: creates and alters molecular systems
* Copyright (C) 2012 University of Bonn. All rights reserved.
*
*
* This file is part of MoleCuilder.
*
* MoleCuilder is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* MoleCuilder is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MoleCuilder. If not, see .
*/
/*
* ManyBodyPotential_TersoffUnitTest.cpp
*
* Created on: Oct 04, 2012
* Author: heber
*/
// include config.h
#ifdef HAVE_CONFIG_H
#include
#endif
using namespace std;
#include
#include
#include
#include "ManyBodyPotential_TersoffUnitTest.hpp"
#include
#include
#include
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/Log.hpp"
#include "FunctionApproximation/FunctionArgument.hpp"
#include "Potentials/Specifics/ManyBodyPotential_Tersoff.hpp"
#include "Potentials/helpers.hpp"
using namespace boost::assign;
#ifdef HAVE_TESTRUNNER
#include "UnitTestMain.hpp"
#endif /*HAVE_TESTRUNNER*/
/********************************************** Test classes **************************************/
// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( ManyBodyPotential_TersoffTest );
ManyBodyPotential_TersoffTest::configurations_t ManyBodyPotential_TersoffTest::configurations;
/** This function looks up all distances ik and jk to a given ij and
* returns a vector of pairs.
*/
std::vector
triplefunction(const argument_t &arguments, const double cutoff)
{
const ManyBodyPotential_TersoffTest::configuration_t &CurrentConfiguration =
ManyBodyPotential_TersoffTest::configurations[arguments.globalid];
std::vector result;
// go through current configuration and gather all other distances
ManyBodyPotential_TersoffTest::configuration_t::const_iterator firstiter =
CurrentConfiguration.begin();
std::advance(firstiter, arguments.indices.first);
ManyBodyPotential_TersoffTest::configuration_t::const_iterator seconditer =
CurrentConfiguration.begin();
std::advance(seconditer, arguments.indices.second);
for (ManyBodyPotential_TersoffTest::configuration_t::const_iterator iter =
CurrentConfiguration.begin();
iter != CurrentConfiguration.end();
++iter) {
// skip k==i and k==j
if ((iter == firstiter) || (iter == seconditer))
continue;
FunctionModel::arguments_t args(2);
// ik
args[0].distance = firstiter->distance(*iter);
args[0].indices = std::make_pair(
std::distance(CurrentConfiguration.begin(), firstiter),
std::distance(CurrentConfiguration.begin(), iter)
);
args[0].globalid = arguments.globalid;
// jk
args[1].distance = seconditer->distance(*iter);
args[1].indices = std::make_pair(
std::distance(CurrentConfiguration.begin(), seconditer),
std::distance(CurrentConfiguration.begin(), iter)
);
args[1].globalid = arguments.globalid;
result.push_back(args);
}
return result;
}
void ManyBodyPotential_TersoffTest::setUp()
{
// failing asserts should be thrown
ASSERT_DO(Assert::Throw);
setVerbosity(10);
// we use parameters from tremolo/defaults/tersoff/tersoff.potentials
// [Tersoff, '89]
params.resize(ManyBodyPotential_Tersoff::MAXPARAMS,0.);
// params[ManyBodyPotential_Tersoff::R] = 1.800000e+00;
// params[ManyBodyPotential_Tersoff::S] = 2.100000e+00;
params[ManyBodyPotential_Tersoff::A] = 1.393600e+03;
params[ManyBodyPotential_Tersoff::B] = 3.467000e+02;
params[ManyBodyPotential_Tersoff::lambda] = 3.487900e+00;
params[ManyBodyPotential_Tersoff::mu] = 2.211900e+00;
// params[ManyBodyPotential_Tersoff::lambda3] = 0.;
// params[ManyBodyPotential_Tersoff::alpha] = 0.;
params[ManyBodyPotential_Tersoff::beta] = 1.572400e-07;
// params[ManyBodyPotential_Tersoff::chi] = 1.;
// params[ManyBodyPotential_Tersoff::omega] = 1.;
params[ManyBodyPotential_Tersoff::n] = 7.275100e-01;
params[ManyBodyPotential_Tersoff::c] = 3.804900e+04;
params[ManyBodyPotential_Tersoff::d] = 4.384000e+00;
params[ManyBodyPotential_Tersoff::h] = -5.705800e-01;
// initial configuration as in tremolo/default/tersoff/tersoff.data with
// Si renamed to C.
// create test configurations of 5 C atoms, constructed via:
// for file in tersoff.vis.00?0.xyz; do
// echo -e "\t{\n\t\tconfiguration_t positions;\n\t\tpositions +="
// tail -n 5 $file | awk -F " " {'print "\t\t\t\tVector("$2","$3","$4")"(NR!=5 ? "," : ";")'}
// echo -e -n "\t}\n"
// done
{
configuration_t positions;
positions +=
Vector(1.000000e+01,1.100000e+01,1.100000e+01),
Vector(1.120000e+01,1.000000e+01,1.000000e+01),
Vector(8.800000e+00,1.000000e+01,1.000000e+01),
Vector(1.000000e+01,1.200000e+01,1.000000e+01),
Vector(1.000000e+01,1.100000e+01,1.240000e+01);
configurations.push_back(positions);
}
{
configuration_t positions;
positions +=
Vector(1.000000e+01,1.099315e+01,1.099482e+01),
Vector(1.119779e+01,1.000179e+01,1.000235e+01),
Vector(8.802208e+00,1.000179e+01,1.000235e+01),
Vector(1.000000e+01,1.200262e+01,9.999421e+00),
Vector(1.000000e+01,1.100066e+01,1.240107e+01);
configurations.push_back(positions);
}
{
configuration_t positions;
positions +=
Vector(1.000000e+01,1.097354e+01,1.098018e+01),
Vector(1.119164e+01,1.000675e+01,1.000902e+01),
Vector(8.808358e+00,1.000675e+01,1.000902e+01),
Vector(1.000000e+01,1.201036e+01,9.997816e+00),
Vector(1.000000e+01,1.100260e+01,1.240397e+01);
configurations.push_back(positions);
}
{
configuration_t positions;
positions +=
Vector(1.000000e+01,1.094419e+01,1.095884e+01),
Vector(1.118308e+01,1.001364e+01,1.001884e+01),
Vector(8.816924e+00,1.001364e+01,1.001884e+01),
Vector(1.000000e+01,1.202283e+01,9.995566e+00),
Vector(1.000000e+01,1.100570e+01,1.240790e+01);
configurations.push_back(positions);
}
{
configuration_t positions;
positions +=
Vector(1.000000e+01,1.090791e+01,1.093293e+01),
Vector(1.117318e+01,1.002158e+01,1.003102e+01),
Vector(8.826818e+00,1.002158e+01,1.003102e+01),
Vector(1.000000e+01,1.203924e+01,9.993210e+00),
Vector(1.000000e+01,1.100969e+01,1.241182e+01);
configurations.push_back(positions);
}
{
configuration_t positions;
positions +=
Vector(1.000000e+01,1.086664e+01,1.090321e+01),
Vector(1.116216e+01,1.003043e+01,1.004546e+01),
Vector(8.837839e+00,1.003043e+01,1.004546e+01),
Vector(1.000000e+01,1.205848e+01,9.991167e+00),
Vector(1.000000e+01,1.101403e+01,1.241470e+01);
configurations.push_back(positions);
}
{
configuration_t positions;
positions +=
Vector(1.000000e+01,1.082297e+01,1.087033e+01),
Vector(1.115036e+01,1.003997e+01,1.006213e+01),
Vector(8.849644e+00,1.003997e+01,1.006213e+01),
Vector(1.000000e+01,1.207923e+01,9.989652e+00),
Vector(1.000000e+01,1.101786e+01,1.241577e+01);
configurations.push_back(positions);
}
{
configuration_t positions;
positions +=
Vector(1.000000e+01,1.077905e+01,1.083482e+01),
Vector(1.113831e+01,1.004988e+01,1.008085e+01),
Vector(8.861694e+00,1.004988e+01,1.008085e+01),
Vector(1.000000e+01,1.210048e+01,9.989022e+00),
Vector(1.000000e+01,1.102071e+01,1.241446e+01);
configurations.push_back(positions);
}
{
configuration_t positions;
positions +=
Vector(1.000000e+01,1.073683e+01,1.079745e+01),
Vector(1.112678e+01,1.005973e+01,1.010129e+01),
Vector(8.873218e+00,1.005973e+01,1.010129e+01),
Vector(1.000000e+01,1.212139e+01,9.989594e+00),
Vector(1.000000e+01,1.102232e+01,1.241038e+01);
configurations.push_back(positions);
}
{
configuration_t positions;
positions +=
Vector(1.000000e+01,1.069834e+01,1.075920e+01),
Vector(1.111685e+01,1.006891e+01,1.012296e+01),
Vector(8.883151e+00,1.006891e+01,1.012296e+01),
Vector(1.000000e+01,1.214131e+01,9.991602e+00),
Vector(1.000000e+01,1.102252e+01,1.240327e+01);
configurations.push_back(positions);
}
// cut from tersoff.etot via:
// for i in `seq 0 1 9`; do
// grep $i.000000e-01 tersoff.etot | awk -F" " {'print "\t\t\t\t"$2","'}
// done
// (though timestep 0 is missing and is added manually)
output +=
-1.333927e+01,
-1.359628e+01,
-1.420701e+01,
-1.479974e+01,
-1.537942e+01,
-1.584603e+01,
-1.615832e+01,
-1.630598e+01,
-1.626654e+01,
-1.603360e+01;
CPPUNIT_ASSERT_EQUAL( output.size(), configurations.size() );
}
void ManyBodyPotential_TersoffTest::tearDown()
{
configurations.clear();
}
/** UnitTest for operator()
*/
void ManyBodyPotential_TersoffTest::operatorTest()
{
boost::function<
std::vector(const argument_t &, const double)
> fct =
triplefunction;
ManyBodyPotential_Tersoff::ParticleTypes_t types =
boost::assign::list_of
(0)(1)
;
ManyBodyPotential_Tersoff tersoff(types);
tersoff.setTriplefunction(fct);
tersoff.setParameters(params);
const_cast(tersoff.R) = 1.8;
const_cast(tersoff.S) = 2.1;
for (size_t index = 0; index < configurations.size(); ++index) {
const configuration_t &CurrentConfiguration = configurations[index];
double temp = 0.;
for (size_t i=0; i < CurrentConfiguration.size(); ++i)
for (size_t j=0; j < CurrentConfiguration.size(); ++j) {
if (i == j)
continue;
argument_t arg;
arg.indices = std::make_pair(i,j);
arg.types = std::make_pair(0,1);
arg.distance = CurrentConfiguration[i].distance(CurrentConfiguration[j]);
arg.globalid = index; // this is needed for the triplefunction to the configuration
FunctionModel::arguments_t args(1,arg);
const ManyBodyPotential_Tersoff::results_t res = tersoff(args);
temp += res[0];
}
// this little precision is because tremolo does seem to handle coordinates
// a little differently than we do, the precise difference in the x coordinate
// of the first and second position for the second configuration is easy to
// see as 1.119779. However, tremolo obtains 1.1197792 for unknown reasons.
// Maybe, there is some float floating around in the code ... see strtod() bugs
// LOG(2, "Comparing " << output[index] << " and " << .5*temp);
CPPUNIT_ASSERT(
Helpers::isEqual(
output[index],
.5*temp,
1.e-4/std::numeric_limits::epsilon()
)
);
}
}
/** UnitTest for derivative()
*/
void ManyBodyPotential_TersoffTest::derivativeTest()
{
// boost::function<
// std::vector(const argument_t &, const double)
// > fct =
// triplefunction;
// ManyBodyPotential_Tersoff::ParticleTypes_t types =
// boost::assign::list_of
// (0)(1)
// ;
// ManyBodyPotential_Tersoff tersoff(types, fct);
// tersoff.setParameters(params);
// CPPUNIT_ASSERT(
// Helpers::isEqual(
// 0.,
// tersoff.derivative(
// FunctionModel::arguments_t(1,argument_t(1.))
// )[0]
// )
// );
}
/** UnitTest for parameter_derivative()
*/
void ManyBodyPotential_TersoffTest::parameter_derivativeTest()
{
// boost::function<
// std::vector(const argument_t &, const double)
// > fct =
// triplefunction;
// ManyBodyPotential_Tersoff::ParticleTypes_t types =
// boost::assign::list_of
// (0)(1)
// ;
// ManyBodyPotential_Tersoff tersoff(types, fct);
// tersoff.setParameters(params);
// CPPUNIT_ASSERT(
// Helpers::isEqual(
// 0.,
// tersoff.parameter_derivative(
// FunctionModel::arguments_t(1,argument_t(1.)),
// 0
// )[0]
// )
// );
// CPPUNIT_ASSERT(
// Helpers::isEqual(
// 0.,
// tersoff.parameter_derivative(
// FunctionModel::arguments_t(1,argument_t(1.)),
// 1
// )[0]
// )
// );
// CPPUNIT_ASSERT(
// Helpers::isEqual(
// 1.,
// tersoff.parameter_derivative(
// FunctionModel::arguments_t(1,argument_t(1.)),
// 2
// )[0]
// )
// );
}