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 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 UnitCellExtension::fillUnitCell() { /* 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 == NULL) return; const SpaceGroup *sg = uc->GetSpaceGroup(); // the actual space group and transformations for this unit cell if (!sg) { QMessageBox::warning(qobject_cast<QWidget*>(parent()), tr("Avogadro"), tr("This unit cell does not have an associated spacegroup.")); return; } // 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 #ifdef OPENBABEL_IS_NEWER_THAN_2_2_99 uniqueV = uc->CartesianToFractional(uniqueV); #else uniqueV *= uc->GetFractionalMatrix(); #endif 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; addAtom = mol.NewAtom(); addAtom->Duplicate(atom); #ifdef OPENBABEL_IS_NEWER_THAN_2_2_99 addAtom->SetVector(uc->FractionalToCartesian(updatedCoordinate)); #else addAtom->SetVector(uc->GetOrthoMatrix() * updatedCoordinate); #endif } // end loop of transformed atoms // Put the original atom into the proper space in the unit cell too #ifdef OPENBABEL_IS_NEWER_THAN_2_2_99 atom->SetVector(uc->FractionalToCartesian(uniqueV)); #else atom->SetVector(uc->GetOrthoMatrix() * uniqueV); #endif } // end loop of atoms
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); }