Designing the FragmentedNuclei Class

This page describes the design of the FragmentedNuclei class.

Why Do We Need the FragmentedNuclei Class?

The need for the FragmentedNuclei class was motivated by the chemical system hierarchy consideration of Designing the Fragmenting Component. In short, each layer of the ChemicalSystem class will require a corresponding container for holding fragments. This is because each layer of the ChemicalSystem introduces new state.

FragmentedNuclei Considerations

nuclei to fragment map

The FragmentedNuclei must track which nuclei are in which fragments.

caps

Responsibility for satisfying the caps consideration from Designing the Fragmenting Component was given to the FragmentedNuclei class.

  • The same cap may appear multiple times in a set of fragments. The FragmentedNuclei object should store a single set of caps and map each fragment to the caps it needs.

non-disjoint

The non-disjoint fragments consideration from Designing the Fragmenting Component is ultimately the responsibility of the FragmentedNuclei object.

fragments can be used as Nuclei objects

Once a FragmentedNuclei object has been created users will likely want to call routines expecting Nuclei objects in a loop. This is facilitated by ensuring that the fragments can be implicitly converted to Nuclei objects.

FragmentedNuclei API

To construct a FragmentedNuclei:

// It's assumed that users already have a Nuclei object
Nuclei some_nuclei = make_a_nuclei_object();

FragmentedNuclei null; // See FragmentedBase for more details
FragmentedNuclei empty(some_nuclei); // Empty

// Two fragments, first contains nuclei 0, 1, and 2, the second contains
// nuclei 3, 4, and 5
auto nuclei_to_frag_map =  {{0, 1, 2}, {3, 4, 5}};
FragmentedNuclei has_frags(some_nuclei, nuclei_to_frag_map);

// If the user already has caps they're in a CapSet
CapSet caps = make_a_cap_set_object();

// Same as "has_frags", but also has caps
FragmentedNuclei has_frags_and_caps(some_nuclei, nuclei_to_frag_map, caps);

A couple of notes on the above:

  • make_an_nuclei_object and make_cap_a_cap_set_object are opaque functions meant to respectively encapsulate the process of creating a Nuclei and CapSet object. The state of the Nuclei and CapSet objects are largely irrelevant for our present purposes.

  • We think most users will create an empty FragmentedNuclei object and then fill it as part of an algorithm versus having all the state already available at construction. By analogy think of filling std::vector via push_back vs. the initializer-list or range constructor.

  • It is not necessary for the user to tell the FragmentedNuclei object which fragments have which caps. This is because the FragmentedNuclei object can determine this mapping from nuclei_to_frag_map and the CapSet object.

Following from the second note, users will need to be able to add fragments and caps to the FragmentedNuclei object. To that end we propose the following APIs:

// Create a fragment which contains nuclei with offsets 0, 1, and 2
empty.emplace_back({0, 1, 2});

// Can also be added as a range, and the user can use the actual nucleus
// objects (n.b., mapping to indices will involve floating point values so it
// is best to use the ``some_nuclei`` directly)
auto itr = some_nuclei.begin()
empty.emplace_back(itr, itr + 3);

// Adds a Cap
some_nuclei.add_cap(Cap(0, 1, Nucleus{...}));

// Short-hand for...
some_nuclei.cap_set().push_back(Cap(0, 1, Nucleus{...}));

Accessing the state:

// Range-based for loop over fragments
for(NucleiView frag_i : fragments){
    // fragments are interchangeable with Nuclei
    function_expecting_nuclei_object(frag_i);
}

// Offset access
NucleiView frag_0 = fragments[0];

Note that accessing fragments as NucleiView objects means that the user will get an object which is the union of actual nuclei and the nuclei from the caps. This is what is needed to satisfy the fragments can be used as Nuclei objects consideration. As shown above, if the user needs to determine which nuclei in the NucleiView are real vs. from a cap the user can directly access the CapSet.

FragmentedNuclei Design

../../../_images/fragmented_nuclei.png

Fig. 12 The state of the FragmentedNuclei class and its relation to other classes.

Fig. 12 shows the design of the FragmentedNuclei class and how the FragmentedNuclei class relates to other classes. Internally FragmentedNuclei stores each fragment’s members by offset, which saves memory and satisfies nuclei to fragment map. When a user requests a fragment they get back a NucleiView object (the fragments can be used as Nuclei objects consideration). The remaining piece of state in the FragmentedNuclei object is a CapSet object (stems from the caps consideration).

FragmentedNuclei Summary

nuclei to fragment map

Internally the FragmentedNuclei class tracks the nuclei in each fragment via their offset in the supersystem.

caps

Each FragmentedNuclei object will contain a CapSet object. The CapSet object is responsible for managing the caps a FragmentedNuclei object needs.

non-disjoint

The FragmentedNuclei class makes no assumptions about whether or not the fragments are disjoint.

fragments can be used as Nuclei objects

Fragments are returned as NucleiView objects. NucleiView objects are implicitly convertible to Nuclei objects.