/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * fragmentation_helpers.cpp * * Created on: Oct 18, 2011 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include "fragmentation_helpers.hpp" #include #include "CodePatterns/Log.hpp" #include "atom.hpp" #include "Bond/bond.hpp" #include "Element/element.hpp" #include "Fragmentation/Graph.hpp" #include "Fragmentation/KeySet.hpp" #include "Helpers/defs.hpp" #include "Helpers/helpers.hpp" #include "molecule.hpp" using namespace std; /** Inserts a (\a No, \a value) pair into the list, overwriting present one. * Note if values are equal, No will decided on which is first * \param *out output stream for debugging * \param &AdaptiveCriteriaList list to insert into * \param &IndexedKeySetList list to find key set for a given index \a No * \param FragOrder current bond order of fragment * \param No index of keyset * \param value energy value */ void InsertIntoAdaptiveCriteriaList(std::map > *AdaptiveCriteriaList, std::map &IndexKeySetList, int FragOrder, int No, double Value) { map::iterator marker = IndexKeySetList.find(No); // find keyset to Frag No. if (marker != IndexKeySetList.end()) { // if found Value *= 1 + MYEPSILON*(*((*marker).second.begin())); // in case of equal energies this makes them not equal without changing anything actually // as the smallest number in each set has always been the root (we use global id to keep the doubles away), seek smallest and insert into AtomMask pair >::iterator, bool> InsertedElement = AdaptiveCriteriaList->insert( make_pair(*((*marker).second.begin()), pair( fabs(Value), FragOrder) )); map >::iterator PresentItem = InsertedElement.first; if (!InsertedElement.second) { // this root is already present if ((*PresentItem).second.second < FragOrder) // if order there is lower, update entry with higher-order term //if ((*PresentItem).second.first < (*runner).first) // as higher-order terms are not always better, we skip this part (which would always include this site into adaptive increase) { // if value is smaller, update value and order (*PresentItem).second.first = fabs(Value); (*PresentItem).second.second = FragOrder; DoLog(2) && (Log() << Verbose(2) << "Updated element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl); } else { DoLog(2) && (Log() << Verbose(2) << "Did not update element " << (*PresentItem).first << " as " << FragOrder << " is less than or equal to " << (*PresentItem).second.second << "." << endl); } } else { DoLog(2) && (Log() << Verbose(2) << "Inserted element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl); } } else { DoLog(1) && (Log() << Verbose(1) << "No Fragment under No. " << No << "found." << endl); } }; /** Counts lines in file. * Note we are scanning lines from current position, not from beginning. * \param InputFile file to be scanned. */ int CountLinesinFile(std::ifstream &InputFile) { char *buffer = new char[MAXSTRINGSIZE]; int lines=0; int PositionMarker = InputFile.tellg(); // not needed as Inputfile is copied, given by value, not by ref // count the number of lines, i.e. the number of fragments InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines InputFile.getline(buffer, MAXSTRINGSIZE); while(!InputFile.eof()) { InputFile.getline(buffer, MAXSTRINGSIZE); lines++; } InputFile.seekg(PositionMarker, ios::beg); delete[](buffer); return lines; }; /** Scans the adaptive order file and insert (index, value) into map. * \param &path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative) * \param &IndexedKeySetList list to find key set for a given index \a No * \return adaptive criteria list from file */ std::map > * ScanAdaptiveFileIntoMap(std::string &path, std::map &IndexKeySetList) { map > *AdaptiveCriteriaList = new map >; int No = 0, FragOrder = 0; double Value = 0.; char buffer[MAXSTRINGSIZE]; string filename = path + ENERGYPERFRAGMENT; ifstream InputFile(filename.c_str()); if (InputFile.fail()) { DoeLog(1) && (eLog() << Verbose(1) << "Cannot find file " << filename << "." << endl); return AdaptiveCriteriaList; } if (CountLinesinFile(InputFile) > 0) { // each line represents a fragment root (Atom::Nr) id and its energy contribution InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines InputFile.getline(buffer, MAXSTRINGSIZE); while(!InputFile.eof()) { InputFile.getline(buffer, MAXSTRINGSIZE); if (strlen(buffer) > 2) { //Log() << Verbose(2) << "Scanning: " << buffer << endl; stringstream line(buffer); line >> FragOrder; line >> ws >> No; line >> ws >> Value; // skip time entry line >> ws >> Value; No -= 1; // indices start at 1 in file, not 0 //Log() << Verbose(2) << " - yields (" << No << "," << Value << ", " << FragOrder << ")" << endl; // clean the list of those entries that have been superceded by higher order terms already InsertIntoAdaptiveCriteriaList(AdaptiveCriteriaList, IndexKeySetList, FragOrder, No, Value); } } // close and done InputFile.close(); InputFile.clear(); } return AdaptiveCriteriaList; }; /** Maps adaptive criteria list back onto (Value, (Root Nr., Order)) * (i.e. sorted by value to pick the highest ones) * \param *out output stream for debugging * \param &AdaptiveCriteriaList list to insert into * \param *mol molecule with atoms * \return remapped list */ std::map > * ReMapAdaptiveCriteriaListToValue(std::map > *AdaptiveCriteriaList, molecule *mol) { atom *Walker = NULL; map > *FinalRootCandidates = new map > ; DoLog(1) && (Log() << Verbose(1) << "Root candidate list is: " << endl); for(map >::iterator runner = AdaptiveCriteriaList->begin(); runner != AdaptiveCriteriaList->end(); runner++) { Walker = mol->FindAtom((*runner).first); if (Walker != NULL) { //if ((*runner).second.second >= Walker->AdaptiveOrder) { // only insert if this is an "active" root site for the current order if (!Walker->MaxOrder) { DoLog(2) && (Log() << Verbose(2) << "(" << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "])" << endl); FinalRootCandidates->insert( make_pair( (*runner).second.first, pair((*runner).first, (*runner).second.second) ) ); } else { DoLog(2) && (Log() << Verbose(2) << "Excluding (" << *Walker << ", " << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "]), as it has reached its maximum order." << endl); } } else { DoeLog(0) && (eLog()<< Verbose(0) << "Atom No. " << (*runner).second.first << " was not found in this molecule." << endl); performCriticalExit(); } } return FinalRootCandidates; }; /** Marks all candidate sites for update if below adaptive threshold. * Picks a given number of highest values and set *AtomMask to true. * \param *out output stream for debugging * \param *AtomMask defines true/false per global Atom::Nr to mask in/out each nuclear site, used to activate given number of site to increment order adaptively * \param FinalRootCandidates list candidates to check * \param Order desired order * \param *mol molecule with atoms * \return true - if update is necessary, false - not */ bool MarkUpdateCandidates(bool *AtomMask, std::map > &FinalRootCandidates, int Order, molecule *mol) { atom *Walker = NULL; int No = -1; bool status = false; for(map >::iterator runner = FinalRootCandidates.upper_bound(pow(10.,Order)); runner != FinalRootCandidates.end(); runner++) { No = (*runner).second.first; Walker = mol->FindAtom(No); //if (Walker->AdaptiveOrder < MinimumRingSize[Walker->getNr()]) { DoLog(2) && (Log() << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", setting entry " << No << " of Atom mask to true." << endl); AtomMask[No] = true; status = true; //} else //Log() << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", however MinimumRingSize of " << MinimumRingSize[Walker->getNr()] << " does not allow further adaptive increase." << endl; } return status; }; /** print atom mask for debugging. * \param *out output stream for debugging * \param *AtomMask defines true/false per global Atom::Nr to mask in/out each nuclear site, used to activate given number of site to increment order adaptively * \param AtomCount number of entries in \a *AtomMask */ void PrintAtomMask(bool *AtomMask, int AtomCount) { DoLog(2) && (Log() << Verbose(2) << " "); for(int i=0;isize(); } StartNr = RootStack.back(); do { RootKeyNr = RootStack.front(); RootStack.pop_front(); Walker = mol->FindAtom(RootKeyNr); NumLevels = 1 << (Walker->AdaptiveOrder - 1); for(int i=0;igetNr()); RootNr++; } while (RootKeyNr != StartNr); return counter; }; /** Free's memory allocated for all KeySets from all orders. * \param *out output stream for debugging * \param ***FragmentLowerOrdersList * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied) * \param *mol molecule with atoms and bonds */ void FreeAllOrdersList(Graph ***FragmentLowerOrdersList, KeyStack &RootStack, molecule *mol) { DoLog(1) && (Log() << Verbose(1) << "Free'ing the lists of all orders per order." << endl); int RootNr = 0; int RootKeyNr = 0; int NumLevels = 0; atom *Walker = NULL; while (!RootStack.empty()) { RootKeyNr = RootStack.front(); RootStack.pop_front(); Walker = mol->FindAtom(RootKeyNr); NumLevels = 1 << (Walker->AdaptiveOrder - 1); for(int i=0;i