Collections serve to group objects. They can contain only chemical objects, and they check the objects that are added to enforce this restriction. When a collection is added to another collection, the elements of the first collection are put into the second collection, i.e. collections don't nest.
There are only few methods defined on collections. The method map() applies a function to each object in the collection, and the methods selectBox() and selectShell() pick a subset of the collection by geometric criteria.
However, like chemical objects, collections inherit the methods of the mix-in class GroupOfAtoms, which is also defined in the module Collection. These methods implement operations that need no more information about their object than a list of the atoms it contains.
A specialized collection is described by the class PartitionedCollection. Instances of this class sort their elements into cubic boxes for more efficient geometric selection. The methods selectBox() and selectShell are reimplemented in a much more efficient way.
Universes describe complete systems. They store the list of objects as a collection, and they delegate specific collection methods to the collection object, meaning that universes can be used wherever collections are required.
Most methods are defined in the abstract base class Universe; the subclasses InfiniteUniverse, OrthorhombicPeriodicUniverse, and CubicPeriodicUniverse only add specific initialization behaviour and some geometry inquiry functions.
Universes cache some information that would be costly to regenerate, e.g. arrays for coordinates, masses, velocities, etc., and also force field evaluators. Whenever a universe is changed (e.g. by the addition of some object), the cache is cleared and an internal version number is incremented. The version number is used to check that references to a given universe in other objects (e.g. variable objects) are consistent with the current state.
Energy evaluation is delegated to special energy evaluator objects that are described elsewhere. Since energy evaluation for a subset requires a different evaluator, more than one evaluator can exist for a given universe. All evaluators are cached since their construction is expensive. Therefore extensive use of different subsets in energy evaluation can use up a lot of memory.