bool OpCanonical::Do(OBBase* pOb, const char* OptionText, OpMap* pOptions, OBConversion* pConv) { OBMol* pmol = dynamic_cast<OBMol*>(pOb); if(!pmol) return false; std::vector<OBAtom*> atoms; FOR_ATOMS_OF_MOL (atom, pmol) atoms.push_back(&*atom); std::vector<unsigned int> symmetry_classes; OBGraphSym gs(pmol); gs.GetSymmetry(symmetry_classes); std::vector<unsigned int> canon_labels; CanonicalLabels(pmol, symmetry_classes, canon_labels); std::vector<OBAtom*> newatoms(atoms.size(), 0); for (std::size_t i = 0; i < canon_labels.size(); ++i) newatoms[canon_labels[i]-1] = atoms[i]; pmol->RenumberAtoms(newatoms); return true; }
void OBUnitCell::FillUnitCell(OBMol *mol) { const SpaceGroup *sg = GetSpaceGroup(); // the actual space group and transformations for this unit cell // For each atom, we loop through: convert the coords back to inverse space, apply the transformations and create new atoms vector3 uniqueV, newV, updatedCoordinate; list<vector3> transformedVectors; // list of symmetry-defined copies of the atom list<vector3>::iterator transformIterator, duplicateIterator; OBAtom *newAtom; list<OBAtom*> atoms; // keep the current list of unique atoms -- don't double-create list<vector3> coordinates; // all coordinates to prevent duplicates bool foundDuplicate; FOR_ATOMS_OF_MOL(atom, *mol) atoms.push_back(&(*atom)); list<OBAtom*>::iterator i; for (i = atoms.begin(); i != atoms.end(); ++i) { uniqueV = (*i)->GetVector(); uniqueV = CartesianToFractional(uniqueV); uniqueV = WrapFractionalCoordinate(uniqueV); coordinates.push_back(uniqueV); transformedVectors = sg->Transform(uniqueV); for (transformIterator = transformedVectors.begin(); transformIterator != transformedVectors.end(); ++transformIterator) { // coordinates are in reciprocal space -- check if it's in the unit cell // if not, transform it in place updatedCoordinate = WrapFractionalCoordinate(*transformIterator); foundDuplicate = false; // Check if the transformed coordinate is a duplicate of an atom for (duplicateIterator = coordinates.begin(); duplicateIterator != coordinates.end(); ++duplicateIterator) { if (areDuplicateAtoms(*duplicateIterator, updatedCoordinate)) { foundDuplicate = true; break; } } if (foundDuplicate) continue; coordinates.push_back(updatedCoordinate); // make sure to check the new atom for dupes newAtom = mol->NewAtom(); newAtom->Duplicate(*i); newAtom->SetVector(FractionalToCartesian(updatedCoordinate)); } // end loop of transformed atoms (*i)->SetVector(FractionalToCartesian(uniqueV)); // move the atom back into the unit cell } // end loop of atoms SetSpaceGroup(1); // We've now applied the symmetry, so we should act like a P1 unit cell }
bool OBFunction::Setup(/*const*/ OBMol &mol) { m_positions.resize(mol.NumAtoms()); FOR_ATOMS_OF_MOL (atom, mol) m_positions[atom->GetIdx()-1] = Eigen::Vector3d(atom->GetVector().AsArray()); m_gradients.resize(mol.NumAtoms(), Eigen::Vector3d::Zero()); std::vector<OBFunctionTerm*>::iterator term; for (term = m_terms.begin(); term != m_terms.end(); ++term) if (!(*term)->Setup()) return false; return true; }
bool OpFillUC::Do(OBBase* pOb, const char* OptionText, OpMap* pOptions, OBConversion* pConv) { OBMol* pmol = dynamic_cast<OBMol*>(pOb); if(!pmol) return false; if (!(pmol->HasData(OBGenericDataType::UnitCell))) { obErrorLog.ThrowError(__FUNCTION__, "Cannot fill unit cell without a unit cell !" , obWarning); return false; } OBUnitCell *pUC = (OBUnitCell*)pmol->GetData(OBGenericDataType::UnitCell); const SpaceGroup* pSG = pUC->GetSpaceGroup(); if (pSG == NULL) { obErrorLog.ThrowError(__FUNCTION__, "Cannot fill unit cell without spacegroup information !" , obWarning); return false; } // Now loop over all symmetry operations, and generate symmetric atoms one at a time // Avoid creating overlapping atoms (duplicate), and bring back atoms within the unit cell // using two options: // "--fillUC strict": keep only atoms that are strictly inside the unit cell // (fractionnal coordinates 0<= <1) // "--fillUC keepconnect": generate symmetrics of the molecule, and translate // it back in the unit cell if necessary std::map<OBAtom*,std::vector<vector3> > vatoms;// key: original atoms, value=all generated symmetrics FOR_ATOMS_OF_MOL(atom, *pmol) vatoms[&(*atom)]=std::vector<vector3>(); for(std::map<OBAtom*,std::vector<vector3> >:: iterator atom=vatoms.begin(); atom!=vatoms.end();++atom){ vector3 orig = atom->first->GetVector(); orig = pUC->CartesianToFractional(orig);// To fractionnal coordinates // Loop over symmetry operators transform3dIterator ti; const transform3d *t = pSG->BeginTransform(ti); while(t){ atom->second.push_back ( (transform3d)(*t) * orig); t = pSG->NextTransform(ti); } } if(0==strncasecmp(OptionText, "keepconnect", 11)){ // First, bring back all symmetrical molecules back in the UC for(unsigned int i=0;i<vatoms.begin()->second.size();++i){ vector3 ccoord(0,0,0);//geometrical center for(std::map<OBAtom*,std::vector<vector3> >:: iterator atom=vatoms.begin(); atom!=vatoms.end();++atom){ ccoord+=atom->second[i]; } ccoord/=vatoms.size(); ccoord=transformedFractionalCoordinate2(ccoord)-ccoord; for(std::map<OBAtom*,std::vector<vector3> >:: iterator atom=vatoms.begin(); atom!=vatoms.end();++atom){ atom->second[i]+=ccoord; } } // Now add atoms that are not duplicates for(std::map<OBAtom*,std::vector<vector3> >:: iterator atom=vatoms.begin(); atom!=vatoms.end();++atom){ for(unsigned int i=1;i<atom->second.size();++i){ bool foundDuplicate = false; for(unsigned int j=0;j<i;++j){ if(atom->second[i].distSq(atom->second[j])<1e-4){ foundDuplicate=true; break; } } if(!foundDuplicate){ OBAtom *newAtom = pmol->NewAtom(); newAtom->Duplicate(atom->first); newAtom->SetVector( pUC->FractionalToCartesian(atom->second[i])); } } } } else{ if(0!=strncasecmp(OptionText, "strict", 6)) obErrorLog.ThrowError(__FUNCTION__, "fillUC: lacking \"strict\n or \"keepconnect\" option, using strict" , obWarning); for(std::map<OBAtom*,std::vector<vector3> >:: iterator atom=vatoms.begin(); atom!=vatoms.end();++atom){ // Bring back within unit cell for(unsigned int i=0;i<atom->second.size();++i){ atom->second[i]=transformedFractionalCoordinate2(atom->second[i]); } for(unsigned int i=1;i<atom->second.size();++i){ bool foundDuplicate = false; for(unsigned int j=0;j<i;++j){ if(atom->second[i].distSq(atom->second[j])<1e-4){ foundDuplicate=true; break; } } if(!foundDuplicate){ OBAtom *newAtom = pmol->NewAtom(); newAtom->Duplicate(atom->first); newAtom->SetVector( pUC->FractionalToCartesian(atom->second[i])); } } } } // Set spacegroup to P1, since we generated all symmetrics pUC->SetSpaceGroup("P1"); /* list<vector3> transformedVectors; // list of symmetry-defined copies of the atom vector3 uniqueV, newV, updatedCoordinate; list<vector3> coordinates; // all coordinates to prevent duplicates vector3 uniqueV, newV, updatedCoordinate; list<vector3> transformedVectors; // list of symmetry-defined copies of the atom list<vector3>::iterator transformIterator, duplicateIterator; OBAtom *newAtom; list<OBAtom*> atoms; // keep the current list of unique atoms -- don't double-create list<vector3> coordinates; // all coordinates to prevent duplicates bool foundDuplicate; FOR_ATOMS_OF_MOL(atom, *mol) atoms.push_back(&(*atom)); list<OBAtom*>::iterator i; for (i = atoms.begin(); i != atoms.end(); ++i) { uniqueV = (*i)->GetVector(); uniqueV = CartesianToFractional(uniqueV); uniqueV = transformedFractionalCoordinate(uniqueV); coordinates.push_back(uniqueV); transformedVectors = sg->Transform(uniqueV); for (transformIterator = transformedVectors.begin(); transformIterator != transformedVectors.end(); ++transformIterator) { // coordinates are in reciprocal space -- check if it's in the unit cell // if not, transform it in place updatedCoordinate = transformedFractionalCoordinate(*transformIterator); foundDuplicate = false; // Check if the transformed coordinate is a duplicate of an atom for (duplicateIterator = coordinates.begin(); duplicateIterator != coordinates.end(); ++duplicateIterator) { if (duplicateIterator->distSq(updatedCoordinate) < 1.0e-4) { foundDuplicate = true; break; } } if (foundDuplicate) continue; coordinates.push_back(updatedCoordinate); // make sure to check the new atom for dupes newAtom = mol->NewAtom(); newAtom->Duplicate(*i); newAtom->SetVector(FractionalToCartesian(updatedCoordinate)); } // end loop of transformed atoms (*i)->SetVector(FractionalToCartesian(uniqueV)); } // end loop of atoms */ return true; }
void SuperCellExtension::fillCell() { /* Change coords back to inverse space, apply the space group transforms * then change coords back to real space */ if (!m_molecule) return; OBUnitCell *uc = m_molecule->OBUnitCell(); if (!uc) { qDebug() << "No unit cell found - fillCell() returning..."; return; } const SpaceGroup *sg = uc->GetSpaceGroup(); // the actual space group and transformations for this unit cell if (sg) { qDebug() << "Space group:" << sg->GetId();// << sg->GetHMName(); // We operate on a copy of the Avogadro molecule // For each atom, we loop through: // * convert the coords back to inverse space // * apply the transformations // * create new (duplicate) atoms OBMol mol = m_molecule->OBMol(); vector3 uniqueV, newV; list<vector3> transformedVectors; // list of symmetry-defined copies of the atom list<vector3>::iterator transformIterator, duplicateIterator; vector3 updatedCoordinate; bool foundDuplicate; OBAtom *addAtom; QList<OBAtom*> atoms; // keep the current list of unique atoms -- don't double-create list<vector3> coordinates; // all coordinates to prevent duplicates FOR_ATOMS_OF_MOL(atom, mol) atoms.push_back(&(*atom)); foreach(OBAtom *atom, atoms) { uniqueV = atom->GetVector(); // Assert: won't crash because we already ensure uc != NULL uniqueV = uc->CartesianToFractional(uniqueV); uniqueV = transformedFractionalCoordinate(uniqueV); coordinates.push_back(uniqueV); transformedVectors = sg->Transform(uniqueV); for (transformIterator = transformedVectors.begin(); transformIterator != transformedVectors.end(); ++transformIterator) { // coordinates are in reciprocal space -- check if it's in the unit cell // if not, transform it in place updatedCoordinate = transformedFractionalCoordinate(*transformIterator); foundDuplicate = false; // Check if the transformed coordinate is a duplicate of an atom for (duplicateIterator = coordinates.begin(); duplicateIterator != coordinates.end(); ++duplicateIterator) { if (duplicateIterator->distSq(updatedCoordinate) < 1.0e-4) { foundDuplicate = true; break; } } if (foundDuplicate) continue; coordinates.push_back(updatedCoordinate); // make sure to check the new atom for dupes addAtom = mol.NewAtom(); addAtom->Duplicate(atom); addAtom->SetVector(uc->FractionalToCartesian(updatedCoordinate)); } // end loop of transformed atoms // Put the original atom into the proper space in the unit cell too atom->SetVector(uc->FractionalToCartesian(uniqueV)); } // end loop of atoms m_molecule->setOBMol(&mol); qDebug() << "Spacegroups done..."; // Need a fresh pointer to the new unit cell - setOBMol is invalidating // the old one. This should be cleaned up to use a more permanent data // structure. uc = m_molecule->OBUnitCell(); uc->SetSpaceGroup(1); }
bool PWscfFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv) { OBMol* pmol = pOb->CastAndClear<OBMol>(); if(pmol==NULL) return false; //Define some references so we can use the old parameter names istream &ifs = *pConv->GetInStream(); char buffer[BUFF_SIZE], tag[BUFF_SIZE]; double x,y,z; double alat = 1.0; vector<string> vs; matrix3x3 ortho; int atomicNum; OBUnitCell *cell = new OBUnitCell(); bool hasEnthalpy=false; double enthalpy, pv; pmol->BeginModify(); while (ifs.getline(buffer,BUFF_SIZE)) { // Older version of pwscf may use this for alat if (strstr(buffer, "lattice parameter (a_0)")) { tokenize(vs, buffer); alat = atof(vs.at(4).c_str()); } // Newer versions will use this for alat instead if (strstr(buffer, "lattice parameter (alat)")) { tokenize(vs, buffer); alat = atof(vs.at(4).c_str()); } // Unit cell info // Newer versions will also say "CELL_PARAMETERS" to complain that no // units were specified if (strstr(buffer, "CELL_PARAMETERS") && !strstr(buffer, "no units specified in CELL_PARAMETERS card")) { // Discover units double conv = 1.0; tokenize(vs, buffer); if (strstr(vs[1].c_str(), "alat")) { conv = alat * BOHR_TO_ANGSTROM; } else if (strstr(vs[1].c_str(), "bohr")) { conv = BOHR_TO_ANGSTROM; } // Add others if needed double v11, v12, v13, v21, v22, v23, v31, v32, v33; ifs.getline(buffer,BUFF_SIZE); // v1 tokenize(vs, buffer); v11 = atof(vs.at(0).c_str()) * conv; v12 = atof(vs.at(1).c_str()) * conv; v13 = atof(vs.at(2).c_str()) * conv; ifs.getline(buffer,BUFF_SIZE); // v2 tokenize(vs, buffer); v21 = atof(vs.at(0).c_str()) * conv; v22 = atof(vs.at(1).c_str()) * conv; v23 = atof(vs.at(2).c_str()) * conv; ifs.getline(buffer,BUFF_SIZE); // v3 tokenize(vs, buffer); v31 = atof(vs.at(0).c_str()) * conv; v32 = atof(vs.at(1).c_str()) * conv; v33 = atof(vs.at(2).c_str()) * conv; // Build unit cell cell->SetData(vector3(v11,v12,v13), vector3(v21,v22,v23), vector3(v31,v32,v33)); } // Unit cell info (for non-variable cell calcs) if (strstr(buffer, "crystal axes: (cart. coord. in units of a_0)") || strstr(buffer, "crystal axes: (cart. coord. in units of alat)")) { double conv = alat * BOHR_TO_ANGSTROM; double v11, v12, v13, v21, v22, v23, v31, v32, v33; ifs.getline(buffer,BUFF_SIZE); // v1 tokenize(vs, buffer); v11 = atof(vs.at(3).c_str()) * conv; v12 = atof(vs.at(4).c_str()) * conv; v13 = atof(vs.at(5).c_str()) * conv; ifs.getline(buffer,BUFF_SIZE); // v2 tokenize(vs, buffer); v21 = atof(vs.at(3).c_str()) * conv; v22 = atof(vs.at(4).c_str()) * conv; v23 = atof(vs.at(5).c_str()) * conv; ifs.getline(buffer,BUFF_SIZE); // v3 tokenize(vs, buffer); v31 = atof(vs.at(3).c_str()) * conv; v32 = atof(vs.at(4).c_str()) * conv; v33 = atof(vs.at(5).c_str()) * conv; // Build unit cell cell->SetData(vector3(v11,v12,v13), vector3(v21,v22,v23), vector3(v31,v32,v33)); } // Atoms info if (strstr(buffer, "ATOMIC_POSITIONS")) { // Clear old atoms from pmol vector<OBAtom*> toDelete; FOR_ATOMS_OF_MOL(a, *pmol) toDelete.push_back(&*a); for (size_t i = 0; i < toDelete.size(); i++) pmol->DeleteAtom(toDelete.at(i)); // Discover units matrix3x3 conv (1); tokenize(vs, buffer); if (strstr(vs[1].c_str(), "alat")) { conv *= (alat * BOHR_TO_ANGSTROM); } else if (strstr(vs[1].c_str(), "crystal")) { // Set to the zero matrix and test below. conv = matrix3x3 (0.0); } // Add others if needed // Load new atoms from molecule ifs.getline(buffer,BUFF_SIZE); // First entry tokenize(vs, buffer); int size = vs.size(); while (size == 4) { atomicNum = OBElements::GetAtomicNum(vs[0].c_str()); x = atof((char*)vs[1].c_str()); y = atof((char*)vs[2].c_str()); z = atof((char*)vs[3].c_str()); // Add atom OBAtom *atom = pmol->NewAtom(); atom->SetAtomicNum(atomicNum); vector3 coords (x,y,z); if (conv.determinant() == 0.0) { // Fractional coords atom->SetVector(cell->FractionalToCartesian(coords)); } else { atom->SetVector(conv * coords); } // Reset vars ifs.getline(buffer,BUFF_SIZE); // First entry tokenize(vs, buffer); size = vs.size(); } } // Free energy if (strstr(buffer, "Final energy =")) { tokenize(vs, buffer); pmol->SetEnergy(atof(vs[3].c_str()) * RYDBERG_TO_KCAL_PER_MOL); } // H - PV = U energy if (strstr(buffer, "! total energy =")) { tokenize(vs, buffer); pmol->SetEnergy(atof(vs[4].c_str()) * RYDBERG_TO_KCAL_PER_MOL); } // Enthalphy if (strstr(buffer, "Final enthalpy =")) { tokenize(vs, buffer); hasEnthalpy = true; enthalpy = atof(vs.at(3).c_str()) * RYDBERG_TO_KCAL_PER_MOL; pv = enthalpy - pmol->GetEnergy(); } } // set final unit cell pmol->SetData(cell); // Set enthalpy if (hasEnthalpy) { OBPairData *enthalpyPD = new OBPairData(); OBPairData *enthalpyPD_pv = new OBPairData(); OBPairData *enthalpyPD_eV = new OBPairData(); OBPairData *enthalpyPD_pv_eV = new OBPairData(); enthalpyPD->SetAttribute("Enthalpy (kcal/mol)"); enthalpyPD_pv->SetAttribute("Enthalpy PV term (kcal/mol)"); enthalpyPD_eV->SetAttribute("Enthalpy (eV)"); enthalpyPD_pv_eV->SetAttribute("Enthalpy PV term (eV)"); double en_kcal_per_mole = enthalpy; double pv_kcal_per_mole = pv; double en_eV = enthalpy / EV_TO_KCAL_PER_MOL; double pv_eV = pv / EV_TO_KCAL_PER_MOL; snprintf(tag, BUFF_SIZE, "%f", en_kcal_per_mole); enthalpyPD->SetValue(tag); snprintf(tag, BUFF_SIZE, "%f", pv_kcal_per_mole); enthalpyPD_pv->SetValue(tag); snprintf(tag, BUFF_SIZE, "%f", en_eV); enthalpyPD_eV->SetValue(tag); snprintf(tag, BUFF_SIZE, "%f", pv_eV); enthalpyPD_pv_eV->SetValue(tag); pmol->SetData(enthalpyPD); pmol->SetData(enthalpyPD_pv); pmol->SetData(enthalpyPD_eV); pmol->SetData(enthalpyPD_pv_eV); } pmol->EndModify(); return true; }