Index: src/Potentials/Specifics/FourBodyPotential_Torsion.cpp
===================================================================
--- src/Potentials/Specifics/FourBodyPotential_Torsion.cpp	(revision e2037e5d443e6ac456d3cbf14b2e4127a4bbd7a6)
+++ src/Potentials/Specifics/FourBodyPotential_Torsion.cpp	(revision e2037e5d443e6ac456d3cbf14b2e4127a4bbd7a6)
@@ -0,0 +1,256 @@
+/*
+ * Project: MoleCuilder
+ * Description: creates and alters molecular systems
+ * Copyright (C)  2013 Frederik Heber. All rights reserved.
+ * Please see the COPYING file or "Copyright notice" in builder.cpp for details.
+ * 
+ *
+ *   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 <http://www.gnu.org/licenses/>. 
+ */
+
+/*
+ * FourBodyPotential_Torsion.cpp
+ *
+ *  Created on: Jul 08, 2013
+ *      Author: heber
+ */
+
+
+// include config.h
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "CodePatterns/MemDebug.hpp"
+
+#include "FourBodyPotential_Torsion.hpp"
+
+#include <boost/assign/list_of.hpp> // for 'map_list_of()'
+#include <boost/bind.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <string>
+
+#include "CodePatterns/Assert.hpp"
+
+#include "FunctionApproximation/Extractors.hpp"
+#include "FunctionApproximation/TrainingData.hpp"
+#include "Potentials/helpers.hpp"
+#include "Potentials/ParticleTypeCheckers.hpp"
+
+class Fragment;
+
+// static definitions
+const FourBodyPotential_Torsion::ParameterNames_t
+FourBodyPotential_Torsion::ParameterNames =
+      boost::assign::list_of<std::string>
+      ("spring_constant")
+      ("equilibrium_distance")
+    ;
+const std::string FourBodyPotential_Torsion::potential_token("torsion");
+
+FourBodyPotential_Torsion::FourBodyPotential_Torsion() :
+  EmpiricalPotential(),
+  params(parameters_t(MAXPARAMS, 0.))
+{
+  // have some decent defaults for parameter_derivative checking
+  params[spring_constant] = 1.;
+  params[equilibrium_distance] = 0.1;
+}
+
+FourBodyPotential_Torsion::FourBodyPotential_Torsion(
+    const ParticleTypes_t &_ParticleTypes
+    ) :
+  EmpiricalPotential(_ParticleTypes),
+  params(parameters_t(MAXPARAMS, 0.))
+{
+  // have some decent defaults for parameter_derivative checking
+  params[spring_constant] = 1.;
+  params[equilibrium_distance] = 0.1;
+}
+
+FourBodyPotential_Torsion::FourBodyPotential_Torsion(
+    const ParticleTypes_t &_ParticleTypes,
+    const double _spring_constant,
+    const double _equilibrium_distance) :
+  EmpiricalPotential(_ParticleTypes),
+  params(parameters_t(MAXPARAMS, 0.))
+{
+  params[spring_constant] = _spring_constant;
+  params[equilibrium_distance] = _equilibrium_distance;
+}
+
+void FourBodyPotential_Torsion::setParameters(const parameters_t &_params)
+{
+  const size_t paramsDim = _params.size();
+  ASSERT( paramsDim <= getParameterDimension(),
+      "FourBodyPotential_Torsion::setParameters() - we need not more than "
+      +toString(getParameterDimension())+" parameters.");
+  for(size_t i=0;i<paramsDim;++i)
+    params[i] = _params[i];
+
+#ifndef NDEBUG
+  parameters_t check_params(getParameters());
+  check_params.resize(paramsDim); // truncate to same size
+  ASSERT( check_params == _params,
+      "FourBodyPotential_Torsion::setParameters() - failed, mismatch in to be set "
+      +toString(_params)+" and set "+toString(check_params)+" params.");
+#endif
+}
+
+FourBodyPotential_Torsion::result_t
+FourBodyPotential_Torsion::function_theta(
+    const double &r_ij,
+    const double &r_ik,
+    const double &r_il,
+    const double &r_jk,
+    const double &r_jl,
+    const double &r_kl
+  ) const
+{
+//  Info info(__func__);
+  const double h_1 = .5*sqrt(2.*(Helpers::pow(r_ij,2)+Helpers::pow(r_ik,2))-Helpers::pow(r_jk,2));
+  const double h_2 = .5*sqrt(2.*(Helpers::pow(r_jl,2)+Helpers::pow(r_kl,2))-Helpers::pow(r_jk,2));
+  const double angle = Helpers::pow(h_1,2) + Helpers::pow(h_2,2) - Helpers::pow(r_il,2);
+  const double divisor = 2.* h_1 * h_2;
+
+//  LOG(2, "DEBUG: cos(theta)= " << angle/divisor);
+  if (divisor == 0.)
+    return 0.;
+  else
+    return angle/divisor;
+}
+
+FourBodyPotential_Torsion::results_t
+FourBodyPotential_Torsion::operator()(
+    const arguments_t &arguments
+    ) const
+{
+  ASSERT( arguments.size() == getSpecificArgumentCount(),
+      "FourBodyPotential_Torsion::operator() - requires exactly three arguments.");
+  ASSERT( ParticleTypeChecker::checkArgumentsAgainstParticleTypes(
+      arguments, getParticleTypes()),
+      "FourBodyPotential_Torsion::operator() - types don't match with ones in arguments.");
+  const argument_t &r_ij = arguments[0]; // 01
+  const argument_t &r_ik = arguments[1]; // 02
+  const argument_t &r_il = arguments[2]; // 03
+  const argument_t &r_jk = arguments[3]; // 12
+  const argument_t &r_jl = arguments[4]; // 13
+  const argument_t &r_kl = arguments[5]; // 23
+  const result_t result =
+      params[spring_constant]
+             * Helpers::pow( function_theta(r_ij.distance, r_ik.distance, r_il.distance, r_jk.distance, r_jl.distance, r_kl.distance) - params[equilibrium_distance], 2 );
+  return std::vector<result_t>(1, result);
+}
+
+FourBodyPotential_Torsion::derivative_components_t
+FourBodyPotential_Torsion::derivative(
+    const arguments_t &arguments
+    ) const
+{
+  ASSERT( arguments.size() == getSpecificArgumentCount(),
+      "FourBodyPotential_Torsion::operator() - requires exactly three arguments.");
+  ASSERT( ParticleTypeChecker::checkArgumentsAgainstParticleTypes(
+      arguments, getParticleTypes()),
+      "FourBodyPotential_Torsion::operator() - types don't match with ones in arguments.");
+  derivative_components_t result;
+  const argument_t &r_ij = arguments[0]; // 01
+  const argument_t &r_ik = arguments[1]; // 02
+  const argument_t &r_il = arguments[2]; // 03
+  const argument_t &r_jk = arguments[3]; // 12
+  const argument_t &r_jl = arguments[4]; // 13
+  const argument_t &r_kl = arguments[5]; // 23
+  result.push_back( 2. * params[spring_constant] * ( function_theta(r_ij.distance, r_ik.distance, r_il.distance, r_jk.distance, r_jl.distance, r_kl.distance) - params[equilibrium_distance]) );
+  ASSERT( result.size() == 1,
+      "FourBodyPotential_Torsion::operator() - we did not create exactly one component.");
+  return result;
+}
+
+FourBodyPotential_Torsion::results_t
+FourBodyPotential_Torsion::parameter_derivative(
+    const arguments_t &arguments,
+    const size_t index
+    ) const
+{
+  ASSERT( arguments.size() == getSpecificArgumentCount(),
+      "FourBodyPotential_Torsion::parameter_derivative() - requires exactly three arguments.");
+  ASSERT( ParticleTypeChecker::checkArgumentsAgainstParticleTypes(
+      arguments, getParticleTypes()),
+      "FourBodyPotential_Torsion::operator() - types don't match with ones in arguments.");
+  const argument_t &r_ij = arguments[0]; // 01
+  const argument_t &r_ik = arguments[1]; // 02
+  const argument_t &r_il = arguments[2]; // 03
+  const argument_t &r_jk = arguments[3]; // 12
+  const argument_t &r_jl = arguments[4]; // 13
+  const argument_t &r_kl = arguments[5]; // 23
+  switch (index) {
+    case spring_constant:
+    {
+      const result_t result =
+                 Helpers::pow( function_theta(r_ij.distance, r_ik.distance, r_il.distance, r_jk.distance, r_jl.distance, r_kl.distance) - params[equilibrium_distance], 2 );
+      return std::vector<result_t>(1, result);
+      break;
+    }
+    case equilibrium_distance:
+    {
+      const result_t result =
+          -2. * params[spring_constant]
+                 * ( function_theta(r_ij.distance, r_ik.distance, r_il.distance, r_jk.distance, r_jl.distance, r_kl.distance) - params[equilibrium_distance]);
+      return std::vector<result_t>(1, result);
+      break;
+    }
+    default:
+      ASSERT(0, "FourBodyPotential_Torsion::parameter_derivative() - derivative to unknown parameter desired.");
+      break;
+  }
+}
+
+FunctionModel::extractor_t
+FourBodyPotential_Torsion::getSpecificExtractor() const
+{
+  Fragment::charges_t charges;
+  charges.resize(getParticleTypes().size());
+  std::transform(getParticleTypes().begin(), getParticleTypes().end(),
+      charges.begin(), boost::lambda::_1);
+  FunctionModel::extractor_t returnfunction =
+      boost::bind(&Extractors::gatherDistancesFromFragment,
+          boost::bind(&Fragment::getPositions, _1),
+          boost::bind(&Fragment::getCharges, _1),
+          charges,
+          _2);
+  return returnfunction;
+}
+
+FunctionModel::filter_t
+FourBodyPotential_Torsion::getSpecificFilter() const
+{
+  FunctionModel::filter_t returnfunction =
+      boost::bind(&Extractors::reorderArgumentsByParticleTypes,
+        boost::bind(&Extractors::filterArgumentsByParticleTypes,
+            _1,
+            getParticleTypes()),
+        getParticleTypes()
+      );
+  return returnfunction;
+}
+
+void
+FourBodyPotential_Torsion::setParametersToRandomInitialValues(
+    const TrainingData &data)
+{
+  params[FourBodyPotential_Torsion::spring_constant] = 2.*rand()/(double)RAND_MAX;
+  params[FourBodyPotential_Torsion::equilibrium_distance] = -.5+1.*rand()/(double)RAND_MAX;
+}
+
