Saving coordination and water paths#

Calculating and persisting independent named interaction analyses.

Keep chemical-state assignments separate from observed metal candidates and water paths. Store both methods with the source system, retaining evaluated-empty coverage, actual participants and original provenance. Visualization and scene/session management belong to MolSysViewer.

Added in version 1.0.0.

Preparing indexed chemistry#

This zinc/water/carbonyl fragment system illustrates hydration paths and coordination candidates using controlled coordinates; it is not a minimized metalloprotein.

import numpy as np
import molsysmt as msm
from rdkit import Chem
molsys = msm.convert(Chem.AddHs(Chem.MolFromSmiles('O.C=O.C=O')), to_form='molsysmt.MolSys')
xyz = np.zeros((3, 11, 3))
xyz[:,:,2] = np.arange(11) * 3 + 3
xyz[:,0] = [0,0,0]
xyz[:,5] = [.1,0,0]
xyz[:,6] = [0,.1,0]
xyz[:,2] = [.3,0,0]
xyz[:,4] = [0,.3,0]
xyz[1,4] += 2
molsys.structures.append(coordinates=msm.pyunitwizard.quantity(xyz, 'nm'))
analysis = msm.interactions.water_bridges.get_water_bridges(molsys, pbc=False)
print('Observations:', analysis.n_interactions, 'evaluated frames:', analysis.evaluated_structure_indices.tolist())
metal = msm.convert(Chem.AddHs(Chem.MolFromSmiles('O.C=O.C=O.[Zn+2]')), to_form='molsysmt.MolSys')
xyz_metal = np.zeros((3,12,3))
xyz_metal[:,:,2] = np.arange(12)*3 + 3
xyz_metal[:,0]=[0,0,0]; xyz_metal[:,6]=[.1,0,0]; xyz_metal[:,7]=[0,.1,0]
xyz_metal[:,2]=[.3,0,0]; xyz_metal[:,4]=[0,.3,0]; xyz_metal[:,5]=[0,0,.2]
xyz_metal[1,4] += 2
metal.structures.append(coordinates=msm.pyunitwizard.quantity(xyz_metal,'nm'))
molsys = metal
Observations: 2 evaluated frames: [0, 1, 2]

Attaching named results#

The detector does not attach automatically. Names identify independent analyses; their method definitions and scopes remain distinct.

molsys.interactions = {
    'metal-candidates': msm.interactions.metal_coordination.get_metal_coordination(molsys,pbc=False),
    'water-paths': msm.interactions.water_bridges.get_water_bridges(molsys,pbc=False),
}
print({name: result.n_interactions for name,result in molsys.interactions.items()})
{'metal-candidates': 3, 'water-paths': 2}

Saving and recovering analyses#

Public H5MSM 0.5 conversion retains names, sparse observations, method parameters, occurrence indices and actual producer versions.

import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as folder:
    path=str(Path(folder)/'hydration.h5msm')
    msm.convert(molsys,to_form=path)
    recovered=msm.convert(path,to_form='molsysmt.MolSys')
for name, result in recovered.interactions.items():
    original=molsys.interactions[name]
    assert result.parameters==original.parameters and result.software==original.software
    np.testing.assert_array_equal(result.to_dict()['occurrence_indices'],original.to_dict()['occurrence_indices'])
print('Named round trips preserve original provenance')
Named round trips preserve original provenance

Querying and reordering structures#

A subset keeps source correspondence and remaps both axes. Frame indices are not structure IDs; a frame with zero water paths remains explicitly evaluated.

subset=msm.extract(recovered,selection=list(range(11,-1,-1)),structure_indices=[2,0,1])
print(subset.interactions['water-paths'].structure_source_indices)
print('Empty water frame:',recovered.interactions['water-paths'].query(structure_indices=[1]).n_interactions)
[2 0 1]
Empty water frame: 0

Removing participating atoms#

Removing the mediator drops its paths without recalculating unrelated observations. Removing a metal drops its candidates; neither operation creates or deletes a declared chemical bond on behalf of a detector.

without_water=msm.extract(recovered,selection=list(range(1,12)))
without_metal=msm.extract(recovered,selection=[i for i in range(12) if i!=5])
print('Water paths after removing O:',without_water.interactions['water-paths'].n_interactions)
print('Metal candidates after removing Zn:',without_metal.interactions['metal-candidates'].n_interactions)
Water paths after removing O: 0
Metal candidates after removing Zn: 0

Saving separate hydration orders#

Keep exact one-water and two-water results under distinct names so their criteria and coverage stay explicit. This second controlled polar-fragment system has a three-leg chain and no one-water connection. An evaluated empty analysis is valid and can accompany the system alongside nonempty analyses.

molsys_B = msm.convert(Chem.AddHs(Chem.MolFromSmiles('O.O.N.N')), to_form='molsysmt.MolSys')
chain = np.zeros((3, 14, 3))
chain[:, :, 2] = np.arange(14) * 3 + 3
chain[:, :4] = [[0,0,0], [.3,0,0], [-.3,0,0], [.6,0,0]]
chain[:, 4] = [0,.1,0]; chain[:, 5] = [.1,0,0]
chain[:, 6] = [.3,.1,0]; chain[:, 7] = [.3,-.1,0]
chain[:, 8] = [-.2,0,0]; chain[:, 11] = [.5,0,0]
chain[1, 5] += [2,2,2]
molsys_B.structures.append(coordinates=msm.pyunitwizard.quantity(chain, 'nm'))
molsys_B.interactions = {
    'one-water': msm.interactions.water_bridges.get_water_bridges(molsys_B, order=1, pbc=False),
    'two-waters': msm.interactions.water_bridges.get_water_bridges(molsys_B, order=2, pbc=False),
}
with tempfile.TemporaryDirectory() as folder:
    path = str(Path(folder) / 'hydration-orders.h5msm')
    msm.convert(molsys_B, to_form=path)
    recovered_B = msm.convert(path, to_form='molsysmt.MolSys')
for name, result in recovered_B.interactions.items():
    original = molsys_B.interactions[name]
    assert result.parameters == original.parameters and result.software == original.software
    np.testing.assert_array_equal(result.participant_atoms, original.participant_atoms)
    np.testing.assert_array_equal(result.to_dict()['occurrence_indices'], original.to_dict()['occurrence_indices'])
    print(name, 'order:', result.parameters['mediator_order'], 'observations:', result.n_interactions)
without_second_water = msm.extract(recovered_B, selection=[i for i in range(14) if i != 1])
print('Two-water paths after mediator removal:', without_second_water.interactions['two-waters'].n_interactions)
one-water order: 1 observations: 0
two-waters order: 2 observations: 2
Two-water paths after mediator removal: 0