/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * PcpParser_helper.cpp * * Created on: Oct 27, 2011 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include #include #include #include "CodePatterns/Log.hpp" #include "Element/element.hpp" #include "Element/periodentafel.hpp" #include "Helpers/helpers.hpp" #include "molecule.hpp" #include "Parser/ConfigFileBuffer.hpp" /** Reads parameter from a parsed file. * The file is either parsed for a certain keyword or if null is given for * the value in row yth and column xth. If the keyword was necessity#critical, * then an error is thrown and the programme aborted. * \warning value is modified (both in contents and position)! * \param verbose 1 - print found value to stderr, 0 - don't * \param *file file to be parsed * \param name Name of value in file (at least 3 chars!) * \param sequential 1 - do not reset file pointer to begin of file, 0 - set to beginning * (if file is sequentially parsed this can be way faster! However, beware of multiple values per line, as whole line is read - * best approach: 0 0 0 1 (not resetted only on last value of line) - and of yth, which is now * counted from this unresetted position!) * \param xth Which among a number of parameters it is (in grid case it's row number as grid is read as a whole!) * \param yth In grid case specifying column number, otherwise the yth \a name matching line * \param type Type of the Parameter to be read * \param value address of the value to be read (must have been allocated) * \param repetition determines, if the keyword appears multiply in the config file, which repetition shall be parsed, i.e. 1 if not multiply * \param critical necessity of this keyword being specified (optional, critical) * \return 1 - found, 0 - not found * \note Routine is taken from the pcp project and hack-a-slack adapted to C++ */ int ParseForParameter(const int verbose, ifstream * const file, const char * const name, const int sequential, const int xth, const int yth, const int type, void * value, const int repetition, const int critical) { int i = 0; int j = 0; // loop variables int length = 0; int maxlength = -1; long file_position = file->tellg(); // mark current position char *dummy1 = NULL; char *dummy = NULL; char free_dummy[MAXSTRINGSIZE]; // pointers in the line that is read in per step dummy1 = free_dummy; //fprintf(stderr,"Parsing for %s\n",name); if (repetition == 0) //Error(SomeError, "ParseForParameter(): argument repetition must not be 0!"); return 0; int line = 0; // marks line where parameter was found int found = (type >= grid) ? 0 : (-yth + 1); // marks if yth parameter name was found while((found != repetition)) { dummy1 = dummy = free_dummy; do { file->getline(dummy1, 256); // Read the whole line if (file->eof()) { if ((critical) && (found == 0)) { //Error(InitReading, name); fprintf(stderr,"Error:InitReading, critical %s not found\n", name); exit(255); } else { //if (!sequential) file->clear(); file->seekg(file_position, ios::beg); // rewind to start position return 0; } } line++; } while (dummy != NULL && dummy1 != NULL && ((dummy1[0] == '#') || (dummy1[0] == '\0'))); // skip commentary and empty lines // C++ getline removes newline at end, thus re-add if ((dummy1 != NULL) && (strchr(dummy1,'\n') == NULL)) { i = strlen(dummy1); dummy1[i] = '\n'; dummy1[i+1] = '\0'; } //fprintf(stderr,"line %i ends at %i, newline at %i\n", line, strlen(dummy1), strchr(dummy1,'\n')-free_dummy); if (dummy1 == NULL) { if (verbose) fprintf(stderr,"Error reading line %i\n",line); } else { //fprintf(stderr,"Now parsing the line %i: %s\n", line, dummy1); } // Seek for possible end of keyword on line if given ... if (name != NULL) { dummy = strchr(dummy1,'\t'); // set dummy on first tab or space which ever's nearer if (dummy == NULL) { dummy = strchr(dummy1, ' '); // if not found seek for space while ((dummy != NULL) && ((*dummy == '\t') || (*dummy == ' '))) // skip some more tabs and spaces if necessary dummy++; } if (dummy == NULL) { dummy = strchr(dummy1, '\n'); // set on line end then (whole line = keyword) //fprintf(stderr,"Error: Cannot find tabs or spaces on line %i in search for %s\n", line, name); //Error(FileOpenParams, NULL); } else { //fprintf(stderr,"found tab at %i\n",(char *)dummy-(char *)dummy1); } } else dummy = dummy1; // ... and check if it is the keyword! //fprintf(stderr,"name %p, dummy %i/%c, dummy1 %i/%c, strlen(name) %i\n", &name, dummy, *dummy, dummy1, *dummy1, strlen(name)); if ((name == NULL) || (((dummy-dummy1 >= 3) && (strncmp(dummy1, name, strlen(name)) == 0)) && ((unsigned int)(dummy-dummy1) == strlen(name)))) { found++; // found the parameter! //fprintf(stderr,"found %s at line %i between %i and %i\n", name, line, dummy1, dummy); if (found == repetition) { for (i=0;i= grid) { // grid structure means that grid starts on the next line, not right after keyword dummy1 = dummy = free_dummy; do { file->getline(dummy1, 256); // Read the whole line, skip commentary and empty ones if (file->eof()) { if ((critical) && (found == 0)) { //Error(InitReading, name); fprintf(stderr,"Error:InitReading, critical %s not found\n", name); exit(255); } else { //if (!sequential) file->clear(); file->seekg(file_position, ios::beg); // rewind to start position return 0; } } line++; } while ((dummy1[0] == '#') || (dummy1[0] == '\n')); if (dummy1 == NULL){ if (verbose) fprintf(stderr,"Error reading line %i\n", line); } else { //fprintf(stderr,"Reading next line %i: %s\n", line, dummy1); } } else { // simple int, strings or doubles start in the same line while ((*dummy == '\t') || (*dummy == ' ')) // skip interjacent tabs and spaces dummy++; } // C++ getline removes newline at end, thus re-add if ((dummy1 != NULL) && (strchr(dummy1,'\n') == NULL)) { j = strlen(dummy1); dummy1[j] = '\n'; dummy1[j+1] = '\0'; } int start = (type >= grid) ? 0 : yth-1 ; for (j=start;j j) && (type == upper_trigrid)) || ((j > i) && (type == lower_trigrid))) { *((double *)value) = 0.0; fprintf(stderr,"%f\t",*((double *)value)); value = (void *)((long)value + sizeof(double)); //value += sizeof(double); } else { // otherwise we must skip all interjacent tabs and spaces and find next value dummy1 = dummy; dummy = strchr(dummy1, '\t'); // seek for tab or space if (dummy == NULL) dummy = strchr(dummy1, ' '); // if not found seek for space if (dummy == NULL) { // if still zero returned ... dummy = strchr(dummy1, '\n'); // ... at line end then if ((j < yth-1) && (type < 4)) { // check if xth value or not yet if (critical) { if (verbose) fprintf(stderr,"Error: EoL at %i and still missing %i value(s) for parameter %s\n", line, yth-j, name); //return 0; exit(255); //Error(FileOpenParams, NULL); } else { //if (!sequential) file->clear(); file->seekg(file_position, ios::beg); // rewind to start position return 0; } } } else { //fprintf(stderr,"found tab at %i\n",(char *)dummy-(char *)free_dummy); } if (*dummy1 == '#') { // found comment, skipping rest of line //if (verbose) fprintf(stderr,"Error: '#' at %i and still missing %i value(s) for parameter %s\n", line, yth-j, name); if (!sequential) { // here we need it! file->seekg(file_position, ios::beg); // rewind to start position } return 0; } //fprintf(stderr,"value from %i to %i\n",(char *)dummy1-(char *)free_dummy,(char *)dummy-(char *)free_dummy); switch(type) { case (row_int): *((int *)value) = atoi(dummy1); if ((verbose) && (i==0) && (j==0)) fprintf(stderr,"%s = ", name); if (verbose) fprintf(stderr,"%i\t",*((int *)value)); value = (void *)((long)value + sizeof(int)); //value += sizeof(int); break; case(row_double): case(grid): case(lower_trigrid): case(upper_trigrid): *((double *)value) = atof(dummy1); if ((verbose) && (i==0) && (j==0)) fprintf(stderr,"%s = ", name); if (verbose) fprintf(stderr,"%lg\t",*((double *)value)); value = (void *)((long)value + sizeof(double)); //value += sizeof(double); break; case(double_type): *((double *)value) = atof(dummy1); if ((verbose) && (i == xth-1)) fprintf(stderr,"%s = %lg\n", name, *((double *) value)); //value += sizeof(double); break; case(int_type): *((int *)value) = atoi(dummy1); if ((verbose) && (i == xth-1)) fprintf(stderr,"%s = %i\n", name, *((int *) value)); //value += sizeof(int); break; default: case(string_type): if (value != NULL) { //if (maxlength == -1) maxlength = strlen((char *)value); // get maximum size of string array maxlength = MAXSTRINGSIZE; length = maxlength > (dummy-dummy1) ? (dummy-dummy1) : maxlength; // cap at maximum strncpy((char *)value, dummy1, length); // copy as much ((char *)value)[length] = '\0'; // and set end marker if ((verbose) && (i == xth-1)) fprintf(stderr,"%s is '%s' (%i chars)\n",name,((char *) value), length); //value += sizeof(char); } else { } break; } } while (*dummy == '\t') dummy++; } } } } } if ((type >= row_int) && (verbose)) fprintf(stderr,"\n"); if (!sequential) { file->clear(); file->seekg(file_position, ios::beg); // rewind to start position } //fprintf(stderr, "End of Parsing\n\n"); return (found); // true if found, false if not } /** Reads parameter from a parsed file. * The file is either parsed for a certain keyword or if null is given for * the value in row yth and column xth. If the keyword was necessity#critical, * then an error is thrown and the programme aborted. * \warning value is modified (both in contents and position)! * \param verbose 1 - print found value to stderr, 0 - don't * \param *FileBuffer pointer to buffer structure * \param name Name of value in file (at least 3 chars!) * \param sequential 1 - do not reset file pointer to begin of file, 0 - set to beginning * (if file is sequentially parsed this can be way faster! However, beware of multiple values per line, as whole line is read - * best approach: 0 0 0 1 (not resetted only on last value of line) - and of yth, which is now * counted from this unresetted position!) * \param xth Which among a number of parameters it is (in grid case it's row number as grid is read as a whole!) * \param yth In grid case specifying column number, otherwise the yth \a name matching line * \param type Type of the Parameter to be read * \param value address of the value to be read (must have been allocated) * \param repetition determines, if the keyword appears multiply in the config file, which repetition shall be parsed, i.e. 1 if not multiply * \param critical necessity of this keyword being specified (optional, critical) * \return 1 - found, 0 - not found * \note Routine is taken from the pcp project and hack-a-slack adapted to C++ */ int ParseForParameter(const int verbose, struct ConfigFileBuffer * const FileBuffer, const char * const name, const int sequential, const int xth, const int yth, const int type, void * value, const int repetition, const int critical) { int i = 0; int j = 0; // loop variables int length = 0; int maxlength = -1; int OldCurrentLine = FileBuffer->CurrentLine; char *dummy1 = NULL; char *dummy = NULL; // pointers in the line that is read in per step char *free_dummy = NULL; if (verbose) fprintf(stderr,"Begin of Parsing for %s\n",name); if (repetition == 0) //Error(SomeError, "ParseForParameter(): argument repetition must not be 0!"); return 0; int found = (type >= grid) ? 0 : (-yth + 1); // marks if yth parameter name was found while((found != repetition)) { dummy1 = dummy = NULL; do { if (FileBuffer->CurrentLine < FileBuffer->NoLines) free_dummy = dummy1 = FileBuffer->buffer[ FileBuffer->LineMapping[FileBuffer->CurrentLine++] ]; if (FileBuffer->CurrentLine >= FileBuffer->NoLines) { if ((critical) && (found == 0)) { //Error(InitReading, name); fprintf(stderr,"Error:InitReading, critical %s not found\n", name); return 0; } else { //fprintf(stdout,"Rewinding to OldCurrentLine due to search till end of file.\n"); FileBuffer->CurrentLine = OldCurrentLine; // rewind to start position return 0; } } if (dummy1 == NULL) { if (verbose) fprintf(stderr,"Error reading line %i\n",FileBuffer->CurrentLine); } else { if (verbose) fprintf(stderr,"Now parsing the line %i: %s\n", FileBuffer->CurrentLine, dummy1); } //FileBuffer->CurrentLine++; } while (dummy1 != NULL && ((dummy1[0] == '#') || (dummy1[0] == '\0'))); // skip commentary and empty lines // Seek for possible end of keyword on line if given ... if (name != NULL) { dummy = strchr(dummy1,'\t'); // set dummy on first tab or space which ever's nearer if (dummy == NULL) { dummy = strchr(dummy1, ' '); // if not found seek for space while ((dummy != NULL) && ((*dummy == '\t') || (*dummy == ' '))) // skip some more tabs and spaces if necessary dummy++; } if (dummy == NULL) { dummy = strchr(dummy1, '\n'); // set on line end then (whole line = keyword) //fprintf(stderr,"Error: Cannot find tabs or spaces on line %i in search for %s\n", line, name); //Error(FileOpenParams, NULL); } else { if (verbose) fprintf(stderr,"found tab at line %i at position %li\n",FileBuffer->CurrentLine, (char *)dummy-(char *)dummy1); } } else dummy = dummy1; // ... and check if it is the keyword! //fprintf(stderr,"name %p, dummy %i/%c, dummy1 %i/%c, strlen(name) %i\n", &name, dummy, *dummy, dummy1, *dummy1, strlen(name)); if ((name == NULL) || (((dummy-dummy1 >= 3) && (strncmp(dummy1, name, strlen(name)) == 0)) && ((unsigned int)(dummy-dummy1) == strlen(name)))) { found++; // found the parameter! if (verbose) fprintf(stderr,"found %s at line %i between %li and %li\n", name, FileBuffer->CurrentLine, (unsigned long)dummy1, (unsigned long)dummy); if (found == repetition) { for (i=0;i= grid) { // grid structure means that grid starts on the next line, not right after keyword dummy1 = dummy = NULL; do { dummy1 = FileBuffer->buffer[ FileBuffer->LineMapping[ FileBuffer->CurrentLine++] ]; if (FileBuffer->CurrentLine >= FileBuffer->NoLines) { if ((critical) && (found == 0)) { //Error(InitReading, name); fprintf(stderr,"Error:InitReading, critical %s not found\n", name); exit(255); } else { //fprintf(stdout,"Rewinding to OldCurrentLine due to search till end of line.\n"); FileBuffer->CurrentLine = OldCurrentLine; // rewind to start position return 0; } } if (dummy1 == NULL) { if (verbose) fprintf(stderr,"Error reading line %i\n", FileBuffer->CurrentLine); } else { if (verbose) fprintf(stderr,"Reading next line %i: %s\n", FileBuffer->CurrentLine, dummy1); } //FileBuffer->CurrentLine++; } while ((dummy1 != NULL) && ((dummy1[0] == '#') || (dummy1[0] == '\n'))); dummy = dummy1; } else { // simple int, strings or doubles start in the same line while ((*dummy == '\t') || (*dummy == ' ')) // skip interjacent tabs and spaces dummy++; } for (j=((type >= grid) ? 0 : yth-1);j j) && (type == upper_trigrid)) || ((j > i) && (type == lower_trigrid))) { *((double *)value) = 0.0; fprintf(stderr,"%f\t",*((double *)value)); value = (void *)((long)value + sizeof(double)); //value += sizeof(double); } else { // otherwise we must skip all interjacent tabs and spaces and find next value dummy1 = dummy; dummy = strchr(dummy1, '\t'); // seek for tab or space if (dummy == NULL) dummy = strchr(dummy1, ' '); // if not found seek for space if (dummy == NULL) { // if still zero returned ... dummy = strchr(dummy1, '\n'); // ... at line end then if ((j < yth-1) && (type < 4)) { // check if xth value or not yet if (critical) { if (verbose) fprintf(stderr,"Error: EoL at %i and still missing %i value(s) for parameter %s\n", FileBuffer->CurrentLine, yth-j, name); //return 0; exit(255); //Error(FileOpenParams, NULL); } else { if (!sequential) { // here we need it! //fprintf(stdout,"Rewinding to OldCurrentLine due to end of line and sequential %d.\n", sequential); FileBuffer->CurrentLine = OldCurrentLine; // rewind to start position } return 0; } } } else { if (verbose) fprintf(stderr,"found tab at line %i at position %li\n",FileBuffer->CurrentLine, (char *)dummy-(char *)free_dummy); } if (*dummy1 == '#') { // found comment, skipping rest of line //if (verbose) fprintf(stderr,"Error: '#' at %i and still missing %i value(s) for parameter %s\n", line, yth-j, name); if (!sequential) { // here we need it! //fprintf(stdout,"Rewinding to OldCurrentLine due to comment and sequential %d.\n", sequential); FileBuffer->CurrentLine = OldCurrentLine; // rewind to start position } return 0; } if (verbose) fprintf(stderr,"value from %li to %li\n",(char *)dummy1-(char *)free_dummy,(char *)dummy-(char *)free_dummy); switch(type) { case (row_int): *((int *)value) = atoi(dummy1); if ((verbose) && (i==0) && (j==0)) fprintf(stderr,"%s = ", name); if (verbose) fprintf(stderr,"%i\t",*((int *)value)); value = (void *)((long)value + sizeof(int)); //value += sizeof(int); break; case(row_double): case(grid): case(lower_trigrid): case(upper_trigrid): *((double *)value) = atof(dummy1); if ((verbose) && (i==0) && (j==0)) fprintf(stderr,"%s = ", name); if (verbose) fprintf(stderr,"%lg\t",*((double *)value)); value = (void *)((long)value + sizeof(double)); //value += sizeof(double); break; case(double_type): *((double *)value) = atof(dummy1); if ((verbose) && (i == xth-1)) fprintf(stderr,"%s = %lg\n", name, *((double *) value)); //value += sizeof(double); break; case(int_type): *((int *)value) = atoi(dummy1); if ((verbose) && (i == xth-1)) fprintf(stderr,"%s = %i\n", name, *((int *) value)); //value += sizeof(int); break; default: case(string_type): if (value != NULL) { //if (maxlength == -1) maxlength = strlen((char *)value); // get maximum size of string array maxlength = MAXSTRINGSIZE; length = maxlength > (dummy-dummy1) ? (dummy-dummy1) : maxlength; // cap at maximum strncpy((char *)value, dummy1, length); // copy as much ((char *)value)[length] = '\0'; // and set end marker if ((verbose) && (i == xth-1)) fprintf(stderr,"%s is '%s' (%i chars)\n",name,((char *) value), length); //value += sizeof(char); } else { } break; } } while (*dummy == '\t') dummy++; } } } } } if ((type >= row_int) && (verbose)) fprintf(stderr,"\n"); if (!sequential) { //fprintf(stdout,"Rewinding to OldCurrentLine due to sequential %d.\n", sequential); FileBuffer->CurrentLine = OldCurrentLine; // rewind to start position } if (verbose) fprintf(stderr, "End of Parsing for %s\n\n",name); return (found); // true if found, false if not } /** Loads a molecule from a ConfigFileBuffer. * \param *mol molecule to load * \param *FileBuffer ConfigFileBuffer to use * \param *periode periodentafel for finding elements * \param FastParsing whether to parse trajectories or not */ void LoadMolecule(molecule * const &mol, struct ConfigFileBuffer * const &FileBuffer, const periodentafel * const periode, const bool FastParsing) { int MaxTypes = 0; const element *elementhash[MAX_ELEMENTS]; char name[MAXSTRINGSIZE]; int Z = -1; int No[MAX_ELEMENTS]; int verbose = DoLog(4); double value[3]; if (mol == NULL) { ELOG(0, "Molecule is not allocated in LoadMolecule(), exit."); performCriticalExit(); } ParseForParameter(verbose,FileBuffer,"MaxTypes", 0, 1, 1, int_type, &(MaxTypes), 1, critical); if (MaxTypes == 0) { ELOG(1, "There are no atoms according to MaxTypes in this config file." << endl); //performCriticalExit(); } else { // prescan number of ions per type LOG(0, "STATUS: Prescanning ions per type: " << endl); int NoAtoms = 0; for (int i=0; i < MaxTypes; i++) { sprintf(name,"Ion_Type%i",i+1); ParseForParameter(verbose,FileBuffer, (const char*)name, 0, 1, 1, int_type, &No[i], 1, critical); ParseForParameter(verbose,FileBuffer, name, 0, 2, 1, int_type, &Z, 1, critical); elementhash[i] = periode->FindElement(Z); LOG(1, i << ". Z = " << elementhash[i]->getAtomicNumber() << " with " << No[i] << " ions."); NoAtoms += No[i]; } int repetition = -1; // which repeated keyword shall be read // sort the lines via the LineMapping sprintf(name,"Ion_Type%i",MaxTypes); if (!ParseForParameter(verbose,FileBuffer, (const char*)name, 1, 1, 1, int_type, &value[0], 1, critical)) { ELOG(0, "There are no atoms in the config file!" << endl); performCriticalExit(); return; } FileBuffer->CurrentLine++; // skip to next line FileBuffer->MapIonTypesInBuffer(NoAtoms); for (int i=FileBuffer->CurrentLine; iNoLines;++i) { LOG(4, FileBuffer->buffer[ FileBuffer->LineMapping[i] ]); } map AtomList[MaxTypes]; map LinearList; atom *neues = NULL; Vector tempVector; int _fixedion; typedef boost::tokenizer > tokenizer; boost::char_separator sep("\t "); ConvertTo toDouble; ConvertTo toInt; for (int i=0; i < MaxTypes; i++) { for(int j=0;jbuffer[ FileBuffer->LineMapping[FileBuffer->CurrentLine] ]); const std::string line_without_comment = line.substr(0,line.find("#")); tokenizer tokens(line_without_comment, sep); if (tokens.begin() != tokens.end()) { tokenizer::iterator tok_iter = tokens.begin(); const std::string token = *tok_iter++; if (token == keyword) { LOG(3, "INFO: Found keyword " << keyword << " in line " << FileBuffer->CurrentLine << std::endl); if (step == 0) { neues = World::getInstance().createAtom(); AtomList[i][j] = neues; LOG(4, "Filling LinearList [ (FileBuffer->LineMapping[" << FileBuffer->CurrentLine << "]) = " << FileBuffer->LineMapping[FileBuffer->CurrentLine] << " with " << neues << endl); LinearList[ FileBuffer->LineMapping[FileBuffer->CurrentLine] ] = neues; neues->setType(elementhash[i]); // find element type } else neues = AtomList[i][j]; // count tokens size_t tokens_size = 0; for (tokenizer::iterator tokiter = tokens.begin(); tokiter != tokens.end(); ++tokiter) ++tokens_size; LOG(3, "INFO: Line contains " << tokens_size << " tokens." << std::endl); // and parse tempVector.Zero(); if (tokens_size >= 5) { // only AtomicPosition and FixedIon for (int i=0;isetPositionAtStep(step, tempVector); _fixedion = toInt(*tok_iter++); neues->setFixedIon(_fixedion == 1); LOG(3, "INFO: Parsing AtomicPosition " << tempVector << " and FixedIon " << _fixedion << "." << std::endl); } tempVector.Zero(); if (tokens_size >= 8) { // AtomicVelocity for (int i=0;isetAtomicVelocityAtStep(step, tempVector); tempVector.Zero(); if (tokens_size >= 11) { // AtomicForce LOG(3, "INFO: Parsing AtomicForce" << std::endl); for (int i=0;isetAtomicForceAtStep(step, tempVector); std::stringstream output; output << "Parsed position of step " << (step+1) << ": "; output << neues->getPositionAtStep(step); // next step output << "\t"; output << (neues->getFixedIon() ? "true" : "false"); output << "\t"; output << neues->getAtomicVelocityAtStep(step); // next step output << "\t"; output << neues->getAtomicForceAtStep(step); // next step LOG(2, output.str()); step++; } else { if ((repetition > step) || (repetition == -1)) repetition = step; break; } } FileBuffer->CurrentLine++; } } } if (repetition <= 1) // if onyl one step, desactivate use of trajectories mol->MDSteps = 0; else { LOG(0, "Found " << repetition << " trajectory step(s)."); mol->MDSteps = repetition; } // put atoms into the molecule in their original order for(map::iterator runner = LinearList.begin(); runner != LinearList.end(); ++runner) { mol->AddAtom(runner->second); } } }