diff --git a/resources/surface_description.json b/resources/surface_description.json index 5530345..3e4cc21 100644 --- a/resources/surface_description.json +++ b/resources/surface_description.json @@ -113,9 +113,9 @@ "description": "

Difference between the alpha and beta electron densities

" }, "fragment_patch": { - "cmap": "Qualitative14Dark", + "cmap": "Turbo", "displayName": "Fragment Patch", - "occName": "fragment", + "occName": "fragment_patch", "description": "

The index of the associated neighbouring fragment/molecule

" }, "de_idx": { diff --git a/src/core/chemicalstructure.cpp b/src/core/chemicalstructure.cpp index ccee3c4..9efcb28 100644 --- a/src/core/chemicalstructure.cpp +++ b/src/core/chemicalstructure.cpp @@ -10,9 +10,15 @@ #include namespace impl { -template + +MaybeFragment getFragmentForAtom(const ChemicalStructure &structure, + GenericAtomIndex atomIndex) { + auto fragIndex = structure.fragmentIndexForGeneralAtom(atomIndex); + return structure.getFragment(fragIndex); +} + MaybeFragment getFragmentForAtom(const ChemicalStructure &structure, - Index atomIndex) { + int atomIndex) { auto fragIndex = structure.fragmentIndexForAtom(atomIndex); return structure.getFragment(fragIndex); } @@ -572,7 +578,7 @@ FragmentIndex ChemicalStructure::fragmentIndexForAtom(int atomIndex) const { } FragmentIndex -ChemicalStructure::fragmentIndexForAtom(GenericAtomIndex idx) const { +ChemicalStructure::fragmentIndexForGeneralAtom(GenericAtomIndex idx) const { return fragmentIndexForAtom(genericIndexToIndex(idx)); } @@ -627,7 +633,7 @@ QColor ChemicalStructure::atomColor(GenericAtomIndex atomIndex) const { return Qt::black; } case AtomColoring::Fragment: { - auto fragIndex = fragmentIndexForAtom(atomIndex); + auto fragIndex = fragmentIndexForGeneralAtom(atomIndex); return getFragmentColor(fragIndex); } case AtomColoring::Index: @@ -1163,9 +1169,10 @@ QString ChemicalStructure::getFragmentLabelForAtoms( return "None"; // Get unique fragment indices for the atoms - ankerl::unordered_dense::set uniqueFragments; + ankerl::unordered_dense::set + uniqueFragments; for (const auto &idx : idxs) { - uniqueFragments.insert(fragmentIndexForAtom(idx)); + uniqueFragments.insert(fragmentIndexForGeneralAtom(idx)); } // Get chemical formula for these atoms diff --git a/src/core/chemicalstructure.h b/src/core/chemicalstructure.h index 3bc13ca..5fbde9e 100644 --- a/src/core/chemicalstructure.h +++ b/src/core/chemicalstructure.h @@ -187,7 +187,7 @@ class ChemicalStructure : public QObject { inline size_t numberOfFragments() const { return m_fragments.size(); } FragmentIndex fragmentIndexForAtom(int) const; - FragmentIndex fragmentIndexForAtom(GenericAtomIndex) const; + virtual FragmentIndex fragmentIndexForGeneralAtom(GenericAtomIndex) const; MaybeFragment getFragmentForAtom(int) const; MaybeFragment getFragmentForAtom(GenericAtomIndex) const; diff --git a/src/crystal/crystalstructure.cpp b/src/crystal/crystalstructure.cpp index d3ebfdb..42a5593 100644 --- a/src/crystal/crystalstructure.cpp +++ b/src/crystal/crystalstructure.cpp @@ -599,6 +599,7 @@ void CrystalStructure::completeFragmentContaining(GenericAtomIndex index) { } updateBondGraph(); } + void CrystalStructure::completeFragmentContaining(int atomIndex) { if (atomIndex < 0 || atomIndex >= numberOfAtoms()) return; @@ -1098,6 +1099,17 @@ const FragmentMap &CrystalStructure::symmetryUniqueFragments() const { return m_symmetryUniqueFragments; } +FragmentIndex +CrystalStructure::fragmentIndexForGeneralAtom(GenericAtomIndex index) const { + if(m_unitCellAtomFragments.size() == 0) return ChemicalStructure::fragmentIndexForGeneralAtom(index); + qDebug() << m_unitCellAtomFragments.size() << index.unique; + FragmentIndex fragmentIndex = m_unitCellAtomFragments.at(index.unique); + fragmentIndex.h += index.x; + fragmentIndex.k += index.y; + fragmentIndex.l += index.z; + return fragmentIndex; +} + Fragment::State CrystalStructure::getSymmetryUniqueFragmentState( FragmentIndex fragmentIndex) const { const auto kv = m_symmetryUniqueFragments.find(fragmentIndex); @@ -1331,7 +1343,9 @@ void CrystalStructure::setPairInteractionsFromDimerAtoms( params.fragmentDimer = ud; params.nearestAtomDistance = d.nearestAtomDistance; params.centroidDistance = d.centroidDistance; - params.hasInversionSymmetry = false; + // TODO better handling of inversion symmetry + QString modelName = pair->interactionModel(); + params.hasInversionSymmetry = !(modelName == "cg" || modelName.startsWith("crystalclear")); pair->setParameters(params); p->add(pair); } diff --git a/src/crystal/crystalstructure.h b/src/crystal/crystalstructure.h index 4ef57ca..21b21d1 100644 --- a/src/crystal/crystalstructure.h +++ b/src/crystal/crystalstructure.h @@ -43,6 +43,7 @@ class CrystalStructure : public ChemicalStructure { inline const auto &spaceGroup() const { return m_crystal.space_group(); } occ::Mat3N convertCoordinates(const occ::Mat3N &pos, ChemicalStructure::CoordinateConversion) const override; + FragmentIndex fragmentIndexForGeneralAtom(GenericAtomIndex) const override; void deleteFragmentContainingAtomIndex(int atomIndex) override; void deleteIncompleteFragments() override; void deleteAtoms(const std::vector &) override; diff --git a/src/crystalx.cpp b/src/crystalx.cpp index b0b4479..76e5552 100644 --- a/src/crystalx.cpp +++ b/src/crystalx.cpp @@ -883,6 +883,10 @@ void Crystalx::loadExternalFileData(QString filename) { showStatusMessage( QString("Loading crystal clear output from %1").arg(filename)); project->loadCrystalClearJson(filename); + } + if (filename.endsWith("elat_results.json")) { + showStatusMessage(QString("Loading occ elat output from %1").arg(filename)); + project->loadCrystalClearJson(filename); } else if (filename.endsWith("surface.json")) { showStatusMessage(QString("Loading crystal surface from %1").arg(filename)); project->loadCrystalClearSurfaceJson(filename); diff --git a/src/graphics/scene.cpp b/src/graphics/scene.cpp index 6178025..06a5abe 100644 --- a/src/graphics/scene.cpp +++ b/src/graphics/scene.cpp @@ -238,7 +238,8 @@ void Scene::setSelectStatusForAtomDoubleClick(int atom) { auto atomIndex = m_structure->indexToGenericIndex(atom); if (m_structure->testAtomFlag(atomIndex, AtomFlag::Contact)) return; - const auto fragmentIndex = m_structure->fragmentIndexForAtom(atomIndex); + const auto fragmentIndex = + m_structure->fragmentIndexForGeneralAtom(atomIndex); const auto &atomIndices = m_structure->atomIndicesForFragment(fragmentIndex); auto idx = m_structure->indexToGenericIndex(atom); m_structure->setAtomFlag(idx, AtomFlag::Selected, true); @@ -1424,7 +1425,7 @@ void Scene::generateAllExternalFragments() { qDebug() << "Generate external fragment"; if (!mesh) return; - occ::IVec de_idxs = mesh->vertexProperty("de_idx").cast(); + occ::IVec de_idxs = mesh->vertexProperty("External atom index").cast(); qDebug() << "num de_idxs" << de_idxs.size(); ankerl::unordered_dense::set unique(de_idxs.data(), de_idxs.data() + de_idxs.size()); @@ -1540,7 +1541,7 @@ void Scene::colorSelectedAtoms(const QColor &color, bool fragments) { auto idxs = m_structure->atomsWithFlags(AtomFlag::Selected); if (fragments) { for (const auto &idx : idxs) { - const auto frag = m_structure->fragmentIndexForAtom(idx); + const auto frag = m_structure->fragmentIndexForGeneralAtom(idx); m_structure->setFragmentColor(frag, color); } } else { diff --git a/src/io/crystalclear.cpp b/src/io/crystalclear.cpp index 0e08dd1..abbcba4 100644 --- a/src/io/crystalclear.cpp +++ b/src/io/crystalclear.cpp @@ -56,10 +56,15 @@ CrystalStructure *loadCrystalClearJson(const QString &filename) { return nullptr; occ::crystal::Crystal crystal = loadOccCrystal(json["crystal"]); + // TODO check if it's cg and then set symmetry of interactions QList interactions; QList> atomIndices; + QString modelName = "cg"; + if(json.contains("model")) { + modelName = QString::fromStdString(json["model"]); + } // Parse neighbor energies auto pairsArray = json["pairs"]; interactions.resize(pairsArray.size()); @@ -69,7 +74,7 @@ CrystalStructure *loadCrystalClearJson(const QString &filename) { auto &neighbors = interactions[i]; auto &offsets = atomIndices[i]; for (int j = 0; j < siteEnergies.size(); ++j) { - auto *pair = new PairInteraction("cg"); + auto *pair = new PairInteraction(modelName); auto dimerObj = siteEnergies[j]; auto energiesObj = dimerObj["energies"]; pair->setLabel(QString::number(j + 1)); diff --git a/src/volume/isosurface_calculator.cpp b/src/volume/isosurface_calculator.cpp index 056d556..f174683 100644 --- a/src/volume/isosurface_calculator.cpp +++ b/src/volume/isosurface_calculator.cpp @@ -134,6 +134,37 @@ QString IsosurfaceCalculator::surfaceName() { .arg(m_parameters.isovalue); } +void setFragmentPatchForMesh(Mesh * mesh, ChemicalStructure *structure) { + if(!mesh) return; + if(!structure) return; + ankerl::unordered_dense::map fragmentIndices; + + Mesh::ScalarPropertyValues fragmentPatch(mesh->numberOfVertices()); + fragmentPatch.setConstant(-1.0); + occ::IVec de_idxs = mesh->vertexProperty("External atom index").cast(); + auto atomIndices = mesh->atomsOutside(); + for (int i = 0; i < de_idxs.size(); i++) { + int idx = de_idxs(i); + if (idx >= atomIndices.size()) { + continue; + } + const auto &genericIndex = atomIndices[idx]; + FragmentIndex fidx = structure->fragmentIndexForGeneralAtom(genericIndex); + if(fidx.u == -1) { + continue; + } + const auto kv = fragmentIndices.find(fidx); + if(kv != fragmentIndices.end()) { + fragmentPatch(i) = kv->second; + } + else { + fragmentPatch(i) = fragmentIndices.size(); + fragmentIndices.insert({fidx, fragmentIndices.size()}); + } + } + mesh->setVertexProperty("Fragment Patch", fragmentPatch); +} + void IsosurfaceCalculator::surfaceComplete() { qDebug() << "Task" << m_name << "finished in IsosurfaceCalculator"; QList meshes = io::loadMeshes(m_fileNames); @@ -155,6 +186,7 @@ void IsosurfaceCalculator::surfaceComplete() { } mesh->setAtomsInside(m_atomsInside); mesh->setAtomsOutside(m_atomsOutside); + setFragmentPatchForMesh(mesh, params.structure); mesh->setParent(m_structure); // create the child instance that will be shown MeshInstance *instance = new MeshInstance(mesh);