Querying interaction results#
Build an experimental molsysmt.Interactions result from observations that
have local atom and structure indices. By default these equal the source
system’s indices; explicit source maps support a selected or reordered domain.
This class stores the
observations; it does not detect interactions or declare covalent bonds.
Construction and queries validate their arguments through ArgDigest. Counts and
indices must be integers: booleans and fractional values are rejected before
they can become different atom or structure indices. Integer lists, NumPy
arrays, empty selections and record generators remain supported. Existing
positional calls keep their argument order. The keyword-only
skip_digestion=False defaults to validation; use True only inside a pipeline
that has already checked the complete input contract. Stored cross-column
invariants and file/schema checks remain active on that route.
import molsysmt as msm
records = [
{
"structure_index": 0,
"interaction_type": "hbond",
"participants": [
{"role": "donor", "atom_indices": [0]},
{"role": "hydrogen", "atom_indices": [1]},
{"role": "acceptor", "atom_indices": [2]},
],
"measurements": {"distance": 0.20},
},
]
interactions = msm.Interactions.from_records(
records, n_atoms=3, n_structures=3,
evaluated_structure_indices=[0, 2],
method="example", measure_units={"distance": "nm"},
)
The distance is in nanometers. Structure 2 was evaluated and has no observed
interactions; structure 1 was not evaluated. The result keeps that difference.
By default, the declared atom search scope is internal over all local atoms.
The caller must declare the actual search scope; the class cannot infer from
observed records whether a detector examined all possible participants.
For a search involving one selection and its surroundings, declare the selection and the complete atom universe examined:
scoped = msm.Interactions.from_records(
records, n_atoms=4, n_structures=3,
evaluated_structure_indices=[0, 2], method="example",
measure_units={"distance": "nm"},
evaluation_mode="incident", evaluation_atom_indices=[0],
evaluation_universe_indices=[0, 1, 2],
)
assert scoped.evaluation_scope["universe_indices"].tolist() == [0, 1, 2]
internal(A) covers relations whose participant atoms all belong to A;
incident(A) covers relations with at least one participant atom in A;
between(A, B) covers relations touching each of two disjoint sets. In every
mode, all participants must belong to the declared universe. The declaration
applies uniformly to the listed evaluated structures. Analyses with distinct
scopes belong in separate named results. A structure marked evaluated and
empty is empty only within this declared search scope.
interactions.query(structure_indices=[2, 0, 2]).to_dict()
interactions.query(atom_indices=[0], mode="involving_selection")
interactions.query(atom_indices=[0, 1, 2], mode="within_selection")
interactions.query(atom_indices=[0], mode="across_selection_boundary")
interactions.between_selections([0, 1], [2], exclusive=True)
involving_selection (the default) means at least one participating atom belongs
to the selection; within_selection requires every participating atom;
across_selection_boundary requires atoms inside and outside the selection.
These names describe the atom-selection boundary, not a molecular boundary.
For a ring, every constituent atom participates in these tests; a hydrogen bond
includes its donor, hydrogen and acceptor. Empty atom selections return no
observations in all three modes.
between_selections(A, B) requires at least one atom from each disjoint set. With
exclusive=True, every participant atom must belong to A or B.
Only these explicit query names are supported. between_selections is a separate
method, not a fourth value for query(mode=...), because it needs two selections.
Queries preserve the scientific search that produced the analysis:
detector selection_mode and stored evaluation_mode still use internal,
incident and between. Existing H5MSM 0.5 and InteractionsDict files retain
those scientific values without migration or a schema change.
Each query returns a lightweight view. to_dict() provides typed occurrence
columns, explicit evaluated-structure indices, measurement units, and optional
periodic-image vectors. Use relation(index) to inspect the type and roles
referenced by a result’s relation_indices column.
Inspecting bounded pages#
Keep a query and project a small page instead of copying all its occurrences:
view = interactions.query(structure_indices=[2, 0])
page = view.to_page(offset=0, limit=50, max_participant_atoms=10000)
assert page["total_count"] == view.n_interactions
assert page["occurrence_indices"].tolist() == [0]
assert page["participant_roles"] == ("donor", "hydrogen", "acceptor")
assert page["next_offset"] is None
offset refers to rows in this query’s order, rather than complete-analysis
occurrence indices. Use next_offset to request the next page; it is None
when the current page is empty or reaches the end. A zero limit gives an empty
page with count and coverage. Negative, boolean and noninteger bounds raise.
The experimental schema molsysmt.interactions.page@1 contains the occurrence
columns provided by to_dict(), plus a compact catalog of the page’s relations.
relation_catalog_indices contains complete-analysis relation indices;
relation_types and relation_participant_offsets use positions in that compact
catalog. participant_roles, participant_atom_offsets and participant_atoms
encode its participant groups. Occurrence relation_indices remain in the
complete analysis’s space; find their catalog positions with
numpy.searchsorted(page["relation_catalog_indices"], page["relation_indices"]).
Parallel observations retain distinct occurrence_indices. Measurements,
units, evidence and periodic images follow the page’s occurrence order.
max_participant_atoms bounds the sum of constituent atoms over page occurrences,
counting a reused relation once per occurrence. An oversized page raises before
copying its participant definitions or images; reduce limit or explicitly
increase that budget. Empty arrays retain their dtypes and offsets start at zero.
Source maps and evaluated coverage share read-only arrays with the analysis.
Paging bounds additional occurrence and participant copies. Constructing the
query retains its own row-index array; optional query indexes and frame metadata
have separate costs. Edited analyses can page without packing all surviving
columns. to_dict() continues to copy every selected occurrence. A page is for
inspection; use InteractionsDict or H5MSM for complete persistence. Evaluated
coverage still refers to the analysis’s declared evaluation_scope.
The aligned occurrence_indices column identifies each observation within
this named analysis, even when two observations share a structure and relation.
Filtering and an H5MSM round trip preserve these indices. Extracting or editing
the analysis creates a new set of indices; rebuild saved selections against
the new result. The current API does not expose a persistent revision token.
If any input observation supplies periodic-image vectors, every observation
in that result must supply them; missing vectors are not interpreted as zero
images.
Each vector applies to one participant in relation order. With the three box
vectors as rows in nanometers, add image_vector @ box to each constituent
atom’s stored coordinate. A positive [1, 0, 0] adds the first box vector;
relative geometry uses the first participant as reference. All atoms in a
compound participant receive the same shift. These vectors do not unwrap a
ring split across a periodic boundary.
To transfer the complete result through MolSysMT’s conversion system,
convert it to molsysmt.InteractionsDict:
columns = msm.convert(interactions, to_form="molsysmt.InteractionsDict")
assert msm.get_form(columns) == "molsysmt.InteractionsDict"
restored = msm.convert(columns, to_form="molsysmt.Interactions")
assert restored.query(structure_indices=[2]).n_interactions == 0
InteractionsDict.data contains versioned NumPy columns for relations,
participants, occurrences, evaluated coverage, evidence, and measurements.
It avoids one Python dictionary per occurrence. It is a typed Python payload,
not JSON data. A query view’s to_dict() has a different purpose: it reports
selected occurrences and cannot reconstruct the full result.
interactions.software maps producer software names to the versions used
when calculating the observations. Both hydrogen-bond and disulfide adapters record
{"molsysmt": msm.__version__} at calculation time. The dictionary also
appears in query projections and survives conversion, remapping, invalidation,
and H5MSM persistence. Saving or loading with another MolSysMT version does
not replace the producer version. Older results without this metadata expose
{}, meaning unknown. When constructing an analysis from an external
detector, you can declare its versions with software={"detector_name": "1.2"}.
Inspecting execution provenance#
parameters contains scientific criteria. execution_records describes how each
set of evaluated structures was calculated. Each record has a structure_indices
integer array and a details dictionary. Projected detectors record execution
mode, coordinate block count and memory policy. Unknown details appear as {}.
runs = interactions.execution_records
assert runs[0]["structure_indices"].tolist() == sorted(
interactions.evaluated_structure_indices.tolist())
assert runs[0]["details"] == {} # This example declares no execution details.
A frame query restricts these records even when it has zero occurrences. After partial recalculation, an analysis can contain records from several executions. Changing a returned record does not modify the analysis. A stored block count continues to describe the original execution after extraction or invalidation; it is not a count of frames still present. H5MSM preserves these records.
New interaction payloads use codec version 2 inside H5MSM 0.5. Current readers
also load version 1 and move its recorded execution keys out of parameters.
Older MolSysMT builds supporting only codec 1 must be updated to read new files.
interactions.save("observations.h5i")
restored = msm.Interactions.load("observations.h5i")
The standalone HDF5 file is versioned and separate from H5MSM. load reads
the complete result into memory. Saving writes active observations in small
numeric windows, including analyses with invalidated or recalculated structures.
It does not create or change a cache of complete occurrence columns. Existing
observations, frame metadata and HDF5 caches still occupy memory. Detectors
continue to return resident results; direct detector-to-file output,
append/resume and public lazy file-backed queries remain unavailable. The disulfide
candidate and both hydrogen-bond detectors have optional Interactions
outputs.
Use remap() to extract a complete result into new index spaces. A relation
survives only if all atoms in its participants survive. Repeated structure
indices make distinct output structures, and evaluated structures with no
occurrences stay marked as evaluated.
If a structure changes and its prior observations are stale, use
invalidate_structures() to remove its occurrences and mark it unevaluated
while keeping its positional structure index:
invalidated = interactions.invalidate_structures([0])
assert invalidated.query(structure_indices=[0]).to_dict()[
"evaluated_structure_indices"
].size == 0
This returns a result with independent validity and leaves existing query views unchanged. It shares read-only columns instead of copying surviving observations. Re-evaluate the affected structures before claiming that they have no interactions.
Numeric storage, including the measurement mapping and its arrays, is read-only
and independent of the input buffers used to construct the result. To change
observations, construct another result; an InteractionsDict provides editable
interchange columns that can be converted back into a validated result.
Invalidating frames allocates coverage information rather than a new copy of every observation. Partial invalidation keeps the underlying shared columns in memory, including excluded rows. Queries do not return those rows. If no observations survive, the new result drops its reference to the occurrence storage; old results and views can still retain it.
Reading complete attributes such as occurrence_structures, image_vectors
or measurements after invalidation can pack and cache all surviving columns.
Use query(...).to_dict() for selected frames or atoms when you need only a
small result. Remapping and typed/pickle serialization can also pack the active data;
temporary packing for those operations is released afterward. This is not yet
an incremental writer or an editor for individual observations.
Reclaiming retired observations#
After invalidation or repeated recalculation, use compact() when you want to
release excluded observation storage:
compacted = invalidated.compact()
assert compacted.evaluated_structure_indices.tolist() == [2]
assert compacted.n_interactions == 0
assert interactions.n_interactions == 1 # The original analysis is unchanged.
The returned full analysis preserves occurrence and relation indices, source maps, coverage and provenance. Unused relation definitions stay in its catalog. Queries and H5MSM saving work as before. Query views cannot be compacted.
Attach it explicitly if you want to replace a named analysis:
molsys.interactions = {**molsys.interactions, "example": analysis.compact()}.
Release references to the previous analysis and its query views to reclaim their
storage. Those snapshots otherwise remain valid and keep their old buffers.
Compacting builds new observation columns and needs memory for that output plus
a temporary copy of one column. It neither recalculates observations nor makes
unevaluated structures evaluated. Saving to H5MSM already writes active blocks
directly, so you do not need to compact before saving.
Changing coordinates#
When you call msm.set(molsys, coordinates=..., structure_indices=...) on a
native MolSys, every attached named analysis becomes unevaluated in the
selected structures. This applies even if you move just one atom, the atom
had no earlier interactions, or the frame previously had zero observations.
Other structures remain evaluated. Periodic box changes use the same rule.
MolSysMT does not run detectors automatically. A moved atom can form a new interaction, and a moved ring member can change the geometry of its entire ring. Checking only previous participants would miss these changes. Recalculate the affected frame, considering the detector’s complete declared atom scope.
Operation on native |
Effect on named analyses |
|---|---|
Coordinates or box through |
Selected frames become unevaluated. |
Empty atom/frame selection, time or identifier edit |
Results remain valid. |
Scientific chemical-state edits through |
All covered frames become unevaluated. |
Changing |
Selected frames become unevaluated. |
Direct writes through arrays or separate domain objects |
You must invalidate the owning analyses explicitly. |
For example, attach a synthetic result to matching coordinates, then move one atom in a previously evaluated-empty frame:
import numpy as np
from molsysmt.native import MolSys, Structures
molsys = MolSys(n_atoms=3)
molsys.structures = Structures(
coordinates=msm.pyunitwizard.quantity(np.zeros((3, 3, 3)), "nm")
)
molsys.interactions = {"example": interactions}
previous_view = interactions.query(structure_indices=[0])
msm.set(molsys, selection=[2], structure_indices=[2],
coordinates=msm.pyunitwizard.quantity([[[0.3, 0.0, 0.0]]], "nm"))
current = molsys.interactions["example"]
assert current.evaluated_structure_indices.tolist() == [0]
assert current.query(structure_indices=[2]).n_interactions == 0
assert current.query(structure_indices=[2]).to_dict()[
"evaluated_structure_indices"
].size == 0 # Pending calculation, not an evaluated absence of interactions.
assert current.query(structure_indices=[0]).n_interactions == 1
assert previous_view.n_interactions == 1 # A snapshot of the earlier analysis.
For explicit coordinate writes outside that owner boundary, invalidate the named analyses yourself:
molsys.interactions = {
name: analysis.invalidate_structures([0])
for name, analysis in molsys.interactions.items()
}
Recalculating selected frames#
Calculate new observations for the changed frames with the appropriate detector,
using the same molecular system axes and the complete original atom search scope.
Then call current.replace_structures(fresh) and attach the returned analysis
under its original name. Every frame evaluated by fresh replaces all its old
observations. A recalculated frame with zero observations remains evaluated.
Other frames and previously held snapshots remain unchanged. Nothing is detected
or attached automatically.
For the synthetic example above, declare a new evaluated-empty result for frame 2:
fresh = msm.Interactions.from_records(
[], n_atoms=3, n_structures=3, evaluated_structure_indices=[2],
method=interactions.method, parameters=interactions.parameters,
software=interactions.software, source_id=interactions.source_id,
measure_units=interactions.measure_units,
)
updated = current.replace_structures(fresh)
molsys.interactions = {"example": updated}
assert updated.query(structure_indices=[2]).n_interactions == 0
assert updated.query(structure_indices=[2]).to_dict()[
"evaluated_structure_indices"
].tolist() == [2] # Evaluated absence, unlike the earlier pending frame.
assert updated.query(structure_indices=[0]).n_interactions == 1
For a real Buch analysis, the equivalent workflow is:
# Given a MolSys whose named "buch" analysis used this same scope and pbc=False:
# fresh = msm.interactions.hbonds.get_buch_hbonds(
# molsys, structure_indices=[2], pbc=False,
# output_type="molsysmt.Interactions")
# updated = molsys.interactions["buch"].replace_structures(fresh)
# molsys.interactions = {**molsys.interactions, "buch": updated}
Both operands must be full analyses with the same local/source axes and maps,
source label, method, parameters, producer versions, measurement names/units,
and effective atom evaluation scope. A query view or an extracted subsystem
is not a replacement operand. Differences raise an error; use a separate name
for a different scientific calculation. Parameter equality is strict, including
scientific attribution. Execution mode and block counts may differ: they are
preserved per set of evaluated frames in updated.execution_records.
Populated frames cannot mix known periodic images with unknown images. Empty
frames do not invent images or impose missing observations.
Replacement shares immutable source blocks and indexes the owner of each frame. When the relation catalog is unchanged, its buffers and existing block maps are shared too. Identity maps require no stored vector. Recognizing incoming relations can build a compact lazy index with 16 numeric bytes per registered relation; subsequent edits reuse it. Full participant/role equality is always checked, including hash collisions. This process-local cache is not serialized or used as an interaction identifier. New definitions extend the catalog and may allocate new catalog buffers. Frame bookkeeping still requires memory proportional to the number of structures. Typed dictionary/pickle export and remapping can allocate all active rows. HDF5 export instead writes directly from the active blocks, including a structure with many observations. Selecting or converting a system before writing can still materialize data through those separate operations. A selected-frame query visits its owners and copies only the selected occurrence columns, while sharing the relation registry. Atom queries reuse each active source block’s lazy inverse indexes. These selected projections differ from views of an ordinary packed analysis, which share its occurrence columns too. Repeated replacement drops fully superseded block references; it does not retain a chain of analysis versions. A partly active block retains its original rows, and unused relation definitions may remain in the registry. Many small edits can therefore accumulate blocks; automatic compaction is still pending.
New occurrence indices belong to the updated analysis version and survive its
H5MSM/typed round trip. Replacing a frame does not preserve its old canvas handles.
Reading complete columns, remapping, pickle and typed dictionary export can
materialize all active data. HDF5 saving avoids that packing step; it does not
provide editing of individual rows or resumable output.
Assigning fresh directly under an existing name still replaces the whole
analysis: use replace_structures to preserve other frames.
subset = interactions.remap(atom_indices=[0, 1, 2], structure_indices=[2, 0])
assert subset.n_structures == 2
assert subset.query(structure_indices=[0]).n_interactions == 0
assert subset.structure_source_indices.tolist() == [2, 0]
atom_source_indices and structure_source_indices map each local positional
index to its original source index; source_n_atoms and
source_n_structures define the original index spaces. These are indices, not
element IDs. remap() composes the maps and preserves source_id. An
appended structure or atom with no counterpart in the original source has map
value -1. Query projections do not copy the complete maps on every call; read
them from the result when needed. The typed dictionary and standalone HDF5
file omit identity-map vectors; their readers reconstruct those maps from
the declared axis sizes.
A native MolSys can hold several named, full interaction analyses. Their
atom and structure counts must match the system. Its copy(), extract(),
and remove() methods preserve or remap the analyses.
Methods and attribution#
Calculation methods use an author’s name when a scientific definition is
established, or describe the geometric criterion. A profile selects the
recognition and geometry conventions within a method. These names do not claim
that the reference program originated the criterion:
Calculation |
Method |
Profile |
Reference implementation |
|---|---|---|---|
Hydrogen bonds |
|
|
MDTraj |
Hydrogen bonds |
|
|
CPPTRAJ |
Hydrogen bonds |
|
|
ProLIF |
Hydrogen bonds |
|
|
MDAnalysis geometry |
Cation–π |
|
|
ProLIF |
Cation–π |
|
|
Mol* geometry |
Cation–π |
|
|
MolSysMT proposal |
π–π |
|
|
ProLIF |
π–π |
|
|
MDTraj geometry |
π–π |
|
|
Mol* geometry |
π–π |
|
|
MolSysMT proposal |
For example, method="donor_acceptor_distance_angle", profile="elemental_fon"
selects the existing CPPTRAJ-compatible definition. The old selectors prolif,
cpptraj, mdanalysis_geometry, mdtraj_geometry, and molstar_geometry
remain supported aliases in their respective functions. Changing the name
does not change participants, cutoffs, inclusivity, periodic images or defaults.
Explicit incompatible method/profile combinations raise an error.
The site recognizer has descriptive methods elemental_nitrogen_oxygen,
elemental_fluorine_oxygen_nitrogen, and smarts_donor_acceptor;
its previous software selectors remain aliases too.
Detector-produced analyses include method, profile, method_definition,
and attribution in analysis.parameters. The attribution payload uses
schema="molsysmt.scientific_attribution@1", a calculation target and a compact
list of bibliographic records. Each record declares its contextual roles:
scientific_criterion, reference_implementation, or executed_software.
A reference to ProLIF does not mean ProLIF was executed. Actual producer
versions remain in analysis.software; a reached RDKit branch records RDKit.
The versioned method definition identifies a contract, not a scientific DOI.
The original reference for the historical Buch selector has not been verified;
its recorded criterion is hydrogen_acceptor_distance, without a guessed paper.
The existing Luzard–Chandler entry point records the established
luzar_chandler criterion and its paper while retaining its public spelling.
The complete typed dictionary, standalone file and H5MSM 0.5 preserve these
records, including the bibliography and producer versions recorded at calculation
time. Query views expose .parameters; their occurrence-only to_dict() does
not carry the complete analysis parameters. Loading, querying and remapping do
not register a new scientific calculation. Manually constructed and older
analyses may have no attribution; missing records mean unknown provenance.
When Ackredit is installed, completed calculations also register their used
references in the current Ackredit session. An evaluated structure with no
observations still belongs to that calculation. MolSysMT imports Ackredit lazily
and enables no import hooks, DOI enrichment, persistent journal or reminders.
Without Ackredit, the same result-level metadata is produced. A broken optional
provider emits a diagnostic while preserving the scientific result.
This also applies when warnings are promoted to errors. If creating or emitting
that diagnostic fails, a fallback log retains MSM-WARN-ATTR-001, the operation
and both failures. Scientific errors and unrelated warnings still propagate.
The caller owns workflow sessions and report destinations:
# Optional workflow reporting; requires Ackredit.
import ackredit
with ackredit.session("interaction-workflow"):
analysis = msm.interactions.hbonds.get_hbonds(molecular_system, pbc=False)
print(ackredit.report(format="bibtex"))
Here molecular_system must supply the detector’s required chemistry and
coordinates; this sketch does not assign chemistry or download a system.
Bibliography is stored once per analysis, never once per observation. Portable
workflow capture and contextual report roles are being coordinated with
Ackredit #75.
Associating an analysis#
Attaching an analysis declares that its local atom and structure indices correspond to the system’s local indices. You are responsible for choosing the matching system. MolSysMT checks index bounds, result consistency, and matching axis sizes; equal counts alone do not establish molecular identity. The writer of an H5MSM containing both system and analyses is responsible for their correspondence and declared associations.
When loading an analysis from another file, align it with the target before
attachment if either axis has a different order. remap() accepts old
analysis indices in the desired new order. It can extract or reorder the
analysis; it does not embed a smaller analysis into a larger target domain.
Source maps are provenance and are not automatically matched to the target.
source_id is an optional label supplied by the caller, not a verified
fingerprint. Attachment requires no automatic origin authentication. Use
coordinates and periodic boxes compatible with the calculation; the stored
image vectors refer to that geometry.
import numpy as np
from molsysmt.native import MolSys
molsys = MolSys(n_atoms=3)
molsys.structures.append(coordinates=np.zeros((3, 3, 3)))
molsys.interactions = {"example": interactions}
selected = molsys.extract(atom_indices=[0, 1, 2], structure_indices=[2, 0])
assert selected.interactions["example"].n_structures == 2
You can also attach an analysis returned directly by the disulfide candidate detector. This synthetic example identifies a geometric candidate; it does not declare a covalent bond:
builder = msm.MolSysBuilder()
first = builder.add_atom(atom_name="SG", atom_type="S")
second = builder.add_atom(atom_name="SG", atom_type="S")
builder.add_group([first], group_name="CYS")
builder.add_group([second], group_name="CYS")
builder.set_coordinates(
msm.pyunitwizard.quantity([[0, 0, 0], [0.20, 0, 0]], "nm")
)
molsys = builder.build()
analysis = msm.interactions.disulfides.get_disulfide_candidates(
molsys, pbc=False, output_type="molsysmt.Interactions"
)
molsys.interactions = {"disulfide_candidates": analysis}
assert molsys.interactions["disulfide_candidates"].n_interactions == 1
For a system with covalently attached donor hydrogens, use the Buch detector to construct an analysis of H-A distances (in nm):
analysis = msm.interactions.hbonds.get_buch_hbonds(
molsys, output_type="molsysmt.Interactions"
)
molsys.interactions = {**molsys.interactions, "buch": analysis}
visible = analysis.query(structure_indices=[0]).to_dict()
The result declares the automatically eligible participants, including
donor hydrogens attached outside an atom selection. Two selections must have
disjoint participant universes or identical roles for this optional output.
Supplied role arrays and a second structure axis are currently unsupported.
With PBC, the donor is the image anchor, the hydrogen uses its D-H minimum
image, and the acceptor continues from that hydrogen using the observed H-A
image. The stored distance checks the H-A segment; D-H unwrapping supplies
consistent drawing geometry and does not add a detection criterion. These
detectors use eager execution; requesting Interactions does not make them
stream coordinates or write observations incrementally.
For the joint distance-and-angle criterion, use
msm.interactions.hbonds.get_luzard_chandler_hbonds(..., output_type="molsysmt.Interactions"). It measures donor-to-acceptor distance
in nm and the H-D-A angle in rad, with the donor as vertex. The defaults are
0.35 nm and a strict angular cutoff of 30 degrees (pi/6 rad). Its periodic
images independently unwrap D-H and D-A from the donor; they reproduce the
two vectors used for the angle. It has the same optional-result scope limits
as Buch and preserves evaluated-empty frames and producer versions.
Appended structures remain unevaluated by existing analyses, including a
coordinate-only source passed to msm.append_structures. Adding atoms to a
system with analyses keeps their previous search universe fixed; the added
atoms are outside it and are not claimed as evaluated. Adding atoms from a
source MolSys that already has analyses, or appending structures from such a
source, requires an explicit analysis merge policy and currently raises an
error. H5MSM 0.4 and MolSysDict 0.1 cannot store attached analyses and
reject that export. H5MSM 0.5 writes and reads the named analyses with the
system; Interactions.save() remains available for standalone results.
Directional halogen observations#
The experimental molsysmt.interactions.halogen_bonds.get_halogen_bonds()
returns four singleton roles: donor, halogen, acceptor and acceptor reference.
Every role participates in atom-set queries; an acceptor with two eligible
reference neighbors can yield two separately identifiable directional relations.
The descriptive distance_two_angles method with smarts_donor_acceptor profile
reproduces the ProLIF 2.2.2 core adapted from Auffinger et al. (2004), not that
paper’s original element-specific distance thresholds. Producer versions and
the adapted paper/reference bibliography persist with each named analysis. See
get_halogen_bonds and Saving halogen-bond analyses.
Hydrophobic atom-pair observations#
The experimental molsysmt.interactions.hydrophobic.get_hydrophobic_interactions()
uses atom_pair_distance with smarts_hydrophobic_atoms, reproducing the pinned
ProLIF 2.2.2 core. Two distinct atoms form an unordered relation, with ascending
source indices and roles hydrophobic_1/hydrophobic_2; roles do not encode the
selected interface sides. Self records and reverse duplicates are excluded.
Additional covalent/intramolecular exclusions are not inferred. Use disjoint
selections for interfacial observations. This typed proximity is not a residue
scale value or interaction energy. Scope, known-empty coverage, canonical MIC
images, original producers and reference bibliography remain part of the named
analysis. See get_hydrophobic_interactions and
Saving hydrophobic analyses.
Coordination and solvent paths#
molsysmt.interactions.metal_coordination.get_metal_coordination() stores
directed metal/ligand candidates; it does not declare bonds in ChemicalStates.
molsysmt.interactions.water_bridges.get_water_bridges() stores two or three
D-H-A legs with six or nine singleton roles and one or two mediator waters.
order=1 is the default; order=2 means exactly two distinct waters, not up to two. Repeated atoms
retain their separate chemical roles; involving_selection queries return an occurrence
once. Internal queries require all actual branch atoms, including mediator
O and the participating H. An unused water H is not an extra participant.
Both analyses retain evaluated-empty frames, original references/producer
versions, units and observed images through named H5MSM 0.5 conversion.