/** \file periodentafel.cpp * * Function implementations for the class periodentafel. * */ #include "Helpers/MemDebug.hpp" using namespace std; #include #include #include #include #include "Helpers/Assert.hpp" #include "element.hpp" #include "elements_db.hpp" #include "helpers.hpp" #include "lists.hpp" #include "log.hpp" #include "periodentafel.hpp" #include "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 * const pointer) { atomicNumber_t Z = pointer->getNumber(); ASSERT(!elements.count(Z), "Element is already present."); pointer->sort = &pointer->Z; 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(element * const 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 */ element * const 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 */ element * const periodentafel::FindElement(const char * const 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 */ element * const periodentafel::AskElement() 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 */ element * const periodentafel::EnterElement() { atomicNumber_t Z = 0; DoLog(0) && (Log() << Verbose(0) << "Atomic number: " << Z << endl); cin >> Z; element * const 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->name; DoLog(0) && (Log() << Verbose(0) << "Short form [max 3 chars]: " << endl); cin >> tmp->symbol; AddElement(tmp); return tmp; } return res; }; /******************** Access to iterators ****************************/ periodentafel::const_iterator periodentafel::begin(){ return elements.begin(); } periodentafel::const_iterator periodentafel::end(){ return elements.end(); } periodentafel::reverse_iterator periodentafel::rbegin(){ return reverse_iterator(elements.end()); } periodentafel::reverse_iterator periodentafel::rend(){ 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; }; /** Prints period table to given stream. * \param *output output stream * \param *checkliste elements table for this molecule */ bool periodentafel::Checkout(ostream * const output, const int * const checkliste) const { bool result = true; int No = 1; if (output != NULL) { *output << "# Ion type data (PP = PseudoPotential, Z = atomic number)" << endl; *output << "#Ion_TypeNr.\tAmount\tZ\tRGauss\tL_Max(PP)L_Loc(PP)IonMass\t# chemical name, symbol" << endl; for(const_iterator iter=elements.begin(); iter!=elements.end();++iter){ if (((*iter).first < MAX_ELEMENTS) && (checkliste[(*iter).first])) { (*iter).second->No = No; result = result && (*iter).second->Checkout(output, No++, checkliste[(*iter).first]); } } 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; int counter = 0; pair< std::map::iterator, bool > InserterTest; if (!(*input).fail()) { (*input).getline(header1, MAXSTRINGSIZE); (*input).getline(header2, MAXSTRINGSIZE); // skip first two header lines 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)) { if (elements.count(neues->getNumber())) {// if element already present, remove and delete old one (i.e. replace it) //cout << neues->symbol << " is present already." << endl; element * const Elemental = FindElement(neues->getNumber()); ASSERT(Elemental != NULL, "element should be present but is not??"); *Elemental = *neues; delete(neues); neues = Elemental; } else { InserterTest = elements.insert(pair (neues->getNumber(), neues)); ASSERT(InserterTest.second, "Could not insert new element into periodentafel on LoadElementsDatabase()."); } DoLog(0) && (Log() << Verbose(0) << " " << elements[neues->getNumber()]->symbol); counter++; } else { DoeLog(2) && (eLog() << Verbose(2) << "Detected empty line or invalid element in elements db, discarding." << endl); DoLog(0) && (Log() << Verbose(0) << " "); delete(neues); } } DoLog(0) && (Log() << Verbose(0) << endl); } else { DoeLog(1) && (eLog() << Verbose(1) << "Could not open the database." << endl); status = false; } if (counter == 0) status = false; 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; };