Index: src/LevMartester.cpp
===================================================================
--- src/LevMartester.cpp	(revision e920d3d78bfcf50bfef7c62b3496caceec76e6e1)
+++ src/LevMartester.cpp	(revision b17e0f1720ab9dbd5bf476331ca6348b89a84adb)
@@ -75,38 +75,4 @@
 
 using namespace boost::assign;
-
-HomologyGraph getFirstGraphWithThreeCarbons(const HomologyContainer &homologies)
-{
-  FragmentNode SaturatedCarbon(6,4); // carbon has atomic number 6 and should have 4 bonds for C3H8
-  FragmentNode DanglingCarbon(6,3); // carbon has atomic number 6 and should have 3 pure bonds for C3H8
-  for (HomologyContainer::container_t::const_iterator iter =
-      homologies.begin(); iter != homologies.end(); ++iter) {
-    if ((iter->first.hasNode(SaturatedCarbon,2)) && (iter->first.hasNode(DanglingCarbon,1)))
-      return iter->first;
-  }
-  return HomologyGraph();
-}
-
-HomologyGraph getFirstGraphWithTwoCarbons(const HomologyContainer &homologies)
-{
-  FragmentNode SaturatedCarbon(6,3); // carbon has atomic number 6 and should have 4 bonds for C2H6
-  for (HomologyContainer::container_t::const_iterator iter =
-      homologies.begin(); iter != homologies.end(); ++iter) {
-    if (iter->first.hasNode(SaturatedCarbon,2))
-      return iter->first;
-  }
-  return HomologyGraph();
-}
-
-HomologyGraph getFirstGraphWithOneCarbon(const HomologyContainer &homologies)
-{
-  FragmentNode SaturatedCarbon(6,2); // carbon has atomic number 6 and has 3 bonds (to other Hs)
-  for (HomologyContainer::container_t::const_iterator iter =
-      homologies.begin(); iter != homologies.end(); ++iter) {
-    if (iter->first.hasNode(SaturatedCarbon,1))
-      return iter->first;
-  }
-  return HomologyGraph();
-}
 
 HomologyGraph getFirstGraphwithTimesSpecificElement(
@@ -247,39 +213,42 @@
   {
     // then we ought to pick the right HomologyGraph ...
-    const HomologyGraph graph = getFirstGraphWithThreeCarbons(homologies);
-    LOG(1, "First representative graph containing three saturated carbons is " << graph << ".");
-
-    // Afterwards we go through all of this type and gather the distance and the energy value
-    TrainingData AngleData(
-        boost::bind(&Extractors::reorderArgumentsByIncreasingDistance,
-            boost::bind(&Extractors::gatherAllSymmetricDistanceArguments,
-                boost::bind(&Extractors::gatherPositionOfTuples,
-                    _1, Fragment::charges_t(3,6.)
-                ), _2 // gather carbon triples
+    const HomologyGraph graph = getFirstGraphwithTimesSpecificElement(homologies,6,3);
+    if (graph != HomologyGraph()) {
+      LOG(1, "First representative graph containing three saturated carbons is " << graph << ".");
+
+      // Afterwards we go through all of this type and gather the distance and the energy value
+      TrainingData AngleData(
+          boost::bind(&Extractors::reorderArgumentsByIncreasingDistance,
+              boost::bind(&Extractors::gatherAllSymmetricDistanceArguments,
+                  boost::bind(&Extractors::gatherPositionOfTuples,
+                      _1, Fragment::charges_t(3,6.)
+                  ), _2 // gather carbon triples
+              )
             )
-          )
-        );
-    AngleData(homologies.getHomologousGraphs(graph));
-    LOG(1, "INFO: I gathered the following training data:\n" <<
-        _detail::writeDistanceEnergyTable(AngleData.getDistanceEnergyTable()));
-    // NOTICE that distance are in bohrradi as they come from MPQC!
-
-    // now perform the function approximation by optimizing the model function
-    FunctionModel::parameters_t params(PairPotential_Angle::MAXPARAMS, 0.);
-    params[PairPotential_Angle::energy_offset] =  -1.;
-    params[PairPotential_Angle::spring_constant] =  1.;
-    params[PairPotential_Angle::equilibrium_distance] =  0.2;
-    PairPotential_Angle angle;
-    LOG(0, "INFO: Initial parameters are " << params << ".");
-    angle.setParameters(params);
-    FunctionModel &model = angle;
-    FunctionApproximation approximator(AngleData, model);
-    if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
-      approximator(FunctionApproximation::ParameterDerivative);
-    else
-      ELOG(0, "We require parameter derivatives for a box constraint minimization.");
-    params = model.getParameters();
-
-    LOG(0, "RESULT: Best parameters are " << params << ".");
+          );
+      AngleData(homologies.getHomologousGraphs(graph));
+      LOG(1, "INFO: I gathered the following training data: " << AngleData);
+      // NOTICE that distance are in bohrradi as they come from MPQC!
+
+      // now perform the function approximation by optimizing the model function
+      FunctionModel::parameters_t params(PairPotential_Angle::MAXPARAMS, 0.);
+      params[PairPotential_Angle::energy_offset] =  -1.;
+      params[PairPotential_Angle::spring_constant] =  1.;
+      params[PairPotential_Angle::equilibrium_distance] =  0.2;
+      PairPotential_Angle angle;
+      LOG(0, "INFO: Initial parameters are " << params << ".");
+      angle.setParameters(params);
+      FunctionModel &model = angle;
+      FunctionApproximation approximator(AngleData, model);
+      if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
+        approximator(FunctionApproximation::ParameterDerivative);
+      else {
+        ELOG(0, "We require parameter derivatives for a box constraint minimization.");
+        return 1;
+      }
+      params = model.getParameters();
+
+      LOG(0, "RESULT: Best parameters are " << params << ".");
+    }
   }
 
@@ -287,37 +256,41 @@
   {
     // then we ought to pick the right HomologyGraph ...
-    const HomologyGraph graph = getFirstGraphWithTwoCarbons(homologies);
-    LOG(1, "First representative graph containing two saturated carbons is " << graph << ".");
-
-    // Afterwards we go through all of this type and gather the distance and the energy value
-    TrainingData MorseData(
-        boost::bind(&Extractors::gatherAllSymmetricDistanceArguments,
-            boost::bind(&Extractors::gatherPositionOfTuples,
-                _1, Fragment::charges_t(2,6.)
-            ), _2 // gather first carbon pair
-          )
-        );
-    MorseData(homologies.getHomologousGraphs(graph));
-    LOG(1, "INFO: I gathered the following training data:\n" <<
-        _detail::writeDistanceEnergyTable(MorseData.getDistanceEnergyTable()));
-    // NOTICE that distance are in bohrradi as they come from MPQC!
-
-    // now perform the function approximation by optimizing the model function
-    FunctionModel::parameters_t params(PairPotential_Morse::MAXPARAMS, 0.);
-    params[PairPotential_Morse::dissociation_energy] =  0.5;
-    params[PairPotential_Morse::energy_offset] =  -1.;
-    params[PairPotential_Morse::spring_constant] =  1.;
-    params[PairPotential_Morse::equilibrium_distance] =  2.9;
-    PairPotential_Morse morse;
-    morse.setParameters(params);
-    FunctionModel &model = morse;
-    FunctionApproximation approximator(MorseData, model); // we only give CC distance, hence 1 input dim
-    if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
-      approximator(FunctionApproximation::ParameterDerivative);
-    else
-      ELOG(0, "We require parameter derivatives for a box constraint minimization.");
-    params = model.getParameters();
-
-    LOG(0, "RESULT: Best parameters are " << params << ".");
+    const HomologyGraph graph = getFirstGraphwithTimesSpecificElement(homologies,6,2);
+    if (graph != HomologyGraph()) {
+      LOG(1, "First representative graph containing two saturated carbons is " << graph << ".");
+
+      // Afterwards we go through all of this type and gather the distance and the energy value
+      TrainingData MorseData(
+          boost::bind(&Extractors::gatherAllSymmetricDistanceArguments,
+              boost::bind(&Extractors::gatherPositionOfTuples,
+                  _1, Fragment::charges_t(2,6.)
+              ), _2 // gather first carbon pair
+            )
+          );
+      MorseData(homologies.getHomologousGraphs(graph));
+      LOG(1, "INFO: I gathered the following training data: " << MorseData);
+      // NOTICE that distance are in bohrradi as they come from MPQC!
+
+      // now perform the function approximation by optimizing the model function
+      FunctionModel::parameters_t params(PairPotential_Morse::MAXPARAMS, 0.);
+      params[PairPotential_Morse::dissociation_energy] =  0.5;
+      params[PairPotential_Morse::energy_offset] =  -1.;
+      params[PairPotential_Morse::spring_constant] =  1.;
+      params[PairPotential_Morse::equilibrium_distance] =  2.9;
+      PairPotential_Morse morse;
+      LOG(0, "INFO: Initial parameters are " << params << ".");
+      morse.setParameters(params);
+      FunctionModel &model = morse;
+      FunctionApproximation approximator(MorseData, model); // we only give CC distance, hence 1 input dim
+      if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
+        approximator(FunctionApproximation::ParameterDerivative);
+      else {
+        ELOG(0, "We require parameter derivatives for a box constraint minimization.");
+        return 1;
+      }
+      params = model.getParameters();
+
+      LOG(0, "RESULT: Best parameters are " << params << ".");
+    }
   }
 
@@ -326,54 +299,71 @@
   {
     // then we ought to pick the right HomologyGraph ...
-    const HomologyGraph graph = getFirstGraphWithOneCarbon(homologies);
-    LOG(1, "First representative graph containing one saturated carbon is " << graph << ".");
-
-    // Afterwards we go through all of this type and gather the distance and the energy value
-    TrainingData TersoffData(
-        TrainingData::extractor_t(&Extractors::gatherAllDistances) // gather first carbon pair
-        );
-    TersoffData( homologies.getHomologousGraphs(graph) );
-    LOG(1, "INFO: I gathered the following training data:\n" <<
-        _detail::writeDistanceEnergyTable(TersoffData.getDistanceEnergyTable()));
-    // NOTICE that distance are in bohrradi as they come from MPQC!
-
-    // now perform the function approximation by optimizing the model function
-    boost::function< std::vector<FunctionModel::arguments_t>(const argument_t &, const double)> triplefunction =
-        boost::bind(&getTripleFromArgument, boost::cref(TersoffData.getTrainingInputs()), _1, _2);
-    srand((unsigned)time(0)); // seed with current time
-    LOG(0, "INFO: Initial parameters are " << params << ".");
-
-    SaturationPotential saturation(triplefunction);
-    saturation.setParameters(params);
-    FunctionModel &model = saturation;
-    FunctionApproximation approximator(TersoffData, model); // CH4 has 5 atoms, hence 5*4/2 distances
-    if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
-      approximator(FunctionApproximation::ParameterDerivative);
-    else
-      ELOG(0, "We require parameter derivatives for a box constraint minimization.");
-
-    params = model.getParameters();
-
-    LOG(0, "RESULT: Best parameters are " << params << ".");
-
-//    std::cout << "\tsaturationparticle:";
-//    std::cout << "\tparticle_type=C,";
-//    std::cout << "\tA=" << params[SaturationPotential::A] << ",";
-//    std::cout << "\tB=" << params[SaturationPotential::B] << ",";
-//    std::cout << "\tlambda=" << params[SaturationPotential::lambda] << ",";
-//    std::cout << "\tmu=" << params[SaturationPotential::mu] << ",";
-//    std::cout << "\tbeta=" << params[SaturationPotential::beta] << ",";
-//    std::cout << "\tn=" << params[SaturationPotential::n] << ",";
-//    std::cout << "\tc=" << params[SaturationPotential::c] << ",";
-//    std::cout << "\td=" << params[SaturationPotential::d] << ",";
-//    std::cout << "\th=" << params[SaturationPotential::h] << ",";
-////    std::cout << "\toffset=" << params[SaturationPotential::offset] << ",";
-//    std::cout << "\tR=" << saturation.R << ",";
-//    std::cout << "\tS=" << saturation.S << ";";
-//    std::cout << std::endl;
-
-    // check L2 and Lmax error against training set
-    LOG(1, "INFO: L2sum = " << TersoffData.getL2Error(model)
-        << ", LMax = " << TersoffData.getLMaxError(model) << ".");
+    const HomologyGraph graph = getFirstGraphwithTimesSpecificElement(homologies,6,1);
+    if (graph != HomologyGraph()) {
+      LOG(1, "First representative graph containing one saturated carbon is " << graph << ".");
+
+      // Afterwards we go through all of this type and gather the distance and the energy value
+      Fragment::charges_t SaturatedCarbon;
+      SaturatedCarbon += 6.,1.;
+      TrainingData TersoffData(
+//          boost::bind(&Extractors::gatherAllSymmetricDistanceArguments,
+//              boost::bind(&Extractors::gatherPositionOfTuples,
+//                  _1, boost::cref(SaturatedCarbon)
+//              ), _2
+//            )
+//          );
+          TrainingData::extractor_t(&Extractors::gatherAllDistances) // gather first carbon pair
+          );
+      TersoffData( homologies.getHomologousGraphs(graph) );
+      LOG(1, "INFO: I gathered the following training data: " << TersoffData);
+      // NOTICE that distance are in bohrradi as they come from MPQC!
+
+      // now perform the function approximation by optimizing the model function
+      boost::function< std::vector<FunctionModel::arguments_t>(const argument_t &, const double)> triplefunction =
+          boost::bind(&getTripleFromArgument, boost::cref(TersoffData.getTrainingInputs()), _1, _2);
+      srand((unsigned)time(0)); // seed with current time
+      params[SaturationPotential::all_energy_offset] = 1e+1*rand()/(double)RAND_MAX;//3.487900e+00;
+      params[SaturationPotential::morse_spring_constant] = 1e+1*rand()/(double)RAND_MAX;//1.393600e+03;
+      params[SaturationPotential::morse_equilibrium_distance] = 1e+1*rand()/(double)RAND_MAX;//3.467000e+02;
+      params[SaturationPotential::morse_dissociation_energy] = 1e+1*rand()/(double)RAND_MAX;//3.487900e+00;
+//      params[SaturationPotential::angle_spring_constant] = 1e+1*rand()/(double)RAND_MAX;//3.487900e+00;
+//      params[SaturationPotential::angle_equilibrium_distance] = 2e+0*rand()/(double)RAND_MAX - 1.;//3.487900e+00;
+      LOG(0, "INFO: Initial parameters are " << params << ".");
+
+      SaturationPotential saturation(triplefunction);
+      saturation.setParameters(params);
+      FunctionModel &model = saturation;
+      FunctionApproximation approximator(TersoffData, model); // CH4 has 5 atoms, hence 5*4/2 distances
+      if (model.isBoxConstraint() && approximator.checkParameterDerivatives())
+        approximator(FunctionApproximation::ParameterDerivative);
+      else {
+        ELOG(0, "We require parameter derivatives for a box constraint minimization.");
+        return 1;
+      }
+
+      params = model.getParameters();
+      LOG(0, "RESULT: Best parameters are " << params << ".");
+
+  //    std::cout << "\tsaturationparticle:";
+  //    std::cout << "\tparticle_type=C,";
+  //    std::cout << "\tA=" << params[SaturationPotential::A] << ",";
+  //    std::cout << "\tB=" << params[SaturationPotential::B] << ",";
+  //    std::cout << "\tlambda=" << params[SaturationPotential::lambda] << ",";
+  //    std::cout << "\tmu=" << params[SaturationPotential::mu] << ",";
+  //    std::cout << "\tbeta=" << params[SaturationPotential::beta] << ",";
+  //    std::cout << "\tn=" << params[SaturationPotential::n] << ",";
+  //    std::cout << "\tc=" << params[SaturationPotential::c] << ",";
+  //    std::cout << "\td=" << params[SaturationPotential::d] << ",";
+  //    std::cout << "\th=" << params[SaturationPotential::h] << ",";
+  ////    std::cout << "\toffset=" << params[SaturationPotential::offset] << ",";
+  //    std::cout << "\tR=" << saturation.R << ",";
+  //    std::cout << "\tS=" << saturation.S << ";";
+  //    std::cout << std::endl;
+
+      // check L2 and Lmax error against training set
+      LOG(1, "INFO: L2sum = " << TersoffData.getL2Error(model)
+          << ", LMax = " << TersoffData.getLMaxError(model) << ".");
+    }
+
   }
 
