// *********************** GENERATED BY RAGEL 6.0 ******************* // ** Do not edit directly. Edit NanorexMMPImportExport.rl instead ** // ****************************************************************** // Copyright 2008 Nanorex, Inc. See LICENSE file for details. #include "NanorexMMPImportExport.h" #include #include #include #define VERBOSE #if defined(VERBOSE) #if 0 #define CDEBUG(s) DEBUG_MSG(inputFilename, lineNum, s) inline void DEBUG_MSG(string const& filename, int line, string const& s) { NXLOG_DEBUG(filename, NXUtility::itos(line)+": "+s); /* Nanorex::NXLogger* logger = Nanorex::NXLogger::Instance(); if (logger != 0) logger->log(Nanorex::NXLogLevel_Info, filename, msg.str());*/ } #endif #define CERR(s) { cerr << inputFilename << ": " << NXUtility::itos(lineNum) \ << ": " << s << endl; } // #define CDEBUG(s) NXLOG_DEBUG(inputFilename, NXUtility::itos(lineNum)+": "+s) #define CDEBUG(s) { cerr << inputFilename << ": " << NXUtility::itos(lineNum) \ << ": " << s << endl; } #define CLOG(s) NXLOG_INFO(inputFilename, NXUtility::itos(lineNum)+": "+s) #else #define CDEBUG(s) #define CLOG(s) #endif #define CSEVERE(s) NXLOG_SEVERE(inputFilename, NXUtility::itos(lineNum)+": "+s) %%{ # Ragel fsm machine mmp_parser; include group "group.rl"; mmpformat_line = 'mmpformat' nonNEWLINEspace+ digit{6} nonNEWLINEspace+ 'required' nonNEWLINEspace* ( ';' nonNEWLINEspace+ digit{6} nonNEWLINEspace+ 'preferred' )? nonNEWLINEspace* EOL; kelvin_line = 'kelvin' nonNEWLINEspace+ whole_number % { kelvinTemp = intVal; } nonNEWLINEspace* EOL; end_line = 'end' nonNEWLINEspace+; main := (nonNEWLINEspace* EOL)* mmpformat_line WHITESPACE* ( kelvin_line WHITESPACE* )? group_view_data_stmt_begin_line @ { fhold; fcall group_scanner; } WHITESPACE* group_mol_struct_stmt_begin_line @ { fhold; fcall group_scanner; } WHITESPACE* end1_line WHITESPACE* group_clipboard_stmt_begin_line @ { fhold; fcall group_scanner; } WHITESPACE* end_line any* ; # dynamic stack re-sizing prepush { cerr << "Ragel stack prepush: top = " << top << ", stackSize = " << stackSize << endl; if(top == stackSize) { stackSize += stackSize; stack.resize(stackSize, 0); cerr << "Resized stack to " << stackSize << endl; } } }%% %% # Ragel FSM data // static data from Ragel %% write data; // static data from class NanorexMMPImportExport char const NanorexMMPImportExport::_s_bondOrderString[NUM_BOND_TYPES] = { '1', '2', '3', 'a', 'g', 'c' }; char const NanorexMMPImportExport::_s_bondOrderNameString[NUM_BOND_TYPES][16] = { "single", "double", "triple", "aromatic", "graphitic", "carbomeric" }; char const NanorexMMPImportExport::_s_hybridizationName[8][8] = { "none", "sp", "sp2", "sp3", "X-hyb4", "X-hyb5", "X-hyb6", "X-hyb7" }; /*static*/ void NanorexMMPImportExport::SetResult(NXCommandResult& commandResult, int errCode, string const& errMsg) { commandResult.setResult(errCode); vector message; message.push_back(QObject::tr(errMsg.c_str())); commandResult.setParamVector(message); } // ............................................................................. /* static */ void NanorexMMPImportExport::ClearResult(NXCommandResult& commandResult) { commandResult.setResult((int) NX_CMD_SUCCESS); vector message; commandResult.setParamVector(message); } /* CONSTRUCTOR */ NanorexMMPImportExport::NanorexMMPImportExport() { reset(); } /* DESTRUCTOR */ NanorexMMPImportExport::~NanorexMMPImportExport() { } /* FUNCTION: reset */ void NanorexMMPImportExport::reset(void) { inputFilename.clear(); dataStoreInfo = (NXDataStoreInfo*) NULL; lineNum = 0; insideViewDataGroup = false; insideClipboardGroup = false; atomPtr = NULL; bondPtr = NULL; foundAtomList.clear(); targetAtomList.clear(); molPtr = NULL; molSetPtr = NULL; molSetPtrStack.clear(); molStyle = "def"; clipboardGroup = NULL; // defaultAtomStyle = "def"; // defaultAtomStyleStack.clear(); // ragel stack stackSize = 2; stack.clear(); stack.resize(stackSize, 0); // initialize the ragel engine %% write init; } /* FUNCTION: importFromFile */ NXCommandResult* NanorexMMPImportExport:: importFromFile(NXMoleculeSet *rootMoleculeSetPtr, NXDataStoreInfo *dsInfo, const std::string& theFilename, int /*frameSetId*/, int /*frameIndex*/) { reset(); bool success = true; ClearResult(commandResult); ifstream mmpfile(theFilename.c_str(), ios::in); if(!mmpfile) { populateCommandResult(&commandResult, (string("Couldn't open file: ") + theFilename) .c_str()); success = false; } else { inputFilename = theFilename; dataStoreInfo = dsInfo; success = readMMP(mmpfile, rootMoleculeSetPtr); } // Set the meta information about the data store. if (success) { dataStoreInfo->setIsSingleStructure(true); } return &commandResult; } /* FUNCTION: readMMP */ bool NanorexMMPImportExport::readMMP(istream& instream, NXMoleculeSet *rootMoleculeSetPtr) { p = RagelIstreamPtr(instream); pe = RagelIstreamPtr(instream, 0, ios::end); eof = pe; this->rootMoleculeSetPtr = rootMoleculeSetPtr; molSetPtr = NULL; // molSetPtrStack.push(molSetPtr); /// @todo handle first 'group' statement and molSetPtrStack initialization // Ragel parser implementation bool success = true; %% write exec; // End-of-parsing sanity checks if(molSetPtrStack.size() != 0) { NXLOG_WARNING("NanorexMMPImportExport", "At least one group has no matching egroup statement"); } return success; } /* FUNCTION newAtom */ void NanorexMMPImportExport::newAtom(int id, int atomicNum, int x, int y, int z, string const& style) { if(molPtr == NULL) { CSEVERE("No parent molecule for atom"); return; } // error if id was previously specified map::const_iterator atomExistsQuery = foundAtomList.find(id); if(atomExistsQuery != foundAtomList.end()) { NXLOG_SEVERE("NanorexMMPImportExport", "Atom-id " + NXUtility::itos(id) + " is repeated"); return; } atomPtr = molPtr->NewAtom(); /// @note OpenBabel assigns atomicNum to a 'char' variable so modulo 256 atomPtr->SetAtomicNum(atomicNum); /// @todo set implicit valence based on role (axis, strand etc) if(atomicNum >= 200) atomPtr->SetImplicitValence(4); NXAtomData *atomDataPtr = new NXAtomData(atomicNum); atomDataPtr->setIdx(id); atomDataPtr->setRenderStyleCode(style); assert(atomDataPtr->GetDataType() == NXAtomDataType); atomPtr->SetData(atomDataPtr); // atomic number assert(atomPtr->HasData(NXAtomDataType)); // convert to Angstroms double const LENGTH_SCALE = 1.0e-3; atomPtr->SetVector(double(x) * LENGTH_SCALE, double(y) * LENGTH_SCALE, double(z) * LENGTH_SCALE); foundAtomList[id] = atomPtr; bondPtr = NULL; CDEBUG("atom " + NXUtility::itos(atomId) + " (" + NXUtility::itos(atomicNum) + ") (" + NXUtility::itos(x) + ',' + NXUtility::itos(y) + ',' + NXUtility::itos(z) + ") " + atomStyle); } /* FUNCTION: newAtomInfo*/ void NanorexMMPImportExport::newAtomInfo(string const& key, string const& value) { if(insideViewDataGroup) return; if(atomPtr != NULL) { if(key == "atomtype") { // hybridization info if(value == "sp") atomPtr->SetHyb(1); else if(value == "sp2") atomPtr->SetHyb(2); else if(value == "sp2_g") atomPtr->SetHyb(2); else if(value == "sp3") atomPtr->SetHyb(3); else if(value == "sp3d") atomPtr->SetHyb(3); // else ignore } } CDEBUG("info atom '" + key + "' = '" + value + "'"); } /* FUNCTION: newBond */ void NanorexMMPImportExport::newBond(string const& bondType, int targetAtomId) { if(insideViewDataGroup) return; assert(molPtr != NULL && atomPtr != NULL); map::iterator targetAtomExistsQuery = foundAtomList.find(targetAtomId); if(targetAtomExistsQuery == foundAtomList.end()) { CSEVERE("**ERROR** attempting to bond to non-existent atomID " + NXUtility::itos(targetAtomId)); } else { OBAtom *const targetAtomPtr = targetAtomExistsQuery->second; // guard against duplicates // also a hack to protect against Ragel's duplicate parsing // when encountering a blank line if(molPtr->GetBond(atomPtr, targetAtomPtr) == NULL) { // bond was not previously encountered, include int atomId = ((NXAtomData*)(atomPtr->GetData(NXAtomDataType)))->getIdx(); CDEBUG("bonding atom #" + NXUtility::itos(atomId) + " to atom #" + NXUtility::itos(targetAtomId)); bondPtr = molPtr->NewBond(); bondOrder = GetBondOrderFromType(bondType); bondPtr->SetBondOrder(bondOrder); atomPtr->AddBond(bondPtr); targetAtomPtr->AddBond(bondPtr); bondPtr->SetBegin(atomPtr); bondPtr->SetEnd(targetAtomPtr); CDEBUG("bond" + bondType + " " + NXUtility::itos(targetAtomId)); } else { CSEVERE("bond to atom #" + NXUtility::itos(targetAtomId) + " already exists"); } } } /* FUNCTION: GetBondOrderFromType */ int NanorexMMPImportExport::GetBondOrderFromType(string const& type) { if(type == "1") return 1; else if(type == "2") return 2; else if(type == "3") return 3; else if(type == "a") return 4; else if(type == "c") return 5; else if (type == "g") return 6; else { return -1; } } /* FUNCTION: newBondDirection */ void NanorexMMPImportExport::newBondDirection(int atomId1, int atomId2) { /// @todo Implement post-FNANO08 // no-op for FNANO08 } /* FUNCTION: newMolecule */ void NanorexMMPImportExport::newMolecule(string const& name, string const& style) { if(insideViewDataGroup) return; atomPtr = NULL; bondPtr = NULL; molPtr = molSetPtr->newMolecule(); molPtr->SetTitle(name.c_str()); if(style == "") molStyle = "def"; else molStyle = style; CDEBUG("mol (" + name + ") " + style); } /* FUNCTION: newViewDataGroup */ void NanorexMMPImportExport::newViewDataGroup(void) { insideViewDataGroup = true; CDEBUG("[special] group (View Data)"); } void NanorexMMPImportExport:: newNamedView(std::string const& name, double const& qw, double const& qx, double const& qy, double const& qz, double const& scale, double const& povX, double const& povY, double const& povZ, double const& zoomFactor) { // No need to convert to Angstroms - already NV1's internal units double const TO_ANG = 1.0 /*1.0e-10*/; if(insideViewDataGroup) { NXNamedView view(name, NXQuaternion(qw, qx*TO_ANG, qy*TO_ANG, qz*TO_ANG), scale*TO_ANG, NXVector3d(povX*TO_ANG, povY*TO_ANG, povZ*TO_ANG), zoomFactor); if(name == "HomeView") dataStoreInfo->setHomeView(view); else if(name == "LastView") dataStoreInfo->setLastView(view); else dataStoreInfo->addOtherView(view); } CDEBUG("csys (" + name + ") " + '(' + NXUtility::dtos(qw) + ',' + NXUtility::dtos(qx) + ',' + NXUtility::dtos(qz) + ',' + NXUtility::dtos(qz) + ") " + '(' + NXUtility::dtos(scale) + ") " + '(' + NXUtility::dtos(povX) + ',' + NXUtility::dtos(povY) + ',' + NXUtility::dtos(povZ) + ") " + '(' + NXUtility::dtos(zoomFactor) + ')'); } /* FUNCTION: newMolStructGroup */ void NanorexMMPImportExport::newMolStructGroup(string const& name, string const& classification) { // if(insideClipboardGroup && molSetPtr == NULL) { // // no active top-level group // molSetPtr = new NXMoleculeSet; // molSetPtr->setTitle(name); // // dataStoreInfo->addClipboardStructure(molSetPtr); // } // if in "View Data" group, ignore // if(molSetPtr != NULL) { /*else*/ if(!insideViewDataGroup) { // if in principal molecule-set group or active clipboard group if(molSetPtr == NULL) { // must be inside principal structure group assert(!insideClipboardGroup); molSetPtr = rootMoleculeSetPtr; } // else if(!insideClipboardGroup && molSetPtr == NULL) { // // entering principal structure group // // all changes should go to supplied pointer // molSetPtr = rootMoleculeSetPtr; // } else { // If not at top-level inside principal structure group or // clipboard group, allocate new structure NXMoleculeSet *newMolSetPtr = new NXMoleculeSet; molSetPtr->addChild(newMolSetPtr); molSetPtrStack.push_back(molSetPtr); molSetPtr = newMolSetPtr; } molSetPtr->setTitle(name); molSetPtr->setGroupClassificationString(classification); } // ++molStructGroupLevel; CDEBUG("group (" + name + ") " + classification); } /* FUNCTION: newClipboardGroup */ void NanorexMMPImportExport::newClipboardGroup(void) { assert(molSetPtr == NULL); assert(molSetPtrStack.size() == 0); if(!insideClipboardGroup && clipboardGroup == (NXMoleculeSet*) NULL) { clipboardGroup = new NXMoleculeSet; clipboardGroup->setTitle("Clipboard"); molSetPtr = clipboardGroup; insideClipboardGroup = true; dataStoreInfo->setClipboardStructure(clipboardGroup); CDEBUG("[special] group (Clipboard)"); } else { CSEVERE("Redefinition of 'Clipboard' group"); } } /* FUNCTION: endGroup */ void NanorexMMPImportExport::endGroup(string const& name) { // Must ensure that molSetPtr = NULL between top-level structure groups // Top-level structure groups are defined as the principal structure group // that occurs between the "View Data" and the "Clipboard" groups in the MMP // file, and those from various top-level 'group' statements in the // "Clipboard" group string groupName; if(insideViewDataGroup) groupName = "View Data"; else if(insideClipboardGroup) groupName = (molSetPtr == NULL) ? "Clipboard" : molSetPtr->getTitle(); else groupName = molSetPtr->getTitle(); if(name != groupName) { NXLOG_WARNING("NanorexMMPImportExport", "egroup (" + name + ") attempting to close " "group (" + groupName + ')'); } if(insideViewDataGroup) { insideViewDataGroup = false; molSetPtr = NULL; } else { // non top-level structure groups in clipboard or in the // principal structure group if(molSetPtrStack.size() == 0) { molSetPtr = NULL; if(insideClipboardGroup) insideClipboardGroup = false; } else { molSetPtr = molSetPtrStack.back(); molSetPtrStack.pop_back(); } } CDEBUG("egroup (" + groupName + ')'); } /* FUNCTION: newOpenGroupInfo */ void NanorexMMPImportExport::newOpenGroupInfo(std::string const& key, std::string const& value) { /// @todo CDEBUG("info opengroup " + key + " = " + value); } /* FUNCTION: newChunkInfo */ void NanorexMMPImportExport::newChunkInfo(std::string const& key, std::string const& value) { CDEBUG("info chunk " + key + " = " + value); if(insideViewDataGroup) return; /// @todo } /* FUNCTION: end1 */ void NanorexMMPImportExport::end1(void) { /// @todo CDEBUG("end1"); } /* FUNCTION: exportToFile */ NXCommandResult* NanorexMMPImportExport:: exportToFile(NXMoleculeSet *molSetPtr, NXDataStoreInfo */*dataStoreInfo*/, const std::string& theFilename, int /*frameSetId*/, int /*frameIndex*/) { NXCommandResult *result = new NXCommandResult(); result->setResult(NX_CMD_SUCCESS); ofstream mmpfile(theFilename.c_str(), ios::out); if(!mmpfile) { populateCommandResult(result, (string("Couldn't open file: ") + theFilename) .c_str()); } else { PrintMoleculeSet(mmpfile, molSetPtr); mmpfile.close(); } return result; } /* FUNCTION: GetAtomID */ /* static */ int NanorexMMPImportExport::GetAtomID(OBAtom *atomPtr) { NXAtomData *atomIDData = dynamic_cast(atomPtr->GetData(NXAtomDataType)); int atomID = atomIDData->getIdx(); return atomID; } /* FUNCTION: GetAtomRenderStyleCode */ /* static */ string const& NanorexMMPImportExport::GetAtomRenderStyleCode(OBAtom *const atomPtr) { NXAtomData *atomDataPtr = dynamic_cast(atomPtr->GetData(NXAtomDataType)); string const& atomStyle = atomDataPtr->getRenderStyleCode(); return atomStyle; } /* FUNCTION: PrintMolecule */ /* static */ void NanorexMMPImportExport::PrintMolecule(ostream& o, OBMol *const molPtr) { set prevAtomIdx; set prevBondIdx; /// @todo - replace with simple bond count o << "mol (" << molPtr->GetTitle() << ')' << endl; OBAtomIterator atomIter; OBAtom *atomPtr = NULL; // For each atom ... for(atomPtr = molPtr->BeginAtom(atomIter); atomPtr != NULL; atomPtr = molPtr->NextAtom(atomIter)) { // ... write the 'atom' line ... int atomID = GetAtomID(atomPtr); o << "atom " << atomID << " (" << atomPtr->GetAtomicNum() << ") " << '(' << atomPtr->x() << ',' << atomPtr->y() << ',' << atomPtr->z() << ") " << GetAtomRenderStyleCode(atomPtr) << endl; if(atomPtr->GetHyb() != 0) { o << "info atom atomtype = " << _s_hybridizationName[atomPtr->GetHyb()]; } // ... write the 'bond' lines for this atom ... // ... first sort bonds by type ... OBBondIterator bondIter; OBBond *bondPtr = NULL; vector bondCategories[6]; for(bondPtr = atomPtr->BeginBond(bondIter); bondPtr != NULL; bondPtr = atomPtr->NextBond(bondIter)) { // write bond statement only if target atom was previously written OBAtom *nbrAtomPtr = bondPtr->GetNbrAtom(atomPtr); int nbrAtomID = GetAtomID(nbrAtomPtr); if(prevAtomIdx.find(nbrAtomID) != prevAtomIdx.end()) { int bondOrder = bondPtr->GetBondOrder(); bondCategories[bondOrder-1].push_back(nbrAtomID); // record bond for sanity check at end prevBondIdx.insert(bondPtr->GetIdx()); } } // ... write the bonds, one line per type ... for(int i=0; i<6; ++i) { int J = bondCategories[i].size(); if(J > 0) { o << "bond" << _s_bondOrderString[i]; for(int j=0; jNumAtoms() == prevAtomIdx.size()) debugMsg << "PASS (" << molPtr->NumAtoms() << ')' << endl; else debugMsg << "FAIL: " << molPtr->NumAtoms() << " != " << prevAtomIdx.size()<< endl; debugMsg << "# bonds check "; if(molPtr->NumBonds() == prevBondIdx.size()) debugMsg << "PASS (" << molPtr->NumBonds() << ')' << endl; else debugMsg << "FAIL: " << molPtr->NumBonds() << " != " << prevBondIdx.size()<< endl; debugMsg.flush(); NXLOG_DEBUG("NanorexMMPImportExport::PrintMoleculeSet", debugMsg.str().c_str()); } /* FUNCTION: PrintMoleculeSet */ /* static */ void NanorexMMPImportExport::PrintMoleculeSet(ostream& o, NXMoleculeSet *const molSetPtr) { // Iterate over all child molecules OBMolIterator molIter; for(molIter = molSetPtr->moleculesBegin(); molIter != molSetPtr->moleculesEnd(); ++molIter) { PrintMolecule(o, *molIter); } // Iterate over all child molecule sets NXMoleculeSetIterator molSetIter; for(molSetIter = molSetPtr->childrenBegin(); molSetIter != molSetPtr->childrenEnd(); ++molSetIter) { PrintMoleculeSet(o, *molSetIter); } } /* FUNCTION: populateCommandResult */ void NanorexMMPImportExport::populateCommandResult (NXCommandResult* result, const string& message) { result->setResult(NX_PLUGIN_REPORTS_ERROR); vector resultVector; resultVector.push_back("OpenBabelImportExport"); resultVector.push_back(message.c_str()); result->setParamVector(resultVector); } Q_EXPORT_PLUGIN2 (NanorexMMPImportExport, NanorexMMPImportExport)