1 Extractor

The extractor reads molecular structures and calculates properties for their atoms, residues, bonds and rings. Its core classes provide the language in which those calculations are written.

The diagrams show the main classes and representative calculators. Method signatures include only the arguments needed to explain each relationship.

1.1 A language for molecular calculations

The library is an embedded domain-specific language: its C++ types and operations let a calculator work with molecular concepts directly. Protein holds atoms, residues and topology; ProteinConformation holds coordinates and results for one pose. Chemical roles distinguish, for example, a carbonyl carbon from an alpha carbon. A bond or ring records which atoms belong to it.

For the ring-current calculation, GeometryResult::Compute first calls Ring::ComputeGeometry for each ring using the pose’s atomic positions. It stores each ring’s centre, normal and vertices in the conformation. BiotSavartResult::Compute uses this geometry to calculate the field from nearby rings at each atom. It stores the accumulated field and shielding contribution in that atom’s conformation record. Ring membership stays fixed across poses; the geometry and calculated values can change.

The input readers and topology code establish chemical roles and connectivity before the calculators run. Calculators can then select atoms, bonds and rings from that description and concentrate on their numerical work. They use the result interfaces to declare prerequisites and write output. Adding a calculation need not mean inventing another naming scheme or atom order.

An atom’s chemical record, pose data and accumulated trajectory measurements all use the same index. These separate stores let coordinates and results change with the frame without redefining the atom. The following sections explain the class and buffer relationships that make this possible.

Source: GeometryResult.cpp::Compute; BiotSavartResult.cpp::Compute; LegacyAmberTopology.h::SemanticAt; ConformationResult.cpp::WriteAllFeatures.

1.2 Reading the class diagrams

1.3 Identity and a pose

Protein records the atoms, their residues and their topology, independently of their coordinates. ProteinConformation holds the positions and calculated results for one pose. It refers to the protein without owning it, and keeps its own per-atom fields, geometry and result objects.

Protein also owns a list of retained conformations, omitted from this diagram. Temporary conformations used to process trajectory frames need not be added to that list.

Source: Protein.h:37, its owned storage near line 221; ProteinConformation.h:28; ProteinConformation.cpp:7; Atom.h:14.

Protein identity and a conformation
Figure 1.1. Protein identity and a conformation

1.4 Names, roles and grouping

The input code interprets atom names when it constructs the protein. NamingRegistry records the naming conventions used by different source tools for each residue type. NamingApplicator interprets a supplied atom name using the source convention and the atom’s chemical context. FullSystemReader is one of the readers that uses these classes.

This interpretation lets calculators use chemical roles and connectivity without decoding each source tool’s atom names. LegacyAmberTopology, the concrete implementation of ProteinTopology, provides access to bonds, rings and chemical categories. Residues, bonds and rings store indices into the protein’s atom collection. Names remain available for identification and output.

Source: NamingRegistry.h:274 and :378; FullSystemReader.cpp:883 and :959; Protein.cpp:440 onward; ProteinTopology.h:19; LegacyAmberTopology.h:93; SemanticEnums.h:837.

Naming and typed topology
Figure 1.2. Naming and typed topology

1.5 The same atom across buffers

For the atom at index i, Protein::AtomAt(i) retrieves its chemical record, ProteinConformation::AtomAt(i) retrieves its pose data, and TrajectoryProtein::AtomAt(i) retrieves its accumulated measurements. These are separate records for the same atom. A pose calculator writes the current result; a trajectory calculator can use it to update statistics or append a time-series sample.

The records occupy separate arrays. In a dense time-series buffer, one index selects the atom and a second selects the stored sample. The sample’s position in the buffer need not equal its original frame number. Original frame numbers and times are recorded separately.

Source: Protein::AddAtom and AtomAt; ProteinConformation construction and AtomAt; TrajectoryProtein::InitTrajectoryAtoms and AtomAt; DenseBuffer.h:36; BsShieldingTimeSeriesTrajectoryResult.cpp:40 onward.

The same index identifies an atom in the identity records, pose data, accumulated measurements and stored samples.
Figure 1.3. The same index identifies an atom in the identity records, pose data, accumulated measurements and stored samples.

1.6 Pose calculators and their results

The diagram shows result classes for geometry, ring-current and MOPAC calculations. Their static Compute functions receive a conformation, perform a calculation and return a result object. Each function can read the conformation’s coordinates and refer to the associated Protein for chemical identity and topology.

