Changeset c39675


Ignore:
Timestamp:
Apr 8, 2013, 11:56:08 AM (12 years ago)
Author:
Frederik Heber <heber@…>
Branches:
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
Children:
7cdf58
Parents:
6cabaac
git-author:
Frederik Heber <heber@…> (03/03/13 21:15:14)
git-committer:
Frederik Heber <heber@…> (04/08/13 11:56:08)
Message:

Added saturate() to SaturatedFragment.

  • basically, this is AddHydrogenReplacementAtom() but stripped down a bit as we use hydrogens from the pool and as atoms for the fragment need not be copied anymore, we don't need all the father mambo jumbo.
  • SaturatedFragment additionally now needs to know about how hydrogens are treated and whether we actually saturate.
  • SaturatedFragmentUnitTest requires libLinearAlgebra.
Location:
src/Fragmentation/Exporters
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified src/Fragmentation/Exporters/ExportGraph.cpp

    r6cabaac rc39675  
    114114{
    115115  // create the saturation which adds itself to KeySetsInUse
    116   SaturatedFragment_ptr _ptr(new SaturatedFragment(_set, KeySetsInUse, hydrogens));
     116  SaturatedFragment_ptr _ptr(
     117      new SaturatedFragment(
     118          _set,
     119          KeySetsInUse,
     120          hydrogens,
     121          treatment,
     122          saturation)
     123  );
    117124  // and return
    118125  return _ptr;
  • TabularUnified src/Fragmentation/Exporters/SaturatedFragment.cpp

    r6cabaac rc39675  
    3737#include "SaturatedFragment.hpp"
    3838
     39#include <cmath>
     40#include <iostream>
     41
    3942#include "CodePatterns/Assert.hpp"
    40 
     43#include "CodePatterns/Log.hpp"
     44
     45#include "LinearAlgebra/Exceptions.hpp"
     46#include "LinearAlgebra/Plane.hpp"
     47#include "LinearAlgebra/RealSpaceMatrix.hpp"
     48#include "LinearAlgebra/Vector.hpp"
     49
     50#include "Atom/atom.hpp"
     51#include "Bond/bond.hpp"
     52#include "config.hpp"
     53#include "Descriptors/AtomIdDescriptor.hpp"
    4154#include "Fragmentation/Exporters/HydrogenPool.hpp"
     55#include "Fragmentation/HydrogenSaturation_enum.hpp"
     56#include "Graph/BondGraph.hpp"
     57#include "World.hpp"
    4258
    4359SaturatedFragment::SaturatedFragment(
    4460    const KeySet &_set,
    4561    KeySetsInUse_t &_container,
    46     HydrogenPool &_hydrogens) :
     62    HydrogenPool &_hydrogens,
     63    const enum HydrogenTreatment _treatment,
     64    const enum HydrogenSaturation _saturation) :
    4765  container(_container),
    4866  set(_set),
    4967  hydrogens(_hydrogens),
    50   FullMolecule(set)
     68  FullMolecule(set),
     69  treatment(_treatment),
     70  saturation(_saturation)
    5171{
    5272  // add to in-use container
     
    5676  container.insert(set);
    5777
    58   // so far, we don't saturate anything
    59   SaturationHydrogens.clear();
     78  // prepare saturation hydrogens
     79  saturate();
    6080}
    6181
     
    7797  container.erase(iter);
    7898}
     99
     100void SaturatedFragment::saturate()
     101{
     102  // gather all atoms in a vector
     103  std::vector<atom *> atoms;
     104  for (KeySet::const_iterator iter = FullMolecule.begin();
     105      iter != FullMolecule.end();
     106      ++iter) {
     107    atom * const Walker = World::getInstance().getAtom(AtomById(*iter));
     108    ASSERT( Walker != NULL,
     109        "SaturatedFragment::OutputConfig() - id "
     110        +toString(*iter)+" is unknown to World.");
     111    atoms.push_back(Walker);
     112  }
     113
     114//  bool LonelyFlag = false;
     115  for (std::vector<atom *>::const_iterator iter = atoms.begin();
     116      iter != atoms.end();
     117      ++iter) {
     118    atom * const Walker = *iter;
     119
     120    // go through all bonds
     121    const BondList& ListOfBonds = Walker->getListOfBonds();
     122    for (BondList::const_iterator BondRunner = ListOfBonds.begin();
     123        BondRunner != ListOfBonds.end();
     124        ++BondRunner) {
     125      atom * const OtherWalker = (*BondRunner)->GetOtherAtom(Walker);
     126      // if in set
     127      if (set.find(OtherWalker->getId()) != set.end()) {
     128        LOG(4, "DEBUG: Walker " << *Walker << " is bound to " << *OtherWalker << ".");
     129//        if (OtherWalker->getId() > Walker->getId()) { // add bond (Nr check is for adding only one of both variants: ab, ba)
     130////          std::stringstream output;
     131////            output << "ACCEPT: Adding Bond: "
     132//          output << Leaf->AddBond((*iter), OtherWalker, (*BondRunner)->BondDegree);
     133////            LOG(3, output.str());
     134//          //NumBonds[(*iter)->getNr()]++;
     135//        } else {
     136////            LOG(3, "REJECY: Not adding bond, labels in wrong order.");
     137//        }
     138//        LonelyFlag = false;
     139      } else {
     140        LOG(4, "DEBUG: Walker " << *Walker << " is bound to "
     141            << *OtherWalker << ", who is not in this fragment molecule.");
     142        if (saturation == DoSaturate) {
     143//          LOG(3, "ACCEPT: Adding Hydrogen to " << (*iter)->Name << " and a bond in between.");
     144          if (!AddHydrogenReplacementAtom(
     145              (*BondRunner),
     146              Walker,
     147              OtherWalker,
     148              World::getInstance().getConfig()->IsAngstroem == 1))
     149            exit(1);
     150        }
     151//        } else if ((treatment == ExcludeHydrogen) && (OtherWalker->getElementNo() == (atomicNumber_t)1)) {
     152//          // just copy the atom if it's a hydrogen
     153//          atom * const OtherWalker = Leaf->AddCopyAtom(OtherWalker);
     154//          Leaf->AddBond((*iter), OtherWalker, (*BondRunner)->BondDegree);
     155//        }
     156        //NumBonds[(*iter)->getNr()] += Binder->BondDegree;
     157      }
     158    }
     159  }
     160}
     161
     162bool SaturatedFragment::OutputConfig(
     163    std::ostream &out,
     164    const ParserTypes _type) const
     165{
     166  // gather all atoms in a vector
     167  std::vector<atom *> atoms;
     168  for (KeySet::const_iterator iter = FullMolecule.begin();
     169      iter != FullMolecule.end();
     170      ++iter) {
     171    atom * const Walker = World::getInstance().getAtom(AtomById(*iter));
     172    ASSERT( Walker != NULL,
     173        "SaturatedFragment::OutputConfig() - id "
     174        +toString(*iter)+" is unknown to World.");
     175    atoms.push_back(Walker);
     176  }
     177
     178  // TODO: ScanForPeriodicCorrection() is missing so far!
     179  // note however that this is not straight-forward for the following reasons:
     180  // - we do not copy all atoms anymore, hence we are forced to shift the real
     181  //   atoms hither and back again
     182  // - we use a long-range potential that supports periodic boundary conditions.
     183  //   Hence, there we would like the original configuration (split through the
     184  //   the periodic boundaries). Otherwise, we would have to shift (and probably
     185  //   interpolate) the potential with OBCs applying.
     186
     187  // list atoms in fragment for debugging
     188  {
     189    std::stringstream output;
     190    output << "INFO: Contained atoms: ";
     191    for (std::vector<atom *>::const_iterator iter = atoms.begin();
     192        iter != atoms.end(); ++iter) {
     193      output << (*iter)->getName() << " ";
     194    }
     195    LOG(3, output.str());
     196  }
     197
     198  // store to stream via FragmentParser
     199  const bool intermediateResult =
     200      FormatParserStorage::getInstance().save(
     201          out,
     202          FormatParserStorage::getInstance().getSuffixFromType(_type),
     203          atoms);
     204
     205  return intermediateResult;
     206}
     207
     208atom * const SaturatedFragment::getHydrogenReplacement(atom * const replacement)
     209{
     210  atom * const _atom = hydrogens.leaseHydrogen();    // new atom
     211  _atom->setAtomicVelocity(replacement->getAtomicVelocity()); // copy velocity
     212  _atom->setFixedIon(replacement->getFixedIon());
     213  // if we replace hydrogen, we mark it as our father, otherwise we are just an added hydrogen with no father
     214  _atom->father = replacement;
     215  SaturationHydrogens.insert(_atom->getId());
     216  return _atom;
     217}
     218
     219bool SaturatedFragment::AddHydrogenReplacementAtom(
     220    bond::ptr TopBond,
     221    atom *Origin,
     222    atom *Replacement,
     223    bool IsAngstroem)
     224{
     225//  Info info(__func__);
     226  bool AllWentWell = true;    // flag gathering the boolean return value of molecule::AddAtom and other functions, as return value on exit
     227  double bondlength;  // bond length of the bond to be replaced/cut
     228  double bondangle;  // bond angle of the bond to be replaced/cut
     229  double BondRescale;   // rescale value for the hydrogen bond length
     230  bond::ptr FirstBond;
     231  bond::ptr SecondBond; // Other bonds in double bond case to determine "other" plane
     232  atom *FirstOtherAtom = NULL, *SecondOtherAtom = NULL, *ThirdOtherAtom = NULL; // pointer to hydrogen atoms to be added
     233  double b,l,d,f,g, alpha, factors[NDIM];    // hold temporary values in triple bond case for coordination determination
     234  Vector Orthovector1, Orthovector2;  // temporary vectors in coordination construction
     235  Vector InBondvector;    // vector in direction of *Bond
     236  const RealSpaceMatrix &matrix =  World::getInstance().getDomain().getM();
     237  bond::ptr Binder;
     238
     239  // create vector in direction of bond
     240  InBondvector = Replacement->getPosition() - Origin->getPosition();
     241  bondlength = InBondvector.Norm();
     242
     243   // is greater than typical bond distance? Then we have to correct periodically
     244   // the problem is not the H being out of the box, but InBondvector have the wrong direction
     245   // due to Replacement or Origin being on the wrong side!
     246  const BondGraph * const BG = World::getInstance().getBondGraph();
     247  const range<double> MinMaxBondDistance(
     248      BG->getMinMaxDistance(Origin,Replacement));
     249  if (!MinMaxBondDistance.isInRange(bondlength)) {
     250//    LOG(4, "InBondvector is: " << InBondvector << ".");
     251    Orthovector1.Zero();
     252    for (int i=NDIM;i--;) {
     253      l = Replacement->at(i) - Origin->at(i);
     254      if (fabs(l) > MinMaxBondDistance.last) { // is component greater than bond distance (check against min not useful here)
     255        Orthovector1[i] = (l < 0) ? -1. : +1.;
     256      } // (signs are correct, was tested!)
     257    }
     258    Orthovector1 *= matrix;
     259    InBondvector -= Orthovector1; // subtract just the additional translation
     260    bondlength = InBondvector.Norm();
     261//    LOG(4, "INFO: Corrected InBondvector is now: " << InBondvector << ".");
     262  } // periodic correction finished
     263
     264  InBondvector.Normalize();
     265  // get typical bond length and store as scale factor for later
     266  ASSERT(Origin->getType() != NULL,
     267      "SaturatedFragment::AddHydrogenReplacementAtom() - element of Origin is not given.");
     268  BondRescale = Origin->getType()->getHBondDistance(TopBond->BondDegree-1);
     269  if (BondRescale == -1) {
     270    ELOG(1, "There is no typical hydrogen bond distance in replacing bond (" << Origin->getName() << "<->" << Replacement->getName() << ") of degree " << TopBond->BondDegree << "!");
     271    return false;
     272    BondRescale = bondlength;
     273  } else {
     274    if (!IsAngstroem)
     275      BondRescale /= (1.*AtomicLengthToAngstroem);
     276  }
     277
     278  // discern single, double and triple bonds
     279  switch(TopBond->BondDegree) {
     280    case 1:
     281      // check whether replacement has been an excluded hydrogen
     282      if (Replacement->getType()->getAtomicNumber() == HydrogenPool::HYDROGEN) { // neither rescale nor replace if it's already hydrogen
     283        FirstOtherAtom = Replacement;
     284        BondRescale = bondlength;
     285      } else {
     286        FirstOtherAtom = getHydrogenReplacement(Replacement);
     287        InBondvector *= BondRescale;   // rescale the distance vector to Hydrogen bond length
     288        FirstOtherAtom->setPosition(Origin->getPosition() + InBondvector); // set coordination to origin and add distance vector to replacement atom
     289      }
     290      FullMolecule.insert(FirstOtherAtom->getId());
     291//      LOG(4, "INFO: Added " << *FirstOtherAtom << " at: " << FirstOtherAtom->x << ".");
     292      break;
     293    case 2:
     294      {
     295        // determine two other bonds (warning if there are more than two other) plus valence sanity check
     296        const BondList& ListOfBonds = Origin->getListOfBonds();
     297        for (BondList::const_iterator Runner = ListOfBonds.begin();
     298            Runner != ListOfBonds.end();
     299            ++Runner) {
     300          if ((*Runner) != TopBond) {
     301            if (FirstBond == NULL) {
     302              FirstBond = (*Runner);
     303              FirstOtherAtom = (*Runner)->GetOtherAtom(Origin);
     304            } else if (SecondBond == NULL) {
     305              SecondBond = (*Runner);
     306              SecondOtherAtom = (*Runner)->GetOtherAtom(Origin);
     307            } else {
     308              ELOG(2, "Detected more than four bonds for atom " << Origin->getName());
     309            }
     310          }
     311        }
     312      }
     313      if (SecondOtherAtom == NULL) {  // then we have an atom with valence four, but only 3 bonds: one to replace and one which is TopBond (third is FirstBond)
     314        SecondBond = TopBond;
     315        SecondOtherAtom = Replacement;
     316      }
     317      if (FirstOtherAtom != NULL) { // then we just have this double bond and the plane does not matter at all
     318//        LOG(3, "Regarding the double bond (" << Origin->Name << "<->" << Replacement->Name << ") to be constructed: Taking " << FirstOtherAtom->Name << " and " << SecondOtherAtom->Name << " along with " << Origin->Name << " to determine orthogonal plane.");
     319
     320        // determine the plane of these two with the *origin
     321        try {
     322          Orthovector1 = Plane(Origin->getPosition(), FirstOtherAtom->getPosition(), SecondOtherAtom->getPosition()).getNormal();
     323        }
     324        catch(LinearDependenceException &excp){
     325          LOG(0, boost::diagnostic_information(excp));
     326          // TODO: figure out what to do with the Orthovector in this case
     327          AllWentWell = false;
     328        }
     329      } else {
     330        Orthovector1.GetOneNormalVector(InBondvector);
     331      }
     332      //LOG(3, "INFO: Orthovector1: " << Orthovector1 << ".");
     333      // orthogonal vector and bond vector between origin and replacement form the new plane
     334      Orthovector1.MakeNormalTo(InBondvector);
     335      Orthovector1.Normalize();
     336      //LOG(3, "ReScaleCheck: " << Orthovector1.Norm() << " and " << InBondvector.Norm() << ".");
     337
     338      // create the two Hydrogens ...
     339      FirstOtherAtom = getHydrogenReplacement(Replacement);
     340      SecondOtherAtom = getHydrogenReplacement(Replacement);
     341      FullMolecule.insert(FirstOtherAtom->getId());
     342      FullMolecule.insert(SecondOtherAtom->getId());
     343      bondangle = Origin->getType()->getHBondAngle(1);
     344      if (bondangle == -1) {
     345        ELOG(1, "There is no typical hydrogen bond angle in replacing bond (" << Origin->getName() << "<->" << Replacement->getName() << ") of degree " << TopBond->BondDegree << "!");
     346        return false;
     347        bondangle = 0;
     348      }
     349      bondangle *= M_PI/180./2.;
     350//      LOG(3, "INFO: ReScaleCheck: InBondvector " << InBondvector << ", " << Orthovector1 << ".");
     351//      LOG(3, "Half the bond angle is " << bondangle << ", sin and cos of it: " << sin(bondangle) << ", " << cos(bondangle));
     352      FirstOtherAtom->Zero();
     353      SecondOtherAtom->Zero();
     354      for(int i=NDIM;i--;) { // rotate by half the bond angle in both directions (InBondvector is bondangle = 0 direction)
     355        FirstOtherAtom->set(i, InBondvector[i] * cos(bondangle) + Orthovector1[i] * (sin(bondangle)));
     356        SecondOtherAtom->set(i, InBondvector[i] * cos(bondangle) + Orthovector1[i] * (-sin(bondangle)));
     357      }
     358      FirstOtherAtom->Scale(BondRescale);  // rescale by correct BondDistance
     359      SecondOtherAtom->Scale(BondRescale);
     360      //LOG(3, "ReScaleCheck: " << FirstOtherAtom->x.Norm() << " and " << SecondOtherAtom->x.Norm() << ".");
     361      *FirstOtherAtom += Origin->getPosition();
     362      *SecondOtherAtom += Origin->getPosition();
     363      // ... and add to molecule
     364//      LOG(4, "INFO: Added " << *FirstOtherAtom << " at: " << FirstOtherAtom->x << ".");
     365//      LOG(4, "INFO: Added " << *SecondOtherAtom << " at: " << SecondOtherAtom->x << ".");
     366      break;
     367    case 3:
     368      // take the "usual" tetraoidal angle and add the three Hydrogen in direction of the bond (height of the tetraoid)
     369      FirstOtherAtom = getHydrogenReplacement(Replacement);
     370      SecondOtherAtom = getHydrogenReplacement(Replacement);
     371      ThirdOtherAtom = getHydrogenReplacement(Replacement);
     372      FullMolecule.insert(FirstOtherAtom->getId());
     373      FullMolecule.insert(SecondOtherAtom->getId());
     374      FullMolecule.insert(ThirdOtherAtom->getId());
     375
     376      // we need to vectors orthonormal the InBondvector
     377      AllWentWell = AllWentWell && Orthovector1.GetOneNormalVector(InBondvector);
     378//      LOG(3, "INFO: Orthovector1: " << Orthovector1 << ".");
     379      try{
     380        Orthovector2 = Plane(InBondvector, Orthovector1,0).getNormal();
     381      }
     382      catch(LinearDependenceException &excp) {
     383        LOG(0, boost::diagnostic_information(excp));
     384        AllWentWell = false;
     385      }
     386//      LOG(3, "INFO: Orthovector2: " << Orthovector2 << ".")
     387
     388      // create correct coordination for the three atoms
     389      alpha = (Origin->getType()->getHBondAngle(2))/180.*M_PI/2.;  // retrieve triple bond angle from database
     390      l = BondRescale;        // desired bond length
     391      b = 2.*l*sin(alpha);    // base length of isosceles triangle
     392      d = l*sqrt(cos(alpha)*cos(alpha) - sin(alpha)*sin(alpha)/3.);   // length for InBondvector
     393      f = b/sqrt(3.);   // length for Orthvector1
     394      g = b/2.;         // length for Orthvector2
     395//      LOG(3, "Bond length and half-angle: " << l << ", " << alpha << "\t (b,d,f,g) = " << b << ", " << d << ", " << f << ", " << g << ", ");
     396//      LOG(3, "The three Bond lengths: " << sqrt(d*d+f*f) << ", " << sqrt(d*d+(-0.5*f)*(-0.5*f)+g*g) << ", "  << sqrt(d*d+(-0.5*f)*(-0.5*f)+g*g));
     397      factors[0] = d;
     398      factors[1] = f;
     399      factors[2] = 0.;
     400      FirstOtherAtom->LinearCombinationOfVectors(InBondvector, Orthovector1, Orthovector2, factors);
     401      factors[1] = -0.5*f;
     402      factors[2] = g;
     403      SecondOtherAtom->LinearCombinationOfVectors(InBondvector, Orthovector1, Orthovector2, factors);
     404      factors[2] = -g;
     405      ThirdOtherAtom->LinearCombinationOfVectors(InBondvector, Orthovector1, Orthovector2, factors);
     406
     407      // rescale each to correct BondDistance
     408//      FirstOtherAtom->x.Scale(&BondRescale);
     409//      SecondOtherAtom->x.Scale(&BondRescale);
     410//      ThirdOtherAtom->x.Scale(&BondRescale);
     411
     412      // and relative to *origin atom
     413      *FirstOtherAtom += Origin->getPosition();
     414      *SecondOtherAtom += Origin->getPosition();
     415      *ThirdOtherAtom += Origin->getPosition();
     416
     417      // ... and add to molecule
     418//      LOG(4, "INFO: Added " << *FirstOtherAtom << " at: " << FirstOtherAtom->x << ".");
     419//      LOG(4, "INFO: Added " << *SecondOtherAtom << " at: " << SecondOtherAtom->x << ".");
     420//      LOG(4, "INFO: Added " << *ThirdOtherAtom << " at: " << ThirdOtherAtom->x << ".");
     421      break;
     422    default:
     423      ELOG(1, "BondDegree does not state single, double or triple bond!");
     424      AllWentWell = false;
     425      break;
     426  }
     427
     428  return AllWentWell;
     429};
  • TabularUnified src/Fragmentation/Exporters/SaturatedFragment.hpp

    r6cabaac rc39675  
    1414#endif
    1515
     16#include <iosfwd>
    1617#include <set>
     18#include <string>
    1719
     20#include "Bond/bond.hpp"
    1821#include "Fragmentation/KeySet.hpp"
     22#include "Fragmentation/HydrogenSaturation_enum.hpp"
     23#include "Parser/FormatParserStorage.hpp"
    1924
     25class atom;
    2026class HydrogenPool;
    2127
     
    4652      const KeySet &_set,
    4753      KeySetsInUse_t &_container,
    48       HydrogenPool &_hydrogens);
     54      HydrogenPool &_hydrogens,
     55      const enum HydrogenTreatment _treatment,
     56      const enum HydrogenSaturation saturation);
    4957
    5058  /** Destructor of class SaturatedFragment.
     
    6270  }
    6371
     72  /** Getter for the FullMolecule this instance is associated with.
     73   *
     74   * \return const ref to FullMolecule
     75   */
     76  const KeySet & getFullMolecule() const
     77  {
     78    return FullMolecule;
     79  }
     80
     81  /** Getter for the SaturationHydrogens this instance is associated with.
     82   *
     83   * \return const ref to SaturationHydrogens
     84   */
     85  const KeySet & getSaturationHydrogens() const
     86  {
     87    return SaturationHydrogens;
     88  }
     89
     90  /** Prints the config of the fragment of \a _type to \a out.
     91   *
     92   * \param out output stream to write to
     93   * \param _type parser type to write config
     94   */
     95  bool OutputConfig(
     96      std::ostream &out,
     97      const ParserTypes _type) const;
     98
     99private:
     100  /** Helper function to lease and bring in place saturation hydrogens.
     101   *
     102   */
     103  void saturate();
     104
     105  /** Helper function to get a hydrogen replacement for a given \a replacement.
     106   *
     107   * \param replacement atom to "replace" with hydrogen in a fragment.
     108   * \return ref to leased hydrogen atom
     109   */
     110  atom * const getHydrogenReplacement(atom * const replacement);
     111
     112  /** Leases and adds a Hydrogen atom in replacement for the given atom \a *partner in bond with a *origin.
     113   * Here, we have to distinguish between single, double or triple bonds as stated by \a BondDegree, that each demand
     114   * a different scheme when adding \a *replacement atom for the given one.
     115   * -# Single Bond: Simply add new atom with bond distance rescaled to typical hydrogen one
     116   * -# Double Bond: Here, we need the **BondList of the \a *origin atom, by scanning for the other bonds instead of
     117   *    *Bond, we use the through these connected atoms to determine the plane they lie in, vector::MakeNormalvector().
     118   *    The orthonormal vector to this plane along with the vector in *Bond direction determines the plane the two
     119   *    replacing hydrogens shall lie in. Now, all remains to do is take the usual hydrogen double bond angle for the
     120   *    element of *origin and form the sin/cos admixture of both plane vectors for the new coordinates of the two
     121   *    hydrogens forming this angle with *origin.
     122   * -# Triple Bond: The idea is to set up a tetraoid (C1-H1-H2-H3) (however the lengths \f$b\f$ of the sides of the base
     123   *    triangle formed by the to be added hydrogens are not equal to the typical bond distance \f$l\f$ but have to be
     124   *    determined from the typical angle \f$\alpha\f$ for a hydrogen triple connected to the element of *origin):
     125   *    We have the height \f$d\f$ as the vector in *Bond direction (from triangle C1-H1-H2).
     126   *    \f[ h = l \cdot \cos{\left (\frac{\alpha}{2} \right )} \qquad b = 2l \cdot \sin{\left (\frac{\alpha}{2} \right)} \quad \rightarrow \quad d = l \cdot \sqrt{\cos^2{\left (\frac{\alpha}{2} \right)}-\frac{1}{3}\cdot\sin^2{\left (\frac{\alpha}{2}\right )}}
     127   *    \f]
     128   *    vector::GetNormalvector() creates one orthonormal vector from this *Bond vector and vector::MakeNormalvector creates
     129   *    the third one from the former two vectors. The latter ones form the plane of the base triangle mentioned above.
     130   *    The lengths for these are \f$f\f$ and \f$g\f$ (from triangle H1-H2-(center of H1-H2-H3)) with knowledge that
     131   *    the median lines in an isosceles triangle meet in the center point with a ratio 2:1.
     132   *    \f[ f = \frac{b}{\sqrt{3}} \qquad g = \frac{b}{2}
     133   *    \f]
     134   *    as the coordination of all three atoms in the coordinate system of these three vectors:
     135   *    \f$\pmatrix{d & f & 0}\f$, \f$\pmatrix{d & -0.5 \cdot f & g}\f$ and \f$\pmatrix{d & -0.5 \cdot f & -g}\f$.
     136   *
     137   * \param TopBond pointer to bond between \a *origin and \a *replacement
     138   * \param Origin atom that is actually contained in the fragment
     139   * \param Replacement pointer to the atom which shall be copied as a hydrogen atom in this molecule
     140   * \param isAngstroem whether the coordination of the given atoms is in AtomicLength (false) or Angstrom(true)
     141   * \return number of atoms added, if < bond::BondDegree then something went wrong
     142   */
     143  bool AddHydrogenReplacementAtom(
     144      bond::ptr TopBond,
     145      atom *Origin,
     146      atom *Replacement,
     147      bool IsAngstroem);
     148
    64149private:
    65150  //!> container to mark ourselves RAII-style
     
    73158  //!> key set containing the ids of all hydrogens added for saturation
    74159  KeySet SaturationHydrogens;
     160  //!> whether hydrogens are generally contained in set or not
     161  const enum HydrogenTreatment treatment;
     162  //!> whether to actually saturate or not
     163  const enum HydrogenSaturation saturation;
    75164};
    76165
  • TabularUnified src/Fragmentation/Exporters/unittests/Makefile.am

    r6cabaac rc39675  
    2727        ../Fragmentation/Exporters/unittests/HydrogenPoolUnitTest.hpp
    2828HydrogenPoolUnitTest_LDADD = \
    29         ${FRAGMENTATIONEXPORTERSLIBS} \
    30         ../libMolecuilderUI.la
     29        ../libMolecuilderUI.la \
     30        ${FRAGMENTATIONEXPORTERSLIBS}
    3131       
    3232SaturatedFragmentUnitTest_SOURCES = $(top_srcdir)/src/unittests/UnitTestMain.cpp \
     
    3434        ../Fragmentation/Exporters/unittests/SaturatedFragmentUnitTest.hpp
    3535SaturatedFragmentUnitTest_LDADD = \
    36         ${FRAGMENTATIONEXPORTERSLIBS} \
    37         ../libMolecuilderUI.la
     36        ../libMolecuilderUI.la  \
     37        $(top_builddir)/LinearAlgebra/src/LinearAlgebra/libLinearAlgebra.la \
     38        ${FRAGMENTATIONEXPORTERSLIBS}
    3839       
    3940
  • TabularUnified src/Fragmentation/Exporters/unittests/SaturatedFragmentUnitTest.cpp

    r6cabaac rc39675  
    4949#include "CodePatterns/Assert.hpp"
    5050
     51#include "Fragmentation/HydrogenSaturation_enum.hpp"
    5152
    5253#ifdef HAVE_TESTRUNNER
     
    6869
    6970  set = new KeySet;
    70   fragment = new SaturatedFragment(*set, KeySetsInUse, hydrogens);
     71  fragment = new SaturatedFragment(*set, KeySetsInUse, hydrogens, ExcludeHydrogen, DoSaturate);
    7172}
    7273
Note: See TracChangeset for help on using the changeset viewer.