Input and output
Load ligands from SDF, mol2, SMILES, or a directory.
Every loader converges on the same guarantees, because
Ligand demands them: explicit hydrogens, exactly one 3D
conformer, and a filesystem-safe unique name. Enforcing that here rather than downstream
means a malformed input fails while the user still knows which file it came from.
- rbfenetmap.io.loaders.load_fepplus_network(path)[source]
Read a Schrodinger FEP+ edge list into
explicit_pairsspecifications.FEP+ writes its planned map as a text file of
A >>> Blines, each name optionally prefixed by an internal hash and a colon. openfe ships the equivalent asload_fepplus_network; this is the same job in this package’s vocabulary, and it exists so that a group with an existing map can evaluate this tool against it rather than having to start from nothing.- Parameters:
path (pathlib.Path)
- Returns:
"a~b"specifications, ready to hand toNetworkOptionsasexplicit_pairsalongsidepair_strategy="explicit"and theexplicitplanner.- Return type:
- Raises:
ValueError – If a line is unparsable or the file holds no edges.
Notes
Only the topology is imported; FEP+’s atom mappings are not read, and this package maps every imported pair itself. That is the point rather than a limitation – the main reason to import a foreign map is to put it through this package’s own feasibility rules – but it does mean an edge FEP+ was happy with can come back rejected. The
explicitplanner says so loudly instead of dropping it.
- rbfenetmap.io.loaders.load_ligands(paths, *, name_property='_Name')[source]
Load ligands from any mixture of files and directories.
- Parameters:
paths (Iterable[pathlib.Path] or Sequence[str]) – Files or directories. Directories are scanned (non-recursively) for the recognised molecule suffixes.
name_property (str, optional) – Passed to
load_sdf().
- Returns:
In discovery order.
- Return type:
- Raises:
FileNotFoundError – If a named path does not exist.
ValueError – If two ligands end up with the same name, which would silently collapse two network vertices into one.
- rbfenetmap.io.loaders.load_orion_network(path)[source]
Read an OpenEye Orion NES edge list into
explicit_pairsspecifications.Orion writes
A >> Blines, with#comments. Two arrows rather than three is the only structural difference from the FEP+ format, which is exactly why these are two entry points over one parser rather than one loader that sniffs: a guess that read an FEP+ line as an Orion edge would import a network nobody planned.- Parameters:
path (pathlib.Path)
- Returns:
"a~b"specifications. Seeload_fepplus_network()for how to use them and for what is deliberately not imported.- Return type:
- Raises:
ValueError – If a line is unparsable or the file holds no edges.
- rbfenetmap.io.loaders.load_sdf(path, *, name_property='_Name')[source]
Load every record from an SDF or MOL file.
- Parameters:
path (pathlib.Path)
name_property (str, optional) – Molecule property to read the name from. Falls back to
stem_index.
- Return type:
- rbfenetmap.io.loaders.load_smiles(path)[source]
Load a whitespace-delimited
SMILES namefile, embedding each molecule.See the warning in
_prepare(): independently embedded ligands are not co-posed.
- rbfenetmap.io.loaders.sanitize_name(raw, fallback)[source]
Return a filesystem-safe ligand name derived from raw.
Ligand names become directory and file names in exports and are parsed back out of
"source~target"edge keys, so characters outside[A-Za-z0-9_.+-]are replaced with underscores rather than passed through.
JSON serialization of a planned network.
The network file is the package’s own interchange format, and it is deliberately self-contained: molecules travel as MDL molblocks embedded in the JSON rather than as paths to the original inputs. A network that references files by path stops being reproducible the moment someone reorganises a directory, and the mapping indices in it are meaningless against a molecule that has been re-read with different atom ordering.
Rejected candidates are written too. They cost little and they are what explains a disconnected or sparse network after the fact.
Two fields are written only when they carry something – a ligand’s provenance and a
network’s intermediates. Absence already means “not set”, so emitting a null or an
empty list would add a difference to every file ever written in order to convey nothing,
and would break the property that regenerating an all-real network reproduces it
byte-for-byte.
- rbfenetmap.io.networkio.SCHEMA_VERSION = 1
Bumped whenever the on-disk shape changes incompatibly.
- rbfenetmap.io.networkio.dump_network(network, path, *, indent=2)[source]
Write network to path as JSON.
- rbfenetmap.io.networkio.load_network(path)[source]
Read a network written by
dump_network().- Raises:
ValueError – If the file was written by an incompatible schema version.
- Parameters:
path (Path)
- Return type:
- rbfenetmap.io.networkio.network_to_dict(network)[source]
Return the JSON-ready representation of network.
Amber timask / scmask generation.
A ParmEd-free port of BuildEdges._build_rbfe_mask_variables. It lives in
rbfenetmap.io rather than the core because Amber masks are one output format
among several, and nothing in the planning pipeline should depend on them.
Two correctness traps from the original are preserved deliberately, and both are worth understanding before touching this module.
- rbfenetmap.io.amber_masks.DEFAULT_RESIDUE_NAMES = ('SRC', 'DST')
Residue names the exporter assigns to the two endpoints of an edge.
- class rbfenetmap.io.amber_masks.AmberMasks(timask1, timask2, scmask1, scmask2)[source]
Bases:
objectThe four Amber mask strings for one transformation.
- rbfenetmap.io.amber_masks.build_amber_masks(source, target, mapping, *, residue_names=('SRC', 'DST'))[source]
Build the
timask/scmaskpair for one transformation.- Parameters:
- Return type:
- Raises:
rbfenetmap.core.exceptions.ExporterError – If the mapping has no common core, if a soft-core atom name collides with a common-core atom name, or if the mapping violates Amber’s linear-scaling constraint.
Notes
Trap three: the empty core. A mapping with no common core is what a counterpoised (CBFE) edge carries, and left alone this function would happily turn it into
timask1=":SRC",scmask1=":SRC&@<every atom>". That is not a malformed file – it is a valid, runnable single-topology RBFE in which both endpoints are entirely soft-core, which will converge inpmemdand answer a different question than the one asked, with nothing downstream to flag it. It is refused here rather than only in the exporter so no future caller can reopen it. Trap one: name collisions. Amber soft-core masks select atoms by name, not by index. If a soft-core atom shares its name with a common-core atom in the same residue, the mask silently selects that core atom too, and the run proceeds with a soft-core region larger than intended. Nothing downstream reports this; the free energies are simply wrong. Atom names must therefore be unique within a ligand – which is whatantechamber -du yproduces.Trap two: linear scaling. Amber requires
len(TI1) - len(SC1) == len(TI2) - len(SC2). Since each side of that reduces to the size of the common core, the constraint is exactlylen(cc1) == len(cc2)together with injectivity ofcc2– and both are already invariants ofAtomMapping. A mapping built by this package cannot violate it, so the check below can only ever fire on a hand-authored map. It is kept because it is cheap, and because failing here with a clear message beats failing insidepmemdwith an opaque one.