ConformationResult provides the common interface for naming results, declaring their prerequisites and writing their output. It has no virtual Compute function: OperationRunner calls the concrete classes’ static functions in an explicit order and attaches the results to the conformation. Before accepting a result, ProteinConformation::AttachResult checks that its prerequisite results are already attached.

Some result objects own their numerical arrays. Others read or write the conformation’s named per-atom or geometry fields, providing access to those fields without keeping a duplicate buffer.

Source: ConformationResult.h:40; GeometryResult.h:12; BiotSavartResult.h:70; MopacResult.h:33; OperationRunner.cpp:54 and :68; ProteinConformation.cpp:21.

Pose calculator hierarchy and execution
Figure 1.4. Pose calculator hierarchy and execution

1.7 Calculations across frames

TrajectoryResult is a separate abstract base for calculations that process successive frames. Unlike ConformationResult, it declares a virtual Compute operation. For each frame, TrajectoryProtein calls Compute on every attached trajectory result. After the last frame, it calls Finalize on those results.

BsWelfordTrajectoryResult updates statistical moments for each atom. BsShieldingTimeSeriesTrajectoryResult instead collects individual samples and packs them into a dense buffer. Both read the ring-current values calculated for the current conformation.

The diagram omits naming, dependency and HDF5-writing operations to show the calls made during frame processing and finalisation.

Source: TrajectoryResult.h:27; TrajectoryProtein.cpp:238 and :250; BsWelfordTrajectoryResult.cpp:55; BsShieldingTimeSeriesTrajectoryResult.cpp:40.

The separate trajectory calculator hierarchy
Figure 1.5. The separate trajectory calculator hierarchy

1.8 What lives for the whole trajectory

Trajectory controls frame processing. TrajectoryProtein owns the protein, the measurements accumulated for each atom, the attached trajectory results and the dense buffers retained after calculation.

The buffer classes inherit from DenseBufferBase, so TrajectoryProtein can own buffers of different numerical types in one collection. DenseBuffer<T> provides access to the values of type T in a particular buffer.

The ring-current time-series result collects samples in its own storage. During finalisation, it packs them into a dense buffer and transfers that buffer to TrajectoryProtein.

Source: TrajectoryProtein.h:27; TrajectoryProtein.cpp:183; DenseBuffer.h:26; BsShieldingTimeSeriesTrajectoryResult::Finalize.

Trajectory ownership and storage
Figure 1.6. Trajectory ownership and storage

1.9 One frame through the system

The initial conformation is retained as a canonical pose. For each subsequent frame, the loop creates a temporary conformation from the new coordinates. OperationRunner runs the pose calculators and attaches their results to that conformation. Trajectory calculators read the pose results and update the measurements they retain across frames. The loop then writes the configured frame output and can release the temporary conformation.

The diagram starts after the initial conformation has been processed; PDB output and environment preparation are omitted. The pose-calculator box groups the concrete Compute functions. The NPY writer calls ConformationResult::WriteAllFeatures to write the common arrays and invoke each attached result’s output function.

Source: Trajectory.cpp:353 through the frame loop and :405; OperationRunner.cpp:68; FrameNpyEmitter.cpp:68; ConformationResult.cpp:50 and its attached-result writer loop.

The main trajectory frame loop
Figure 1.7. The main trajectory frame loop

1.10 Main objects

Object

What it does

Protein Owns atom and residue records and the protein’s topology.
ProteinConformation Stores coordinates and calculated values for one pose and refers to its Protein.
Atom Records an atom’s chemical identity and its place in the protein.
ConformationAtom Holds the position and named per-atom fields used for one pose.
LegacyAmberTopology Supplies bonds, rings and typed chemical descriptions to the calculators.
ConformationResult Declares the functions through which pose results report prerequisites and write output.
OperationRunner Calls the selected pose calculations in an explicit order and attaches their results.
Trajectory Reads and processes the selected frames in sequence.
TrajectoryProtein Owns the protein and the calculation state retained across frames.
TrajectoryAtom Holds accumulated measurements and events for the same atom over time.
TrajectoryResult Supplies the per-frame and finalisation interface for a trajectory calculation.
DenseBuffer<T> Retains typed values in flat storage addressed by atom and sample offset.