The three UML diagrams below are qualitative diagrams, showing the calling sequence of the important methods. The first shows two different routes from the solver level to OF's KinematicCloud class. The second shows what happens inside the KinematicCloud class up to the point that we arrive at the Cloud class, which will be moving the individual parcels. In the third, we can see what happens for the individual parcels in the KinematicParcel class.
The figure above shows two different routes from the solver to the cloud. In the 'normal' route, cloud.evolve() is called within the solver. In the alternative 'functionObject' route, a FunctionObject will call cloud.evolve(). The swak4foam library provides a FunctionObject which is able to do this for an arbitrary cloud.
'KinematicCloud' in the figure is merely an example and may be replaced by any other cloud.
In the figure above, note that all clouds extend 'KinematicCloud' through inheritance, but KinematicCloud handles the motion. Consequently, for every cloud, the KinematicCloud class is used.
In the figure above, 'move()' is called several times per timestep. Each time a parcel crosses a cell face (or patch), movement stops at the face and continues in a next call to move(). The 'trackToFace()' method takes care of stopping at a face.
'Cloud<ParticleType>' extends 'IDLList<ParticleType>' (not shown), meaning it literally IS a list/collection of parcels. 'Cloud' has methods to serve the ensemble of parcels.
CloudFunctionObjects allow the user to add functionality to the cloud using a 'cloudFunctions' subdict in the 'constant/<CloudName>Properties' file. When writing a custom CloudFunctionObject, you may interpret it as a hook to inject code into the cloud or parcels.
The figure above shows how a CloudFunctionObject is instantiated. It calls the "New" method (note the capital "N": it is not the default "new" operator as seen in C - it is an actual method named "New") of CloudFunctionObjectNew.C. This class is responsible for instantiating the CloudFunctionObject as specified using the 'type' parameter in the 'cloudFunctions' subdict.
This figure may be applied more generally in OpenFOAM. This is called runtime selection.
The FatalError may be exploited using the famous banana trick.
The figure above is a class-dependency diagram, showing how a CloudFunctionObject (here: ParticleTrap, which is merely an example) is added to the runtime selection table and thus made visible to the rest of OpenFOAM. makeBasicKinematicParcelSubmodels.C is an example: one such C-file exists for every cloud in OpenFOAM.
makeParcelCloudFunctionObjects.H holds a list of all CloudFunctionObjects (hard-coded), and thus must be changed if one wishes to add one’s own custom CloudFunctionObject. CloudFunctionObject.H holds macros which manage the runtime selection table in a templated manner. For a custom CloudFunctionObject, these should be called, but not altered.