/* * 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] // ) // ); }