Skip to content

Commit

Permalink
Make sure "fill unit cell" generates copies on the unit cell too
Browse files Browse the repository at this point in the history
Signed-off-by: Geoff Hutchison <[email protected]>
  • Loading branch information
ghutchis committed Oct 17, 2023
1 parent 60f8b77 commit 6eaad7e
Showing 1 changed file with 79 additions and 9 deletions.
88 changes: 79 additions & 9 deletions avogadro/core/spacegroups.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,9 @@

namespace Avogadro::Core {

SpaceGroups::SpaceGroups()
{
}
SpaceGroups::SpaceGroups() {}

SpaceGroups::~SpaceGroups()
{
}
SpaceGroups::~SpaceGroups() {}

unsigned short SpaceGroups::hallNumber(const std::string& spaceGroup)
{
Expand Down Expand Up @@ -64,7 +60,6 @@ unsigned short SpaceGroups::hallNumber(const std::string& spaceGroup)
return hall; // can't find anything
}


CrystalSystem SpaceGroups::crystalSystem(unsigned short hallNumber)
{
if (hallNumber == 1 || hallNumber == 2)
Expand Down Expand Up @@ -254,7 +249,7 @@ Array<Vector3> SpaceGroups::getTransforms(unsigned short hallNumber,
// These transforms are separated by spaces
std::vector<std::string> transforms = split(transformsStr, ' ');

for (auto & transform : transforms)
for (auto& transform : transforms)
ret.push_back(getSingleTransform(transform, v));

return ret;
Expand Down Expand Up @@ -305,7 +300,82 @@ void SpaceGroups::fillUnitCell(Molecule& mol, unsigned short hallNumber,
newAtom.setPosition3d(newCandidate);
}
}
// @todo make this optional
CrystalTools::wrapAtomsToUnitCell(mol);

// Now we need to generate any copies on the unit boundary
// We need to loop through all the atoms again
// if a fractional coordinate contains 0.0, we need to generate a copy
// of the atom at 1.0
atomicNumbers = mol.atomicNumbers();
positions = mol.atomPositions3d();
numAtoms = mol.atomCount();
for (Index i = 0; i < numAtoms; ++i) {
unsigned char atomicNum = atomicNumbers[i];
Vector3 pos = uc->toFractional(positions[i]);

Array<Vector3> newAtoms;
// We need to check each coordinate to see if it is 0.0 or 1.0
// .. if so, we need to generate the symmetric copy
for (Index j = 0; j < 3; ++j) {
Vector3 newPos = pos;
if (fabs(pos[j]) < 0.001) {
newPos[j] = 1.0;
newAtoms.push_back(newPos);
}
if (fabs(pos[j] - 1.0) < 0.001) {
newPos[j] = 0.0;
newAtoms.push_back(newPos);
}

for (Index k = j + 1; k < 3; ++k) {
if (fabs(pos[k]) < 0.001) {
newPos[k] = 1.0;
newAtoms.push_back(newPos);
newPos[k] = 0.0; // revert for the other coords
}
if (fabs(pos[k] - 1.0) < 0.001) {
newPos[k] = 0.0;
newAtoms.push_back(newPos);
newPos[k] = 1.0; // revert
}
}
}
// finally, check if all coordinates are 0.0
if (fabs(pos[0]) < 0.001 && fabs(pos[1]) < 0.001 && fabs(pos[2]) < 0.001)
newAtoms.push_back(Vector3(1.0, 1.0, 1.0));
// or 1.0 .. unlikely, but possible
if (fabs(pos[0] - 1.0) < 0.001 && fabs(pos[1] - 1.0) < 0.001 &&
fabs(pos[2] - 1.0) < 0.001)
newAtoms.push_back(Vector3(0.0, 0.0, 0.0));

for (Index j = 0; j < newAtoms.size(); ++j) {
// The new atoms are in fractional coordinates. Convert to cartesian.
Vector3 newCandidate = uc->toCartesian(newAtoms[j]);

// If there is already an atom in this location within a
// certain tolerance, do not add the atom.
bool atomAlreadyPresent = false;
for (Index k = 0; k < mol.atomCount(); k++) {
// If it does not have the same atomic number, skip over it.
if (mol.atomicNumber(k) != atomicNum)
continue;

Real distance = (mol.atomPosition3d(k) - newCandidate).norm();

if (distance <= cartTol)
atomAlreadyPresent = true;
}

// If there is already an atom present here, just continue
if (atomAlreadyPresent)
continue;

// If we got this far, add the atom!
Atom newAtom = mol.addAtom(atomicNum);
newAtom.setPosition3d(newCandidate);
}
}
}

void SpaceGroups::reduceToAsymmetricUnit(Molecule& mol,
Expand Down Expand Up @@ -359,4 +429,4 @@ const char* SpaceGroups::transformsString(unsigned short hallNumber)
return "";
}

} // end Avogadro namespace
} // namespace Avogadro::Core

0 comments on commit 6eaad7e

Please sign in to comment.