/* * 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. */ /** \file periodentafel.cpp * * Function implementations for the class periodentafel. * */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "Helpers/MemDebug.hpp" #include #include #include #include #include "Helpers/Assert.hpp" #include "element.hpp" #include "elements_db.hpp" #include "Helpers/helpers.hpp" #include "lists.hpp" #include "Helpers/Log.hpp" #include "periodentafel.hpp" #include "Helpers/Verbose.hpp" using namespace std; /************************************* Functions for class periodentafel ***************************/ /** constructor for class periodentafel * Initialises start and end of list and resets periodentafel::checkliste to false. */ periodentafel::periodentafel() { { stringstream input(elementsDB,ios_base::in); bool status = LoadElementsDatabase(input); ASSERT(status, "General element initialization failed"); } { stringstream input(valenceDB,ios_base::in); bool status = LoadValenceDatabase(&input); ASSERT(status, "Valence entry of element initialization failed"); } { stringstream input(orbitalsDB,ios_base::in); bool status = LoadOrbitalsDatabase(&input); ASSERT(status, "Orbitals entry of element initialization failed"); } { stringstream input(HbondangleDB,ios_base::in); bool status = LoadHBondAngleDatabase(&input); ASSERT(status, "HBond angle entry of element initialization failed"); } { stringstream input(HbonddistanceDB,ios_base::in); bool status = LoadHBondLengthsDatabase(&input); ASSERT(status, "HBond distance entry of element initialization failed"); } }; /** destructor for class periodentafel * Removes every element and afterwards deletes start and end of list. * TODO: Handle when elements have changed and store databases then */ periodentafel::~periodentafel() { CleanupPeriodtable(); }; /** Adds element to period table list * \param *pointer element to be added * \return iterator to added element */ periodentafel::iterator periodentafel::AddElement(element * pointer) { atomicNumber_t Z = pointer->getNumber(); ASSERT(!elements.count(Z), "Element is already present."); if (pointer->getNumber() < 1 && pointer->getNumber() >= MAX_ELEMENTS) DoeLog(0) && (eLog() << Verbose(0) << "Invalid Z number!\n"); pair res = elements.insert(pair(Z,pointer)); return res.first; }; /** Removes element from list. * \param *pointer element to be removed */ size_t periodentafel::RemoveElement(const element * pointer) { return RemoveElement(pointer->getNumber()); }; /** Removes element from list. * \param Z element to be removed */ size_t periodentafel::RemoveElement(atomicNumber_t Z) { return elements.erase(Z); }; /** Removes every element from the period table. */ void periodentafel::CleanupPeriodtable() { for(iterator iter=elements.begin();iter!=elements.end();++iter){ delete(*iter).second; } elements.clear(); }; /** Finds an element by its atomic number. * If element is not yet in list, returns NULL. * \param Z atomic number * \return pointer to element or NULL if not found */ const element * periodentafel::FindElement(atomicNumber_t Z) const { const_iterator res = elements.find(Z); return res!=elements.end()?((*res).second):0; }; /** Finds an element by its atomic number. * If element is not yet in list, datas are asked and stored in database. * \param shorthand chemical symbol of the element, e.g. H for hydrogene * \return pointer to element */ const element * periodentafel::FindElement(const string &shorthand) const { element *res = 0; for(const_iterator iter=elements.begin();iter!=elements.end();++iter) { if((*iter).second->getSymbol() == shorthand){ res = (*iter).second; break; } } return res; }; /** Asks for element number and returns pointer to element * \return desired element or NULL */ const element * periodentafel::AskElement() const { const element * walker = NULL; int Z; do { DoLog(0) && (Log() << Verbose(0) << "Atomic number Z: "); cin >> Z; walker = this->FindElement(Z); // give type } while (walker == NULL); return walker; }; /** Asks for element and if not found, presents mask to enter info. * \return pointer to either present or newly created element */ const element * periodentafel::EnterElement() { atomicNumber_t Z = 0; DoLog(0) && (Log() << Verbose(0) << "Atomic number: " << Z << endl); cin >> Z; const element *res = FindElement(Z); if (!res) { // TODO: make this using the constructor DoLog(0) && (Log() << Verbose(0) << "Element not found in database, please enter." << endl); element *tmp = new element; tmp->Z = Z; DoLog(0) && (Log() << Verbose(0) << "Mass: " << endl); cin >> tmp->mass; DoLog(0) && (Log() << Verbose(0) << "Name [max 64 chars]: " << endl); cin >> tmp->getName(); DoLog(0) && (Log() << Verbose(0) << "Short form [max 3 chars]: " << endl); cin >> tmp->getSymbol(); AddElement(tmp); return tmp; } return res; }; /******************** Access to iterators ****************************/ periodentafel::const_iterator periodentafel::begin() const{ return elements.begin(); } periodentafel::const_iterator periodentafel::end() const{ return elements.end(); } periodentafel::reverse_iterator periodentafel::rbegin() const{ return reverse_iterator(elements.end()); } periodentafel::reverse_iterator periodentafel::rend() const{ return reverse_iterator(elements.begin()); } /** Prints period table to given stream. * \param output stream */ bool periodentafel::Output(ostream * const output) const { bool result = true; if (output != NULL) { for(const_iterator iter=elements.begin(); iter !=elements.end();++iter){ result = result && (*iter).second->Output(output); } return result; } else return false; }; /** Loads element list from file. * \param *path to to standard file names */ bool periodentafel::LoadPeriodentafel(const char *path) { ifstream input; bool status = true; bool otherstatus = true; char filename[255]; // fill elements DB strncpy(filename, path, MAXSTRINGSIZE); strncat(filename, "/", MAXSTRINGSIZE-strlen(filename)); strncat(filename, STANDARDELEMENTSDB, MAXSTRINGSIZE-strlen(filename)); input.open(filename); if (!input.fail()) DoLog(0) && (Log() << Verbose(0) << "Using " << filename << " as elements database." << endl); status = status && LoadElementsDatabase(input); input.close(); input.clear(); // fill valence DB per element strncpy(filename, path, MAXSTRINGSIZE); strncat(filename, "/", MAXSTRINGSIZE-strlen(filename)); strncat(filename, STANDARDVALENCEDB, MAXSTRINGSIZE-strlen(filename)); input.open(filename); if (!input.fail()) DoLog(0) && (Log() << Verbose(0) << "Using " << filename << " as valence database." << endl); otherstatus = otherstatus && LoadValenceDatabase(&input); input.close(); input.clear(); // fill orbitals DB per element strncpy(filename, path, MAXSTRINGSIZE); strncat(filename, "/", MAXSTRINGSIZE-strlen(filename)); strncat(filename, STANDARDORBITALDB, MAXSTRINGSIZE-strlen(filename)); input.open(filename); if (!input.fail()) DoLog(0) && (Log() << Verbose(0) << "Using " << filename << " as orbitals database." << endl); otherstatus = otherstatus && LoadOrbitalsDatabase(&input); input.close(); input.clear(); // fill H-BondAngle DB per element strncpy(filename, path, MAXSTRINGSIZE); strncat(filename, "/", MAXSTRINGSIZE-strlen(filename)); strncat(filename, STANDARDHBONDANGLEDB, MAXSTRINGSIZE-strlen(filename)); input.open(filename); if (!input.fail()) DoLog(0) && (Log() << Verbose(0) << "Using " << filename << " as H bond angle database." << endl); otherstatus = otherstatus && LoadHBondAngleDatabase(&input); input.close(); input.clear(); // fill H-BondDistance DB per element strncpy(filename, path, MAXSTRINGSIZE); strncat(filename, "/", MAXSTRINGSIZE-strlen(filename)); strncat(filename, STANDARDHBONDDISTANCEDB, MAXSTRINGSIZE-strlen(filename)); input.open(filename); if (!input.fail()) DoLog(0) && (Log() << Verbose(0) << "Using " << filename << " as H bond length database." << endl); otherstatus = otherstatus && LoadHBondLengthsDatabase(&input); input.close(); input.clear(); if (!otherstatus){ DoeLog(2) && (eLog()<< Verbose(2) << "Something went wrong while parsing the other databases!" << endl); } return status; }; /** load the element info. * \param *input stream to parse from * \return true - parsing successful, false - something went wrong */ bool periodentafel::LoadElementsDatabase(istream &input) { bool status = true; string header1tmp,header2tmp; // first parse into a map, so we can revert to old status in case something goes wront map parsedElements; if (!input.fail()) { getline(input,header1tmp); getline(input,header2tmp); // skip first two header lines //cout << "First header: " << header1tmp << endl; //cout << "Second header: " << header2tmp << endl; // DoLog(0) && (Log() << Verbose(0) << "Parsed elements:"); while (!input.eof()) { element *neues = new element; input >> neues->name; //(*input) >> ws; input >> neues->symbol; //(*input) >> ws; input >> neues->period; //(*input) >> ws; input >> neues->group; //(*input) >> ws; input >> neues->block; //(*input) >> ws; input >> neues->Z; //(*input) >> ws; input >> neues->mass; //(*input) >> ws; input >> neues->CovalentRadius; //(*input) >> ws; input >> neues->VanDerWaalsRadius; //(*input) >> ws; input >> ws; //neues->Output((ofstream *)&cout); if ((neues->getNumber() > 0) && (neues->getNumber() < MAX_ELEMENTS)) { parsedElements[neues->Z] = neues; // DoLog(0) && (Log() << Verbose(0) << " " << *neues); } else { DoeLog(2) && (eLog() << Verbose(2) << "Detected empty line or invalid element in elements db, discarding." << endl); DoLog(0) && (Log() << Verbose(0) << " "); delete(neues); } // when the input is in failed state, we most likely just read garbage if(input.fail()) { DoeLog(2) && (eLog() << Verbose(2) << "Error parsing elements db." << endl); status = false; break; } } // DoLog(0) && (Log() << Verbose(0) << endl); } else { DoeLog(1) && (eLog() << Verbose(1) << "Could not open the database." << endl); status = false; } if (!parsedElements.size()) status = false; if(status){ for(map::iterator iter=parsedElements.begin(); iter!=parsedElements.end(); ++iter){ if (elements.count(iter->first)) { // if element already present, replace the old one // pointer to old element might still be in use, so we have to replace into the old element *(elements[iter->first])=*iter->second; delete(iter->second); } else { // no such element in periodentafel... we can just insert elements[iter->first] = iter->second; } } // all went well.. we now copy the header strncpy(header1,header1tmp.c_str(),MAXSTRINGSIZE); header1[MAXSTRINGSIZE-1]=0; strncpy(header2,header2tmp.c_str(),MAXSTRINGSIZE); header2[MAXSTRINGSIZE-1]=0; } return status; } /** load the valence info. * \param *input stream to parse from * \return true - parsing successful, false - something went wrong */ bool periodentafel::LoadValenceDatabase(istream *input) { char dummy[MAXSTRINGSIZE]; if (!(*input).fail()) { (*input).getline(dummy, MAXSTRINGSIZE); while (!(*input).eof()) { atomicNumber_t Z; (*input) >> Z; ASSERT(elements.count(Z), "Element not present"); (*input) >> ws; (*input) >> elements[Z]->Valence; (*input) >> ws; //Log() << Verbose(3) << "Element " << Z << " has " << FindElement(Z)->Valence << " valence electrons." << endl; } return true; } else return false; } /** load the orbitals info. * \param *input stream to parse from * \return true - parsing successful, false - something went wrong */ bool periodentafel::LoadOrbitalsDatabase(istream *input) { char dummy[MAXSTRINGSIZE]; if (!(*input).fail()) { (*input).getline(dummy, MAXSTRINGSIZE); while (!(*input).eof()) { atomicNumber_t Z; (*input) >> Z; ASSERT(elements.count(Z), "Element not present"); (*input) >> ws; (*input) >> elements[Z]->NoValenceOrbitals; (*input) >> ws; //Log() << Verbose(3) << "Element " << Z << " has " << FindElement(Z)->NoValenceOrbitals << " number of singly occupied valence orbitals." << endl; } return true; } else return false; } /** load the hbond angles info. * \param *input stream to parse from * \return true - parsing successful, false - something went wrong */ bool periodentafel::LoadHBondAngleDatabase(istream *input) { char dummy[MAXSTRINGSIZE]; if (!(*input).fail()) { (*input).getline(dummy, MAXSTRINGSIZE); while (!(*input).eof()) { atomicNumber_t Z; (*input) >> Z; ASSERT(elements.count(Z), "Element not present"); (*input) >> ws; (*input) >> elements[Z]->HBondAngle[0]; (*input) >> elements[Z]->HBondAngle[1]; (*input) >> elements[Z]->HBondAngle[2]; (*input) >> ws; //Log() << Verbose(3) << "Element " << (int)tmp << " has " << FindElement((int)tmp)->HBondAngle[0] << ", " << FindElement((int)tmp)->HBondAngle[1] << ", " << FindElement((int)tmp)->HBondAngle[2] << " degrees bond angle for one, two, three connected hydrogens." << endl; } return true; } else return false; } /** load the hbond lengths info. * \param *input stream to parse from * \return true - parsing successful, false - something went wrong */ bool periodentafel::LoadHBondLengthsDatabase(istream *input) { char dummy[MAXSTRINGSIZE]; if (!(*input).fail()) { (*input).getline(dummy, MAXSTRINGSIZE); while (!(*input).eof()) { atomicNumber_t Z; (*input) >> Z; ASSERT(elements.count(Z), "Element not present"); (*input) >> ws; (*input) >> elements[Z]->HBondDistance[0]; (*input) >> elements[Z]->HBondDistance[1]; (*input) >> elements[Z]->HBondDistance[2]; (*input) >> ws; //Log() << Verbose(3) << "Element " << (int)tmp << " has " << FindElement((int)tmp)->HBondDistance[0] << " Angstrom typical distance to hydrogen." << endl; } return true; } else return false; } /** Stores element list to file. */ bool periodentafel::StorePeriodentafel(const char *path) const { bool result = true; ofstream f; char filename[MAXSTRINGSIZE]; strncpy(filename, path, MAXSTRINGSIZE); strncat(filename, "/", MAXSTRINGSIZE-strlen(filename)); strncat(filename, STANDARDELEMENTSDB, MAXSTRINGSIZE-strlen(filename)); f.open(filename); if (f != NULL) { f << header1 << endl; f << header2 << endl; for(const_iterator iter=elements.begin();iter!=elements.end();++iter){ result = result && (*iter).second->Output(&f); } f.close(); return true; } else return result; };