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 expectingNuclei
objects in a loop. This is facilitated by ensuring that the fragments can be implicitly converted toNuclei
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
andmake_cap_a_cap_set_object
are opaque functions meant to respectively encapsulate the process of creating aNuclei
andCapSet
object. The state of theNuclei
andCapSet
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 fillingstd::vector
viapush_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 theFragmentedNuclei
object can determine this mapping fromnuclei_to_frag_map
and theCapSet
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
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 aCapSet
object. TheCapSet
object is responsible for managing the caps aFragmentedNuclei
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 toNuclei
objects.